Socket
Socket
Sign inDemoInstall

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.8 to 1.0.9

13

CHANGELOG.md
# Changelog
## 1.1.0
## 1.0.8
- Removes more unused
- Fixes bug when size was negative
- Adds a few thousand tests
## 1.0.8
- Removes unused code
- Improves start and end caps
## 1.0.6
- Fixes appearance of start caps

@@ -6,0 +17,0 @@ - Fix appearance of tapered end cap

2

dist/cjs/index.js

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

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

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

// 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
};
function Y(e,t,u,S=g=>g){return e*S(.5-t*(.5-u))}function p(e,t){return[e[0]+t[0],e[1]+t[1]]}function m(e,t){return[e[0]-t[0],e[1]-t[1]]}function f(e,t){return[e[0]*t,e[1]*t]}function fe(e,t){return[e[0]/t,e[1]/t]}function I(e){return[e[1],-e[0]]}function re(e,t){return e[0]*t[0]+e[1]*t[1]}function oe(e,t){return e[0]===t[0]&&e[1]===t[1]}function be(e){return Math.hypot(e[0],e[1])}function ge(e){return e[0]*e[0]+e[1]*e[1]}function Z(e,t){return ge(m(e,t))}function K(e){return fe(e,be(e))}function se(e,t){return Math.hypot(e[1]-t[1],e[0]-t[0])}function ue(e,t){return f(p(e,t),.5)}function V(e,t,u){let S=Math.sin(u),g=Math.cos(u),y=e[0]-t[0],o=e[1]-t[1],x=y*g-o*S,L=y*S+o*g;return[x+t[0],L+t[1]]}function N(e,t,u){return p(e,f(m(t,e),u))}function $(e,t,u){return p(e,f(t,u))}var{min:_,PI:de}=Math,ie=.275,j=de+1e-4;function pe(e,t={}){let{size:u=16,smoothing:S=.5,thinning:g=.5,simulatePressure:y=!0,easing:o=n=>n,start:x={},end:L={},last:q=!1}=t,{cap:k=!0,taper:P=0,easing:C=n=>n*(2-n)}=x,{cap:b=!0,taper:a=0,easing:T=n=>--n*n*n+1}=L;if(e.length===0||u<=0)return[];let U=e[e.length-1].runningLength,B=Math.pow(u*S,2),O=[],v=[],X=e.slice(0,10).reduce((n,i)=>{let r=i.pressure;if(y){let s=_(1,i.distance/u),l=_(1,1-s);r=_(1,n+(l-n)*(s*ie))}return(n+r)/2},e[0].pressure),c=Y(u,g,e[e.length-1].pressure,o),J,A=e[0].vector,z=e[0].point,F=z,E=z,M=F;for(let n=0;n<e.length-1;n++){let{pressure:i}=e[n],{point:r,vector:s,distance:l,runningLength:R}=e[n];if(U-R<3)continue;if(g){if(y){let D=_(1,l/u),W=_(1,1-D);i=_(1,X+(W-X)*(D*ie))}c=Y(u,g,i,o)}else c=u/2;J===void 0&&(J=c);let ae=R<P?C(R/P):1,le=U-R<a?T((U-R)/a):1;c=Math.max(.01,c*Math.min(ae,le));let ee=e[n+1].vector,te=re(s,ee);if(te<0){let D=f(I(A),c);for(let W=1/13,H=0;H<=1;H+=W)E=V(m(r,D),r,j*H),O.push(E),M=V(p(r,D),r,j*-H),v.push(M);z=E,F=M;continue}let ne=f(I(N(ee,s,te)),c);E=m(r,ne),(n===0||Z(z,E)>B)&&(O.push(E),z=E),M=p(r,ne),(n===0||Z(F,M)>B)&&(v.push(M),F=M),X=i,A=s}let d=e[0].point.slice(0,2),h=e.length>1?e[e.length-1].point.slice(0,2):p(e[0].point,[1,1]),Q=O.length<=1||v.length<=1,w=[],G=[];if(Q){if(!(P||a)||q){let n=$(d,K(I(m(d,h))),-(J||c)),i=[];for(let r=1/13,s=r;s<=1;s+=r)i.push(V(n,d,j*2*s));return i}}else{if(P||a&&Q)w.push(d,p(d,[.1,0]));else if(k)for(let r=1/13,s=r;s<=1;s+=r){let l=V(v[0],d,j*s);w.push(l)}else{let r=m(O[0],v[0]),s=f(r,.5),l=f(r,.51);w.push(m(d,s),m(d,l),p(d,l),p(d,s))}let n=ue(O[O.length-1],v[v.length-1]),i=I(K(m(h,n)));if(a||P&&Q)G.push(h,p(h,[1,0]));else if(b){let r=$(h,i,c);for(let s=1/29,l=0;l<=1;l+=s){let R=V(r,h,j*3*l);G.push(R)}}else G.push(p(h,f(i,c)),p(h,f(i,c*.99)),m(h,f(i,c*.99)),m(h,f(i,c)))}return O.concat(G,v.reverse(),w)}function me(e,t={}){var C;let{streamline:u=.5,size:S=16,last:g=!1}=t;if(e.length===0)return[];let y=.15+(1-u)*.85,o=Array.isArray(e[0])?e:e.map(({x:b,y:a,pressure:T=.5})=>[b,a,T]);o.length===1&&(o=[...o,[...p(o[0],[1,1]),...o[0].slice(2)]]);let x=[{point:[o[0][0],o[0][1]],pressure:o[0][2]||.25,vector:[1,1],distance:0,runningLength:0}],L=!1,q=0,k=x[0],P=o.length-1;for(let b=1;b<o.length;b++){let a=g&&b===P?o[b]:N(k.point,o[b],y);if(oe(k.point,a))continue;let T=se(a,k.point);if(q+=T,b<P&&!L){if(q<S)continue;L=!0}k={point:a,pressure:o[b][2]||.5,vector:K(m(k.point,a)),distance:T,runningLength:q},x.push(k)}return x[0].vector=((C=x[1])==null?void 0:C.vector)||[0,0],x}function ce(e,t={}){return pe(me(e,t),t)}var qe=ce;export{qe as default,ce as getStroke,pe as getStrokeOutlinePoints,me as getStrokePoints};
{
"version": "1.0.8",
"version": "1.0.9",
"name": "perfect-freehand",

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

},
"gitHead": "d2eccfdf5fe038dfa3718b2958954451660910fb"
"gitHead": "9529e0e406174f3cfe9e39d2efe4dc8f26e86a02"
}

@@ -115,16 +115,16 @@ # ![Screenshot](perfect-freehand-logo.svg 'Perfect Freehand')

```js
function getSvgPathFromStroke(stroke) {
if (!stroke.length) return ''
function getSvgPathFromStroke(points: number[][]): string {
if (!points.length) return ''
const d = stroke.reduce(
(acc, [x0, y0], i, arr) => {
const [x1, y1] = arr[(i + 1) % arr.length]
acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2)
return acc
},
['M', ...stroke[0], 'Q']
)
d.push('Z')
return d.join(' ')
return points
.reduce(
(acc, point, i, arr) => {
if (i === points.length - 1)
acc.push(point, Vec.med(point, arr[0]), 'L', arr[0], 'Z')
else acc.push(point, Vec.med(point, arr[i + 1]))
return acc
},
['M', points[0], 'Q']
)
.join(' ')
}

@@ -153,2 +153,3 @@ ```

const myPath = new Path2D(pathData)
ctx.fill(myPath)

@@ -189,5 +190,6 @@ ```

export default function Example() {
const [points, setPoints] = React.useState()
const [points, setPoints] = React.useState([])
function handlePointerDown(e) {
e.target.setPointerCapture(e.pointerId)
setPoints([[e.pageX, e.pageY, e.pressure]])

@@ -197,7 +199,15 @@ }

function handlePointerMove(e) {
if (e.buttons === 1) {
setPoints([...points, [e.pageX, e.pageY, e.pressure]])
}
if (e.buttons !== 1) return
setPoints([...points, [e.pageX, e.pageY, e.pressure]])
}
const stroke = getStroke(points, {
size: 16,
thinning: 0.5,
smoothing: 0.5,
streamline: 0.5,
})
const pathData = getSvgPathFromStroke(stroke)
return (

@@ -209,14 +219,3 @@ <svg

>
{points && (
<path
d={getSvgPathFromStroke(
getStroke(points, {
size: 16,
thinning: 0.5,
smoothing: 0.5,
streamline: 0.5,
})
)}
/>
)}
{points && <path d={pathData} />}
</svg>

@@ -231,10 +230,2 @@ )

#### `StrokeOptions`
A TypeScript type for the options object.
```ts
import { StrokeOptions } from 'perfect-freehand'
```
For advanced usage, the library also exports smaller functions that `getStroke` uses to generate its SVG data. While you can use `getStroke`'s data to render strokes with an HTML canvas (via the Path2D element) or with SVG paths, these new functions will allow you to create paths in other rendering technologies.

@@ -244,18 +235,37 @@

A function that accepts an array of points (formatted either as `[x, y, pressure]` or `{ x: number, y: number, pressure: number}`) and a streamline value. Returns a set of adjusted points as `{ point, pressure, vector, distance, runningLength }`. The path's total length will be the `runningLength` of the last point in the array.
```js
import { strokePoints } from 'perfect-freehand'
const strokePoints = getStrokePoints(rawInputPoints)
import { getStrokePoints } from 'perfect-freehand'
import samplePoints from "./samplePoints.json'
const strokePoints = getStrokePoints(samplePoints)
```
Accepts an array of points (formatted either as `[x, y, pressure]` or `{ x: number, y: number, pressure: number}`) and a streamline value. Returns a set of streamlined points as `[x, y, pressure, angle, distance, lengthAtPoint]`. The path's total length will be the length of the last point in the array.
#### `getOutlinePoints`
Accepts an array of points (formatted as `[x, y, pressure, angle, distance, length]`, i.e. the output of `getStrokePoints`) and returns an array of points (`[x, y]`) defining the outline of a pressure-sensitive stroke.
A function that accepts an array of points (formatted as `{ point, pressure, vector, distance, runningLength }`, i.e. the output of `getStrokePoints`) and returns an array of points (`[x, y]`) defining the outline of a pressure-sensitive stroke.
```js
import { getOutlinePoints } from 'perfect-freehand'
import { getStrokePoints, getOutlinePoints } from 'perfect-freehand'
import samplePoints from "./samplePoints.json'
const strokePoints = getStrokePoints(samplePoints)
const outlinePoints = getOutlinePoints(strokePoints)
```
#### `StrokeOptions`
A TypeScript type for the options object. Useful if you're defining your options outside of the `getStroke` function.
```ts
import { StrokeOptions, getStroke } from 'perfect-freehand'
const options: StrokeOptions = {
size: 16,
}
const stroke = getStroke(options)
```
## Support

@@ -262,0 +272,0 @@

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