Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

perfect-freehand

Package Overview
Dependencies
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

perfect-freehand - npm Package Compare versions

Comparing version 1.0.6 to 1.0.7

2

dist/cjs/index.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc