You're Invited: Meet the Socket team at BSidesSF and RSAC - April 27 - May 1.RSVP

perfect-freehand

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

perfect-freehand - npm Package Compare versions

Comparing version

to
1.0.7

@@ -1,1 +0,1 @@

var ft=Object.defineProperty;var dt=t=>ft(t,"__esModule",{value:!0});var xt=(t,e)=>{dt(t);for(var o in e)ft(t,o,{get:e[o],enumerable:!0})};xt(exports,{default:()=>vt,getStroke:()=>st,getStrokeOutlinePoints:()=>rt,getStrokePoints:()=>ot});function Z(t,e,o,M=g=>g){return t*M(.5-e*(.5-o))}function E(t,e){return[t[0]+e[0],t[1]+e[1]]}function x(t,e){return[t[0]-e[0],t[1]-e[1]]}function z(t,e){return[t[0]*e,t[1]*e]}function St(t,e){return[t[0]/e,t[1]/e]}function G(t){return[t[1],-t[0]]}function bt(t,e){return t[0]*e[0]+t[1]*e[1]}function T(t,e){return t[0]===e[0]&&t[1]===e[1]}function kt(t){return Math.hypot(t[0],t[1])}function Pt(t){return t[0]*t[0]+t[1]*t[1]}function nt(t,e){return Pt(x(t,e))}function _(t){return St(t,kt(t))}function I(t,e){return Math.hypot(t[1]-e[1],t[0]-e[0])}function ht(t,e){return z(E(t,e),.5)}function K(t,e,o){let M=Math.sin(o),g=Math.cos(o),R=t[0]-e[0],s=t[1]-e[1],y=R*g-s*M,j=R*M+s*g;return[y+e[0],j+e[1]]}function H(t,e,o){return E(t,z(x(e,t),o))}function h(t,e,o){return E(t,z(e,o))}var{min:V,PI:yt}=Math,gt=.275,N=yt+1e-4;function rt(t,e={}){var mt;let{size:o=16,smoothing:M=.5,thinning:g=.5,simulatePressure:R=!0,easing:s=r=>r,start:y={},end:j={},last:w=!1}=e,{cap:L=!0,taper:v=0,easing:U=r=>r*(2-r)}=y,{cap:d=!0,taper:l=0,easing:q=r=>--r*r*r+1}=j;if(t.length===0)return[];let ut=t[t.length-1].runningLength,it=Math.pow(o*M,2),f=[],S=[],$=t.slice(0,10).reduce((r,P)=>{let a=P.pressure;if(R){let u=V(1,P.distance/o),p=V(1,1-u);a=V(1,r+(p-r)*(u*gt))}return(r+a)/2},t[0].pressure),k=Z(o,g,t[t.length-1].pressure,s),pt,ct=t[0].vector,C=t[0].point,X=C,c=C,m=X,J=!0;for(let r=0;r<t.length-1;r++){let{pressure:P}=t[r],{point:a,vector:u,distance:p,runningLength:n}=t[r];if(r>0&&J&&n<o/2)continue;if(J&&(J=!1),g){if(R){let F=V(1,p/o),et=V(1,1-F);P=V(1,$+(et-$)*(F*gt))}k=Z(o,g,P,s)}else k=o/2;pt===void 0&&(pt=k);let i=n<v?U(n/v):1,O=ut-n<l?q((ut-n)/l):1;k=Math.max(.01,k*Math.min(i,O));let D=((mt=t[r+1])==null?void 0:mt.vector)||u,tt=bt(u,D);if(tt<0){let F=z(G(ct),k);for(let et=1/13,Y=0;Y<=1;Y+=et)m=K(E(a,F),a,N*-Y),c=K(x(a,F),a,N*Y),S.push(m),f.push(c);C=c,X=m;continue}let at=z(G(H(D,u,tt)),k);c=x(a,at),m=E(a,at);let lt=r<2||tt<.25;(lt||nt(C,c)>it)&&(f.push(c),C=c),(lt||nt(X,m)>it)&&(S.push(m),X=m),$=P,ct=u}let b=t[0],B=t[t.length-1],A=J||S.length<2||f.length<2;if(A&&(!(v||l)||w)){let r=0,P=T(b.point,B.point)?E(b.point,[1,1]):B.point;for(let p=0;p<t.length;p++){let{pressure:n,runningLength:i}=t[p];if(i>o){r=Z(o,g,n,s);break}}let a=h(b.point,G(_(x(b.point,P))),-(r||k)),u=[];for(let p=1/13,n=p;n<=1;n+=p)u.push(K(a,b.point,N*2*n));return u}let Q=[],W=[];if(f.length>1&&S.length>1){m=S[1];for(let n=1;n<f.length;n++)if(!T(m,f[n])){c=f[n];break}if(L||v)if(!v&&!(l&&A)){if(!T(m,c)){let n=h(b.point,_(x(c,m)),-I(m,c)/2);for(let i=1/13,O=i;O<=1;O+=i){let D=K(n,b.point,N*O);if(I(D,c)<1)break;Q.push(D)}f.shift(),S.shift()}}else Q.push(b.point.slice(0,2));else if(!T(m,c)){let n=_(x(c,m)),i=I(m,c)/2;Q.push(h(b.point,n,-i),h(b.point,n,-i*.95),h(b.point,n,i*.95),h(b.point,n,i)),f.shift(),S.shift()}let r=f[f.length-1],P=S[S.length-1],a=ht(r,P),u=B.point,p=G(_(x(u,a)));if(d||l)if(!l&&!(v&&A)){let n=h(u,p,k);for(let i=1/29,O=0;O<=1;O+=i){let D=K(n,u,N*3*O);W.push(D)}}else W.push(u.slice(0,2));else{let n=H(a,u,.95),i=k*.95;W.push(h(n,p,i),h(u,p,i),h(u,p,-i),h(n,p,-i))}}return f.concat(W,S.reverse(),Q)}function ot(t,e={}){var U;let{streamline:o=.5,size:M=16,last:g=!1}=e;if(t.length===0)return[];let R=.15+(1-o)*.85,s=Array.isArray(t[0])?t:t.map(({x:d,y:l,pressure:q=.5})=>[d,l,q]);s.length===1&&s.push([...E(s[0],[1,1]),s[0][2]||.5]);let y=[{point:[s[0][0],s[0][1]],pressure:s[0][2]||.25,vector:[1,1],distance:0,runningLength:0}],j=!1,w=0,L=y[0],v=s.length-1;for(let d=1;d<s.length;d++){let l=g&&d===v?s[d]:H(L.point,s[d],R);if(T(L.point,l))continue;let q=I(l,L.point);if(w+=q,d<v&&!j){if(w<M)continue;j=!0}L={point:l,pressure:s[d][2]||.5,vector:_(x(L.point,l)),distance:q,runningLength:w},y.push(L)}return y[0].vector=((U=y[1])==null?void 0:U.vector)||[0,0],y}function st(t,e={}){return rt(ot(t,e),e)}var vt=st;
var pe=Object.defineProperty;var he=e=>pe(e,"__esModule",{value:!0});var xe=(e,t)=>{he(e);for(var o in t)pe(e,o,{get:t[o],enumerable:!0})};xe(exports,{default:()=>ve,getStroke:()=>ne,getStrokeOutlinePoints:()=>ee,getStrokePoints:()=>te});function $(e,t,o,x=b=>b){return e*x(.5-t*(.5-o))}function i(e,t){return[e[0]+t[0],e[1]+t[1]]}function p(e,t){return[e[0]-t[0],e[1]-t[1]]}function l(e,t){return[e[0]*t,e[1]*t]}function Se(e,t){return[e[0]/t,e[1]/t]}function I(e){return[e[1],-e[0]]}function me(e,t){return e[0]*t[0]+e[1]*t[1]}function ce(e,t){return e[0]===t[0]&&e[1]===t[1]}function ke(e){return Math.hypot(e[0],e[1])}function Pe(e){return e[0]*e[0]+e[1]*e[1]}function B(e,t){return Pe(p(e,t))}function K(e){return Se(e,ke(e))}function ae(e,t){return Math.hypot(e[1]-t[1],e[0]-t[0])}function le(e,t){return l(i(e,t),.5)}function L(e,t,o){let x=Math.sin(o),b=Math.cos(o),y=e[0]-t[0],s=e[1]-t[1],d=y*b-s*x,M=y*x+s*b;return[d+t[0],M+t[1]]}function N(e,t,o){return i(e,l(p(t,e),o))}function A(e,t,o){return i(e,l(t,o))}var{min:T,PI:ye}=Math,fe=.275,j=ye+1e-4;function ee(e,t={}){let{size:o=16,smoothing:x=.5,thinning:b=.5,simulatePressure:y=!0,easing:s=n=>n,start:d={},end:M={},last:V=!1}=t,{cap:S=!0,taper:k=0,easing:w=n=>n*(2-n)}=d,{cap:f=!0,taper:c=0,easing:R=n=>--n*n*n+1}=M;if(e.length===0)return[];let U=e[e.length-1].runningLength,re=Math.pow(o*x,2),v=[],P=[],X=e.slice(0,10).reduce((n,u)=>{let r=u.pressure;if(y){let a=T(1,u.distance/o),W=T(1,1-a);r=T(1,n+(W-n)*(a*fe))}return(n+r)/2},e[0].pressure),m=$(o,b,e[e.length-1].pressure,s),J,oe=e[0].vector,_=e[0].point,C=_,O=_,E=C;for(let n=0;n<e.length-1;n++){let{pressure:u}=e[n],{point:r,vector:a,distance:W,runningLength:z}=e[n];if(U-z<3)continue;if(b){if(y){let D=T(1,W/o),Z=T(1,1-D);u=T(1,X+(Z-X)*(D*fe))}m=$(o,b,u,s)}else m=o/2;J===void 0&&(J=m);let de=z<k?w(z/k):1,ge=U-z<c?R((U-z)/c):1;m=Math.max(.01,m*Math.min(de,ge));let se=e[n+1].vector,Y=me(a,se);if(Y<0){let D=l(I(oe),m);for(let Z=1/13,H=0;H<=1;H+=Z)O=L(p(r,D),r,j*H),v.push(O),E=L(i(r,D),r,j*-H),P.push(E);_=O,C=E;continue}let ue=l(I(N(se,a,Y)),m);O=p(r,ue),E=i(r,ue);let ie=n<2||Y<.25;(ie||B(_,O)>re)&&(v.push(O),_=O),(ie||B(C,E)>re)&&(P.push(E),C=E),X=u,oe=a}let g=e[0].point.slice(0,2),h=e.length>1?e[e.length-1].point.slice(0,2):i(e[0].point,[1,1]),Q=v.length<=1||P.length<=1;if(Q&&(!(k||c)||V)){let n=A(g,K(I(p(g,h))),-(J||m)),u=[];for(let r=1/13,a=r;a<=1;a+=r)u.push(L(n,g,j*2*a));return u}let F=[];if(k||c&&Q)F.push(i(g,[.1,0]));else if(S)for(let n=1/13,u=n;u<=1;u+=n){let r=L(P[0],g,j*u);F.push(r)}else{let n=p(v[0],P[0]),u=l(n,.5),r=l(n,.51);F.push(p(g,u),p(g,r),i(g,r),i(g,u))}let G=[],be=le(v[v.length-1],P[P.length-1]),q=I(K(p(h,be)));if(c||k&&Q)G.push(h);else if(f){let n=A(h,q,m);for(let u=1/29,r=0;r<=1;r+=u){let a=L(n,h,j*3*r);G.push(a)}}else G.push(i(h,l(q,m)),i(h,l(q,m*.99)),p(h,l(q,m*.99)),p(h,l(q,m)));return v.concat(G,P.reverse(),F)}function te(e,t={}){var w;let{streamline:o=.5,size:x=16,last:b=!1}=t;if(e.length===0)return[];let y=.15+(1-o)*.85,s=Array.isArray(e[0])?e:e.map(({x:f,y:c,pressure:R=.5})=>[f,c,R]);s.length===1&&s.push([...i(s[0],[1,1]),s[0][2]||.5]);let d=[{point:[s[0][0],s[0][1]],pressure:s[0][2]||.25,vector:[1,1],distance:0,runningLength:0}],M=!1,V=0,S=d[0],k=s.length-1;for(let f=1;f<s.length;f++){let c=b&&f===k?s[f]:N(S.point,s[f],y);if(ce(S.point,c))continue;let R=ae(c,S.point);if(V+=R,f<k&&!M){if(V<x)continue;M=!0}S={point:c,pressure:s[f][2]||.5,vector:K(p(S.point,c)),distance:R,runningLength:V},d.push(S)}return d[0].vector=((w=d[1])==null?void 0:w.vector)||[0,0],d}function ne(e,t={}){return ee(te(e,t),t)}var ve=ne;

@@ -1,1 +0,259 @@

function Z(t,e,o,M=g=>g){return t*M(.5-e*(.5-o))}function E(t,e){return[t[0]+e[0],t[1]+e[1]]}function x(t,e){return[t[0]-e[0],t[1]-e[1]]}function z(t,e){return[t[0]*e,t[1]*e]}function gt(t,e){return[t[0]/e,t[1]/e]}function G(t){return[t[1],-t[0]]}function mt(t,e){return t[0]*e[0]+t[1]*e[1]}function T(t,e){return t[0]===e[0]&&t[1]===e[1]}function dt(t){return Math.hypot(t[0],t[1])}function xt(t){return t[0]*t[0]+t[1]*t[1]}function nt(t,e){return xt(x(t,e))}function _(t){return gt(t,dt(t))}function I(t,e){return Math.hypot(t[1]-e[1],t[0]-e[0])}function at(t,e){return z(E(t,e),.5)}function K(t,e,o){let M=Math.sin(o),g=Math.cos(o),R=t[0]-e[0],s=t[1]-e[1],y=R*g-s*M,j=R*M+s*g;return[y+e[0],j+e[1]]}function H(t,e,o){return E(t,z(x(e,t),o))}function h(t,e,o){return E(t,z(e,o))}var{min:V,PI:St}=Math,lt=.275,N=St+1e-4;function ft(t,e={}){var it;let{size:o=16,smoothing:M=.5,thinning:g=.5,simulatePressure:R=!0,easing:s=r=>r,start:y={},end:j={},last:w=!1}=e,{cap:L=!0,taper:v=0,easing:U=r=>r*(2-r)}=y,{cap:d=!0,taper:l=0,easing:q=r=>--r*r*r+1}=j;if(t.length===0)return[];let rt=t[t.length-1].runningLength,ot=Math.pow(o*M,2),f=[],S=[],$=t.slice(0,10).reduce((r,P)=>{let a=P.pressure;if(R){let u=V(1,P.distance/o),p=V(1,1-u);a=V(1,r+(p-r)*(u*lt))}return(r+a)/2},t[0].pressure),k=Z(o,g,t[t.length-1].pressure,s),st,ut=t[0].vector,C=t[0].point,X=C,c=C,m=X,J=!0;for(let r=0;r<t.length-1;r++){let{pressure:P}=t[r],{point:a,vector:u,distance:p,runningLength:n}=t[r];if(r>0&&J&&n<o/2)continue;if(J&&(J=!1),g){if(R){let F=V(1,p/o),et=V(1,1-F);P=V(1,$+(et-$)*(F*lt))}k=Z(o,g,P,s)}else k=o/2;st===void 0&&(st=k);let i=n<v?U(n/v):1,O=rt-n<l?q((rt-n)/l):1;k=Math.max(.01,k*Math.min(i,O));let D=((it=t[r+1])==null?void 0:it.vector)||u,tt=mt(u,D);if(tt<0){let F=z(G(ut),k);for(let et=1/13,Y=0;Y<=1;Y+=et)m=K(E(a,F),a,N*-Y),c=K(x(a,F),a,N*Y),S.push(m),f.push(c);C=c,X=m;continue}let pt=z(G(H(D,u,tt)),k);c=x(a,pt),m=E(a,pt);let ct=r<2||tt<.25;(ct||nt(C,c)>ot)&&(f.push(c),C=c),(ct||nt(X,m)>ot)&&(S.push(m),X=m),$=P,ut=u}let b=t[0],B=t[t.length-1],A=J||S.length<2||f.length<2;if(A&&(!(v||l)||w)){let r=0,P=T(b.point,B.point)?E(b.point,[1,1]):B.point;for(let p=0;p<t.length;p++){let{pressure:n,runningLength:i}=t[p];if(i>o){r=Z(o,g,n,s);break}}let a=h(b.point,G(_(x(b.point,P))),-(r||k)),u=[];for(let p=1/13,n=p;n<=1;n+=p)u.push(K(a,b.point,N*2*n));return u}let Q=[],W=[];if(f.length>1&&S.length>1){m=S[1];for(let n=1;n<f.length;n++)if(!T(m,f[n])){c=f[n];break}if(L||v)if(!v&&!(l&&A)){if(!T(m,c)){let n=h(b.point,_(x(c,m)),-I(m,c)/2);for(let i=1/13,O=i;O<=1;O+=i){let D=K(n,b.point,N*O);if(I(D,c)<1)break;Q.push(D)}f.shift(),S.shift()}}else Q.push(b.point.slice(0,2));else if(!T(m,c)){let n=_(x(c,m)),i=I(m,c)/2;Q.push(h(b.point,n,-i),h(b.point,n,-i*.95),h(b.point,n,i*.95),h(b.point,n,i)),f.shift(),S.shift()}let r=f[f.length-1],P=S[S.length-1],a=at(r,P),u=B.point,p=G(_(x(u,a)));if(d||l)if(!l&&!(v&&A)){let n=h(u,p,k);for(let i=1/29,O=0;O<=1;O+=i){let D=K(n,u,N*3*O);W.push(D)}}else W.push(u.slice(0,2));else{let n=H(a,u,.95),i=k*.95;W.push(h(n,p,i),h(u,p,i),h(u,p,-i),h(n,p,-i))}}return f.concat(W,S.reverse(),Q)}function bt(t,e={}){var U;let{streamline:o=.5,size:M=16,last:g=!1}=e;if(t.length===0)return[];let R=.15+(1-o)*.85,s=Array.isArray(t[0])?t:t.map(({x:d,y:l,pressure:q=.5})=>[d,l,q]);s.length===1&&s.push([...E(s[0],[1,1]),s[0][2]||.5]);let y=[{point:[s[0][0],s[0][1]],pressure:s[0][2]||.25,vector:[1,1],distance:0,runningLength:0}],j=!1,w=0,L=y[0],v=s.length-1;for(let d=1;d<s.length;d++){let l=g&&d===v?s[d]:H(L.point,s[d],R);if(T(L.point,l))continue;let q=I(l,L.point);if(w+=q,d<v&&!j){if(w<M)continue;j=!0}L={point:l,pressure:s[d][2]||.5,vector:_(x(L.point,l)),distance:q,runningLength:w},y.push(L)}return y[0].vector=((U=y[1])==null?void 0:U.vector)||[0,0],y}function ht(t,e={}){return ft(bt(t,e),e)}var jt=ht;export{jt as default,ht as getStroke,ft as getStrokeOutlinePoints,bt as getStrokePoints};
// src/getStrokeRadius.ts
function getStrokeRadius(size, thinning, pressure, easing = (t) => t) {
return size * easing(0.5 - thinning * (0.5 - pressure));
}
// src/vec.ts
function add(A, B) {
return [A[0] + B[0], A[1] + B[1]];
}
function sub(A, B) {
return [A[0] - B[0], A[1] - B[1]];
}
function mul(A, n) {
return [A[0] * n, A[1] * n];
}
function div(A, n) {
return [A[0] / n, A[1] / n];
}
function per(A) {
return [A[1], -A[0]];
}
function dpr(A, B) {
return A[0] * B[0] + A[1] * B[1];
}
function isEqual(A, B) {
return A[0] === B[0] && A[1] === B[1];
}
function len(A) {
return Math.hypot(A[0], A[1]);
}
function len2(A) {
return A[0] * A[0] + A[1] * A[1];
}
function dist2(A, B) {
return len2(sub(A, B));
}
function uni(A) {
return div(A, len(A));
}
function dist(A, B) {
return Math.hypot(A[1] - B[1], A[0] - B[0]);
}
function med(A, B) {
return mul(add(A, B), 0.5);
}
function rotAround(A, C, r) {
const s = Math.sin(r);
const c = Math.cos(r);
const px = A[0] - C[0];
const py = A[1] - C[1];
const nx = px * c - py * s;
const ny = px * s + py * c;
return [nx + C[0], ny + C[1]];
}
function lrp(A, B, t) {
return add(A, mul(sub(B, A), t));
}
function prj(A, B, c) {
return add(A, mul(B, c));
}
// src/getStrokeOutlinePoints.ts
var { min, PI } = Math;
var RATE_OF_PRESSURE_CHANGE = 0.275;
var FIXED_PI = PI + 1e-4;
function getStrokeOutlinePoints(points, options = {}) {
const {
size = 16,
smoothing = 0.5,
thinning = 0.5,
simulatePressure = true,
easing = (t) => t,
start = {},
end = {},
last: isComplete = false
} = options;
const {
cap: capStart = true,
taper: taperStart = 0,
easing: taperStartEase = (t) => t * (2 - t)
} = start;
const {
cap: capEnd = true,
taper: taperEnd = 0,
easing: taperEndEase = (t) => --t * t * t + 1
} = end;
if (points.length === 0)
return [];
const totalLength = points[points.length - 1].runningLength;
const minDistance = Math.pow(size * smoothing, 2);
const leftPts = [];
const rightPts = [];
let prevPressure = points.slice(0, 10).reduce((acc, curr) => {
let pressure = curr.pressure;
if (simulatePressure) {
const sp = min(1, curr.distance / size);
const rp = min(1, 1 - sp);
pressure = min(1, acc + (rp - acc) * (sp * RATE_OF_PRESSURE_CHANGE));
}
return (acc + pressure) / 2;
}, points[0].pressure);
let radius = getStrokeRadius(size, thinning, points[points.length - 1].pressure, easing);
let firstRadius = void 0;
let prevVector = points[0].vector;
let pl = points[0].point;
let pr = pl;
let tl = pl;
let tr = pr;
for (let i = 0; i < points.length - 1; i++) {
let { pressure } = points[i];
const { point, vector, distance, runningLength } = points[i];
if (totalLength - runningLength < 3)
continue;
if (thinning) {
if (simulatePressure) {
const sp = min(1, distance / size);
const rp = min(1, 1 - sp);
pressure = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE));
}
radius = getStrokeRadius(size, thinning, pressure, easing);
} else {
radius = size / 2;
}
if (firstRadius === void 0) {
firstRadius = radius;
}
const ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1;
const te = totalLength - runningLength < taperEnd ? taperEndEase((totalLength - runningLength) / taperEnd) : 1;
radius = Math.max(0.01, radius * Math.min(ts, te));
const nextVector = points[i + 1].vector;
const nextDpr = dpr(vector, nextVector);
if (nextDpr < 0) {
const offset2 = mul(per(prevVector), radius);
for (let step = 1 / 13, t = 0; t <= 1; t += step) {
tl = rotAround(sub(point, offset2), point, FIXED_PI * t);
leftPts.push(tl);
tr = rotAround(add(point, offset2), point, FIXED_PI * -t);
rightPts.push(tr);
}
pl = tl;
pr = tr;
continue;
}
const offset = mul(per(lrp(nextVector, vector, nextDpr)), radius);
tl = sub(point, offset);
tr = add(point, offset);
const alwaysAdd = i < 2 || nextDpr < 0.25;
if (alwaysAdd || dist2(pl, tl) > minDistance) {
leftPts.push(tl);
pl = tl;
}
if (alwaysAdd || dist2(pr, tr) > minDistance) {
rightPts.push(tr);
pr = tr;
}
prevPressure = pressure;
prevVector = vector;
}
const firstPoint = points[0].point.slice(0, 2);
const lastPoint = points.length > 1 ? points[points.length - 1].point.slice(0, 2) : add(points[0].point, [1, 1]);
const isVeryShort = leftPts.length <= 1 || rightPts.length <= 1;
if (isVeryShort && (!(taperStart || taperEnd) || isComplete)) {
const start2 = prj(firstPoint, uni(per(sub(firstPoint, lastPoint))), -(firstRadius || radius));
const dotPts = [];
for (let step = 1 / 13, t = step; t <= 1; t += step) {
dotPts.push(rotAround(start2, firstPoint, FIXED_PI * 2 * t));
}
return dotPts;
}
const startCap = [];
if (taperStart || taperEnd && isVeryShort) {
startCap.push(add(firstPoint, [0.1, 0]));
} else if (capStart) {
for (let step = 1 / 13, t = step; t <= 1; t += step) {
const pt = rotAround(rightPts[0], firstPoint, FIXED_PI * t);
startCap.push(pt);
}
} else {
const cornersVector = sub(leftPts[0], rightPts[0]);
const offsetA = mul(cornersVector, 0.5);
const offsetB = mul(cornersVector, 0.51);
startCap.push(sub(firstPoint, offsetA), sub(firstPoint, offsetB), add(firstPoint, offsetB), add(firstPoint, offsetA));
}
const endCap = [];
const mid = med(leftPts[leftPts.length - 1], rightPts[rightPts.length - 1]);
const direction = per(uni(sub(lastPoint, mid)));
if (taperEnd || taperStart && isVeryShort) {
endCap.push(lastPoint);
} else if (capEnd) {
const start2 = prj(lastPoint, direction, radius);
for (let step = 1 / 29, t = 0; t <= 1; t += step) {
const pt = rotAround(start2, lastPoint, FIXED_PI * 3 * t);
endCap.push(pt);
}
} else {
endCap.push(add(lastPoint, mul(direction, radius)), add(lastPoint, mul(direction, radius * 0.99)), sub(lastPoint, mul(direction, radius * 0.99)), sub(lastPoint, mul(direction, radius)));
}
return leftPts.concat(endCap, rightPts.reverse(), startCap);
}
// src/getStrokePoints.ts
function getStrokePoints(points, options = {}) {
const { streamline = 0.5, size = 16, last: isComplete = false } = options;
if (points.length === 0)
return [];
const t = 0.15 + (1 - streamline) * 0.85;
const pts = Array.isArray(points[0]) ? points : points.map(({ x, y, pressure = 0.5 }) => [x, y, pressure]);
if (pts.length === 1)
pts.push([...add(pts[0], [1, 1]), pts[0][2] || 0.5]);
const strokePoints = [
{
point: [pts[0][0], pts[0][1]],
pressure: pts[0][2] || 0.25,
vector: [1, 1],
distance: 0,
runningLength: 0
}
];
let hasReachedMinimumLength = false;
let runningLength = 0;
let prev = strokePoints[0];
const max = pts.length - 1;
for (let i = 1; i < pts.length; i++) {
const point = isComplete && i === max ? pts[i] : lrp(prev.point, pts[i], t);
if (isEqual(prev.point, point))
continue;
const distance = dist(point, prev.point);
runningLength += distance;
if (i < max && !hasReachedMinimumLength) {
if (runningLength < size)
continue;
hasReachedMinimumLength = true;
}
prev = {
point,
pressure: pts[i][2] || 0.5,
vector: uni(sub(prev.point, point)),
distance,
runningLength
};
strokePoints.push(prev);
}
strokePoints[0].vector = strokePoints[1]?.vector || [0, 0];
return strokePoints;
}
// src/getStroke.ts
function getStroke(points, options = {}) {
return getStrokeOutlinePoints(getStrokePoints(points, options), options);
}
// src/index.ts
var src_default = getStroke;
export {
src_default as default,
getStroke,
getStrokeOutlinePoints,
getStrokePoints
};
{
"version": "1.0.6",
"version": "1.0.7",
"name": "perfect-freehand",

@@ -60,3 +60,3 @@ "private": false,

},
"gitHead": "6df6712f75139129bd9916220814d707354fbabc"
"gitHead": "0b1fd1bfc560cb15e34724b0b9b56d6a2b750f00"
}

@@ -7,2 +7,3 @@ import { getStrokeRadius } from './getStrokeRadius'

dist2,
div,
dpr,

@@ -122,3 +123,3 @@ isEqual,

let short = true
// let short = true

@@ -136,7 +137,4 @@ /*

if (i > 0 && short && runningLength < size / 2) {
continue
} else if (short) {
short = false
}
// Removes noise from the end of the line
if (totalLength - runningLength < 3) continue

@@ -193,4 +191,6 @@ /*

const nextVector = points[i + 1]?.vector || vector
/* Add points to left and right */
const nextVector = points[i + 1].vector
const nextDpr = dpr(vector, nextVector)

@@ -207,11 +207,14 @@

if (nextDpr < 0) {
// It's a sharp corner. Draw a rounded cap.
// It's a sharp corner. Draw a rounded cap and move on to the next point
// Considering saving these and drawing them later? So that we can avoid
// crossing future points.
const offset = mul(per(prevVector), radius)
for (let step = 1 / 13, t = 0; t <= 1; t += step) {
tr = rotAround(add(point, offset), point, FIXED_PI * -t)
tl = rotAround(sub(point, offset), point, FIXED_PI * t)
leftPts.push(tl)
tr = rotAround(add(point, offset), point, FIXED_PI * -t)
rightPts.push(tr)
leftPts.push(tl)
}

@@ -222,3 +225,2 @@

// Once we've drawn the cap, don't do any more work for this point.
continue

@@ -255,3 +257,2 @@ }

// Set variables for next iteration
prevPressure = pressure

@@ -269,6 +270,11 @@ prevVector = vector

const firstPoint = points[0]
const lastPoint = points[points.length - 1]
const isVeryShort = short || rightPts.length < 2 || leftPts.length < 2
const firstPoint = points[0].point.slice(0, 2)
const lastPoint =
points.length > 1
? points[points.length - 1].point.slice(0, 2)
: add(points[0].point, [1, 1])
const isVeryShort = leftPts.length <= 1 || rightPts.length <= 1
/*

@@ -284,20 +290,6 @@ Draw a dot for very short or completed strokes

if (isVeryShort && (!(taperStart || taperEnd) || isComplete)) {
let ir = 0
const lastPt = isEqual(firstPoint.point, lastPoint.point)
? add(firstPoint.point, [1, 1])
: lastPoint.point
for (let i = 0; i < points.length; i++) {
const { pressure, runningLength } = points[i]
if (runningLength > size) {
ir = getStrokeRadius(size, thinning, pressure, easing)
break
}
}
const start = prj(
firstPoint.point,
per(uni(sub(firstPoint.point, lastPt))),
-(ir || radius)
firstPoint,
uni(per(sub(firstPoint, lastPoint))),
-(firstRadius || radius)
)

@@ -308,3 +300,3 @@

for (let step = 1 / 13, t = step; t <= 1; t += step) {
dotPts.push(rotAround(start, firstPoint.point, FIXED_PI * 2 * t))
dotPts.push(rotAround(start, firstPoint, FIXED_PI * 2 * t))
}

@@ -325,52 +317,27 @@

const startCap: number[][] = []
const endCap: number[][] = []
if (leftPts.length > 1 && rightPts.length > 1) {
tr = rightPts[1]
for (let i = 1; i < leftPts.length; i++) {
if (!isEqual(tr, leftPts[i])) {
tl = leftPts[i]
break
}
if (taperStart || (taperEnd && isVeryShort)) {
// The start point is tapered, noop
startCap.push(add(firstPoint, [0.1, 0]))
} else if (capStart) {
// Draw the round cap - add thirteen points rotating the right point around the start point to the left point
for (let step = 1 / 13, t = step; t <= 1; t += step) {
const pt = rotAround(rightPts[0], firstPoint, FIXED_PI * t)
startCap.push(pt)
}
} else {
// Draw the flat cap - add a point to the left and right of the start point
const cornersVector = sub(leftPts[0], rightPts[0])
const offsetA = mul(cornersVector, 0.5)
const offsetB = mul(cornersVector, 0.51)
if (capStart || taperStart) {
if (!taperStart && !(taperEnd && isVeryShort)) {
if (!isEqual(tr, tl)) {
const start = prj(
firstPoint.point,
uni(sub(tl, tr)),
-dist(tr, tl) / 2
)
for (let step = 1 / 13, t = step; t <= 1; t += step) {
const pt = rotAround(start, firstPoint.point, FIXED_PI * t)
if (dist(pt, tl) < 1) break
startCap.push(pt)
}
leftPts.shift()
rightPts.shift()
}
} else {
startCap.push(firstPoint.point.slice(0, 2))
}
} else {
// Flat cap
if (!isEqual(tr, tl)) {
const vector = uni(sub(tl, tr))
const ptDist = dist(tr, tl) / 2
startCap.push(
sub(firstPoint, offsetA),
sub(firstPoint, offsetB),
add(firstPoint, offsetB),
add(firstPoint, offsetA)
)
}
startCap.push(
prj(firstPoint.point, vector, -ptDist),
prj(firstPoint.point, vector, -ptDist * 0.95),
prj(firstPoint.point, vector, ptDist * 0.95),
prj(firstPoint.point, vector, ptDist)
)
leftPts.shift()
rightPts.shift()
}
}
/*
/*
Draw an end cap

@@ -385,39 +352,28 @@

// The last left point
const ll = leftPts[leftPts.length - 1]
const endCap: number[][] = []
// The last right point
const lr = rightPts[rightPts.length - 1]
// The mid point between the last left and right points
const mid = med(leftPts[leftPts.length - 1], rightPts[rightPts.length - 1])
// The point between the two
const mid = med(ll, lr)
// The direction vector from the mid point to the last point
const direction = per(uni(sub(lastPoint, mid)))
// The last provided point
const last = lastPoint.point
const direction = per(uni(sub(last, mid)))
if (capEnd || taperEnd) {
if (!taperEnd && !(taperStart && isVeryShort)) {
// Draw the end cap
const start = prj(last, direction, radius)
for (let step = 1 / 29, t = 0; t <= 1; t += step) {
const pt = rotAround(start, last, FIXED_PI * 3 * t)
endCap.push(pt)
}
} else {
// Just push the last point to the line
endCap.push(last.slice(0, 2))
}
} else {
// Add a few more points almost at the last point
const justBefore = lrp(mid, last, 0.95)
const r = radius * 0.95
endCap.push(
prj(justBefore, direction, r),
prj(last, direction, r),
prj(last, direction, -r),
prj(justBefore, direction, -r)
)
if (taperEnd || (taperStart && isVeryShort)) {
// Tapered end - push the last point to the line
endCap.push(lastPoint)
} else if (capEnd) {
// Draw the round end cap
const start = prj(lastPoint, direction, radius)
for (let step = 1 / 29, t = 0; t <= 1; t += step) {
const pt = rotAround(start, lastPoint, FIXED_PI * 3 * t)
endCap.push(pt)
}
} else {
// Draw the flat end cap
endCap.push(
add(lastPoint, mul(direction, radius)),
add(lastPoint, mul(direction, radius * 0.99)),
sub(lastPoint, mul(direction, radius * 0.99)),
sub(lastPoint, mul(direction, radius))
)
}

@@ -424,0 +380,0 @@

@@ -79,4 +79,4 @@ import { add, dist, isEqual, lrp, sub, uni } from './vec'

hasReachedMinimumLength = true
// TODO: Backfill the missing points so that tapering works correctly.
}
// Create a new strokepoint (it will be the new "previous" one).

@@ -83,0 +83,0 @@ prev = {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet