perfect-freehand
Advanced tools
Comparing version 0.4.71 to 0.4.91
@@ -0,1 +1,10 @@ | ||
## 0.4.9 | ||
- Prevents duplicates when parsing points. | ||
## 0.4.8 | ||
- Fixes bug on start caps. | ||
- Adds simple test. | ||
## 0.4.6 | ||
@@ -2,0 +11,0 @@ |
@@ -13,3 +13,3 @@ import { StrokeOptions, StrokePoint } from './types'; | ||
pressure?: number; | ||
}>(points: (T | K)[], options: StrokeOptions): StrokePoint[]; | ||
}>(points: (T | K)[], options?: StrokeOptions): StrokePoint[]; | ||
/** | ||
@@ -16,0 +16,0 @@ * ## getStrokeOutlinePoints |
@@ -5,53 +5,3 @@ 'use strict'; | ||
function lerp(y1, y2, mu) { | ||
return y1 * (1 - mu) + y2 * mu; | ||
} | ||
function clamp(n, a, b) { | ||
return Math.max(a, Math.min(b, n)); | ||
} | ||
/** | ||
* Convert an array of points to the correct format ([x, y, radius]) | ||
* @param points | ||
* @returns | ||
*/ | ||
function toPointsArray(points) { | ||
if (Array.isArray(points[0])) { | ||
return points.map(function (_ref) { | ||
var x = _ref[0], | ||
y = _ref[1], | ||
_ref$ = _ref[2], | ||
pressure = _ref$ === void 0 ? 0.5 : _ref$; | ||
return [x, y, pressure]; | ||
}); | ||
} else { | ||
return points.map(function (_ref2) { | ||
var x = _ref2.x, | ||
y = _ref2.y, | ||
_ref2$pressure = _ref2.pressure, | ||
pressure = _ref2$pressure === void 0 ? 0.5 : _ref2$pressure; | ||
return [x, y, pressure]; | ||
}); | ||
} | ||
} | ||
/** | ||
* Compute a radius based on the pressure. | ||
* @param size | ||
* @param thinning | ||
* @param easing | ||
* @param pressure | ||
* @returns | ||
*/ | ||
function getStrokeRadius(size, thinning, easing, pressure) { | ||
if (pressure === void 0) { | ||
pressure = 0.5; | ||
} | ||
if (!thinning) return size / 2; | ||
pressure = clamp(easing(pressure), 0, 1); | ||
return (thinning < 0 ? lerp(size, size + size * clamp(thinning, -0.95, -0.05), pressure) : lerp(size - size * clamp(thinning, 0.05, 0.95), size, pressure)) / 2; | ||
} | ||
/** | ||
* Negate a vector. | ||
@@ -191,3 +141,56 @@ * @param A | ||
} // isLeft: >0 for counterclockwise | ||
function isEqual(a, b) { | ||
return a[0] === b[0] && a[1] === b[1]; | ||
} | ||
function lerp(y1, y2, mu) { | ||
return y1 * (1 - mu) + y2 * mu; | ||
} | ||
function clamp(n, a, b) { | ||
return Math.max(a, Math.min(b, n)); | ||
} | ||
/** | ||
* Convert an array of points to the correct format ([x, y, radius]) | ||
* @param points | ||
* @returns | ||
*/ | ||
function toPointsArray(points) { | ||
if (Array.isArray(points[0])) { | ||
return points.map(function (_ref) { | ||
var x = _ref[0], | ||
y = _ref[1], | ||
_ref$ = _ref[2], | ||
pressure = _ref$ === void 0 ? 0.5 : _ref$; | ||
return [x, y, pressure]; | ||
}); | ||
} else { | ||
return points.map(function (_ref2) { | ||
var x = _ref2.x, | ||
y = _ref2.y, | ||
_ref2$pressure = _ref2.pressure, | ||
pressure = _ref2$pressure === void 0 ? 0.5 : _ref2$pressure; | ||
return [x, y, pressure]; | ||
}); | ||
} | ||
} | ||
/** | ||
* Compute a radius based on the pressure. | ||
* @param size | ||
* @param thinning | ||
* @param easing | ||
* @param pressure | ||
* @returns | ||
*/ | ||
function getStrokeRadius(size, thinning, easing, pressure) { | ||
if (pressure === void 0) { | ||
pressure = 0.5; | ||
} | ||
if (!thinning) return size / 2; | ||
pressure = clamp(easing(pressure), 0, 1); | ||
return (thinning < 0 ? lerp(size, size + size * clamp(thinning, -0.95, -0.05), pressure) : lerp(size - size * clamp(thinning, 0.05, 0.95), size, pressure)) / 2; | ||
} | ||
var min = Math.min, | ||
@@ -204,7 +207,12 @@ PI = Math.PI; | ||
function getStrokePoints(points, options) { | ||
var _options$simulatePres = options.simulatePressure, | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
var _options = options, | ||
_options$simulatePres = _options.simulatePressure, | ||
simulatePressure = _options$simulatePres === void 0 ? true : _options$simulatePres, | ||
_options$streamline = options.streamline, | ||
_options$streamline = _options.streamline, | ||
streamline = _options$streamline === void 0 ? 0.5 : _options$streamline, | ||
_options$size = options.size, | ||
_options$size = _options.size, | ||
size = _options$size === void 0 ? 8 : _options$size; | ||
@@ -229,8 +237,9 @@ streamline /= 2; | ||
for (var i = 1, curr = pts[i], prev = strokePoints[0]; i < pts.length; i++, curr = pts[i], prev = strokePoints[i - 1]) { | ||
var point = lrp(prev.point, curr, 1 - streamline), | ||
pressure = curr[2], | ||
vector = uni(vec(point, prev.point)), | ||
distance = dist(point, prev.point), | ||
runningLength = prev.runningLength + distance; | ||
for (var i = 1, j = 0, curr = pts[i], prev = strokePoints[j]; i < len; i++, curr = pts[i], prev = strokePoints[j]) { | ||
var point = lrp(prev.point, curr, 1 - streamline); | ||
if (isEqual(prev.point, point)) continue; | ||
var pressure = curr[2]; | ||
var vector = uni(vec(point, prev.point)); | ||
var distance = dist(point, prev.point); | ||
var runningLength = prev.runningLength + distance; | ||
strokePoints.push({ | ||
@@ -243,2 +252,3 @@ point: point, | ||
}); | ||
j += 1; // only increment j if we add an item to strokePoints | ||
} | ||
@@ -253,4 +263,6 @@ /* | ||
*/ | ||
// Update the length to the length of the strokePoints array. | ||
len = strokePoints.length; | ||
var totalLength = strokePoints[len - 1].runningLength; | ||
@@ -265,4 +277,4 @@ | ||
if (totalLength - _runningLength > size / 2 || dpr$1 < 0.8) { | ||
for (var j = _i; j < len; j++) { | ||
strokePoints[j].vector = _vector; | ||
for (var _j = _i; _j < len; _j++) { | ||
strokePoints[_j].vector = _vector; | ||
} | ||
@@ -296,24 +308,24 @@ | ||
var _options = options, | ||
_options$size2 = _options.size, | ||
size = _options$size2 === void 0 ? 8 : _options$size2, | ||
_options$thinning = _options.thinning, | ||
thinning = _options$thinning === void 0 ? 0.5 : _options$thinning, | ||
_options$smoothing = _options.smoothing, | ||
smoothing = _options$smoothing === void 0 ? 0.5 : _options$smoothing, | ||
_options$simulatePres2 = _options.simulatePressure, | ||
simulatePressure = _options$simulatePres2 === void 0 ? true : _options$simulatePres2, | ||
_options$easing = _options.easing, | ||
easing = _options$easing === void 0 ? function (t) { | ||
var _options2 = options, | ||
_options2$size = _options2.size, | ||
size = _options2$size === void 0 ? 8 : _options2$size, | ||
_options2$thinning = _options2.thinning, | ||
thinning = _options2$thinning === void 0 ? 0.5 : _options2$thinning, | ||
_options2$smoothing = _options2.smoothing, | ||
smoothing = _options2$smoothing === void 0 ? 0.5 : _options2$smoothing, | ||
_options2$simulatePre = _options2.simulatePressure, | ||
simulatePressure = _options2$simulatePre === void 0 ? true : _options2$simulatePre, | ||
_options2$easing = _options2.easing, | ||
easing = _options2$easing === void 0 ? function (t) { | ||
return t; | ||
} : _options$easing, | ||
_options$start = _options.start, | ||
start = _options$start === void 0 ? {} : _options$start, | ||
_options$end = _options.end, | ||
end = _options$end === void 0 ? {} : _options$end, | ||
_options$last = _options.last, | ||
isComplete = _options$last === void 0 ? false : _options$last; | ||
var _options2 = options, | ||
_options2$streamline = _options2.streamline, | ||
streamline = _options2$streamline === void 0 ? 0.5 : _options2$streamline; | ||
} : _options2$easing, | ||
_options2$start = _options2.start, | ||
start = _options2$start === void 0 ? {} : _options2$start, | ||
_options2$end = _options2.end, | ||
end = _options2$end === void 0 ? {} : _options2$end, | ||
_options2$last = _options2.last, | ||
isComplete = _options2$last === void 0 ? false : _options2$last; | ||
var _options3 = options, | ||
_options3$streamline = _options3.streamline, | ||
streamline = _options3$streamline === void 0 ? 0.5 : _options3$streamline; | ||
streamline /= 2; | ||
@@ -509,12 +521,20 @@ var _start$taper = start.taper, | ||
tr = rightPts[1]; | ||
tl = leftPts[1]; | ||
var _start2 = sub(firstPoint.point, mul(uni(vec(tr, tl)), dist(tr, tl) / 2)); | ||
for (var _i3 = 1; _i3 < leftPts.length; _i3++) { | ||
if (!isEqual(tr, leftPts[_i3])) { | ||
tl = leftPts[_i3]; | ||
break; | ||
} | ||
} | ||
for (var _t2 = 0, _step = 0.2; _t2 <= 1; _t2 += _step) { | ||
startCap.push(rotAround(_start2, firstPoint.point, PI * _t2)); | ||
if (!isEqual(tr, tl)) { | ||
var _start2 = sub(firstPoint.point, mul(uni(vec(tr, tl)), dist(tr, tl) / 2)); | ||
for (var _t2 = 0, _step = 0.2; _t2 <= 1; _t2 += _step) { | ||
startCap.push(rotAround(_start2, firstPoint.point, PI * _t2)); | ||
} | ||
leftPts.shift(); | ||
rightPts.shift(); | ||
} | ||
leftPts.shift(); | ||
rightPts.shift(); | ||
} | ||
@@ -521,0 +541,0 @@ /* |
@@ -1,2 +0,2 @@ | ||
"use strict";function n(n,r,t){return n*(1-t)+r*t}function r(n,r,t){return Math.max(r,Math.min(t,n))}function t(t,e,i,o){return void 0===o&&(o=.5),e?(o=r(i(o),0,1),(e<0?n(t,t+t*r(e,-.95,-.05),o):n(t-t*r(e,.05,.95),t,o))/2):t/2}function e(n,r){return[n[0]+r[0],n[1]+r[1]]}function i(n,r){return[n[0]-r[0],n[1]-r[1]]}function o(n,r){return[r[0]-n[0],r[1]-n[1]]}function u(n,r){return[n[0]*r,n[1]*r]}function s(n){return[n[1],-n[0]]}function a(n,r){return n[0]*r[0]+n[1]*r[1]}function v(n,r){return function(n){return n[0]*n[0]+n[1]*n[1]}(i(n,r))}function f(n){return function(n,r){return[n[0]/r,n[1]/r]}(n,function(n){return Math.hypot(n[0],n[1])}(n))}function c(n,r){return Math.hypot(n[1]-r[1],n[0]-r[0])}function p(n,r,t){var e=Math.sin(t),i=Math.cos(t),o=n[0]-r[0],u=n[1]-r[1];return[o*i-u*e+r[0],o*e+u*i+r[1]]}function h(n,r,t){return e(n,u(o(n,r),t))}Object.defineProperty(exports,"__esModule",{value:!0});var d=Math.min,g=Math.PI;function l(n,r){var t=r.simulatePressure,i=r.streamline,u=void 0===i?.5:i,s=r.size,v=void 0===s?8:s;u/=2,void 0===t||t||(u/=2);var p=function(n){return Array.isArray(n[0])?n.map((function(n){var r=n[2];return[n[0],n[1],void 0===r?.5:r]})):n.map((function(n){var r=n.pressure;return[n.x,n.y,void 0===r?.5:r]}))}(n),d=p.length;if(0===d)return[];1===d&&p.push(e(p[0],[1,0]));for(var g=[{point:[p[0][0],p[0][1]],pressure:p[0][2],vector:[0,0],distance:0,runningLength:0}],l=1,m=p[l],M=g[0];l<p.length;m=p[++l],M=g[l-1]){var L=h(M.point,m,1-u),x=m[2],y=f(o(L,M.point)),P=c(L,M.point);g.push({point:L,pressure:x,vector:y,distance:P,runningLength:M.runningLength+P})}for(var k=g[d-1].runningLength,b=d-2;b>1;b--){var z=g[b],A=z.runningLength,O=z.vector,S=a(g[b-1].vector,g[b].vector);if(k-A>v/2||S<.8){for(var _=b;_<d;_++)g[_].vector=O;break}}return g}function m(n,r){void 0===r&&(r={});var l=r.size,m=void 0===l?8:l,M=r.thinning,L=void 0===M?.5:M,x=r.smoothing,y=void 0===x?.5:x,P=r.simulatePressure,k=void 0===P||P,b=r.easing,z=void 0===b?function(n){return n}:b,A=r.start,O=void 0===A?{}:A,S=r.end,_=void 0===S?{}:S,j=r.last,w=void 0!==j&&j,I=r.streamline,q=void 0===I?.5:I;q/=2;var B=O.taper,C=void 0===B?0:B,D=O.easing,E=void 0===D?function(n){return n*(2-n)}:D,F=_.taper,G=void 0===F?0:F,H=_.easing,J=void 0===H?function(n){return--n*n*n+1}:H,K=n.length;if(0===K)return[];for(var N=n[K-1].runningLength,Q=[],R=[],T=n.slice(0,5).reduce((function(n,r){return(n+r.pressure)/2}),n[0].pressure),U=t(m,L,z,n[K-1].pressure),V=n[0].vector,W=n[0].point,X=W,Y=W,Z=X,$=1;$<K-1;$++){var nn=n[$],rn=nn.point,tn=nn.pressure,en=nn.vector,on=nn.distance,un=nn.runningLength;if(L){if(k){var sn=d(1,1-on/m),an=d(1,on/m);tn=d(1,T+an/2*(sn-T))}U=t(m,L,z,tn)}else U=m/2;var vn=un<C?E(un/C):1,fn=N-un<G?J((N-un)/G):1;U*=Math.min(vn,fn);var cn=n[$+1].vector,pn=a(en,cn);if(pn<0){for(var hn=u(s(V),U),dn=0;dn<1;dn+=.2)Z=p(e(rn,hn),rn,g*-dn),Y=p(i(rn,hn),rn,g*dn),R.push(Z),Q.push(Y);W=Y,X=Z}else{var gn=u(s(h(cn,en,pn)),U);Y=i(rn,gn),Z=e(rn,gn);var ln=1===$||pn<.25,mn=Math.pow((un>m?m:m/2)*y,2);(ln||v(W,Y)>mn)&&(Q.push(h(W,Y,q)),W=Y),(ln||v(X,Z)>mn)&&(R.push(h(X,Z,q)),X=Z),T=tn,V=en}}var Mn=n[0],Ln=n[K-1],xn=R.length<2||Q.length<2;if(xn&&(!C&&!G||w)){for(var yn=0,Pn=0;Pn<K;Pn++){var kn=n[Pn];if(kn.runningLength>m){yn=t(m,L,z,kn.pressure);break}}for(var bn=i(Mn.point,u(s(f(o(Ln.point,Mn.point))),yn||U)),zn=[],An=0;An<=1;An+=.1)zn.push(p(bn,Mn.point,2*g*An));return zn}var On=[];if(!(C||G&&xn)){for(var Sn=i(Mn.point,u(f(o(Z=R[1],Y=Q[1])),c(Z,Y)/2)),_n=0;_n<=1;_n+=.2)On.push(p(Sn,Mn.point,g*_n));Q.shift(),R.shift()}var jn=[];if(G||C&&xn)jn.push(Ln.point);else for(var wn=i(Ln.point,u(s(Ln.vector),U)),In=0;In<=1;In+=.1)jn.push(p(wn,Ln.point,3*g*In));return Q.concat(jn,R.reverse(),On)}exports.default=function(n,r){return void 0===r&&(r={}),m(l(n,r),r)},exports.getStrokeOutlinePoints=m,exports.getStrokePoints=l; | ||
"use strict";function r(r,n){return[r[0]+n[0],r[1]+n[1]]}function n(r,n){return[r[0]-n[0],r[1]-n[1]]}function t(r,n){return[n[0]-r[0],n[1]-r[1]]}function e(r,n){return[r[0]*n,r[1]*n]}function i(r){return[r[1],-r[0]]}function o(r,n){return r[0]*n[0]+r[1]*n[1]}function u(r,t){return function(r){return r[0]*r[0]+r[1]*r[1]}(n(r,t))}function a(r){return function(r,n){return[r[0]/n,r[1]/n]}(r,function(r){return Math.hypot(r[0],r[1])}(r))}function v(r,n){return Math.hypot(r[1]-n[1],r[0]-n[0])}function s(r,n,t){var e=Math.sin(t),i=Math.cos(t),o=r[0]-n[0],u=r[1]-n[1];return[o*i-u*e+n[0],o*e+u*i+n[1]]}function f(n,i,o){return r(n,e(t(n,i),o))}function c(r,n){return r[0]===n[0]&&r[1]===n[1]}function p(r,n,t){return r*(1-t)+n*t}function h(r,n,t){return Math.max(n,Math.min(t,r))}function d(r,n,t,e){return void 0===e&&(e=.5),n?(e=h(t(e),0,1),(n<0?p(r,r+r*h(n,-.95,-.05),e):p(r-r*h(n,.05,.95),r,e))/2):r/2}Object.defineProperty(exports,"__esModule",{value:!0});var g=Math.min,l=Math.PI;function m(n,e){void 0===e&&(e={});var i=e.simulatePressure,u=e.streamline,s=void 0===u?.5:u,p=e.size,h=void 0===p?8:p;s/=2,void 0===i||i||(s/=2);var d=function(r){return Array.isArray(r[0])?r.map((function(r){var n=r[2];return[r[0],r[1],void 0===n?.5:n]})):r.map((function(r){var n=r.pressure;return[r.x,r.y,void 0===n?.5:n]}))}(n),g=d.length;if(0===g)return[];1===g&&d.push(r(d[0],[1,0]));for(var l=[{point:[d[0][0],d[0][1]],pressure:d[0][2],vector:[0,0],distance:0,runningLength:0}],m=1,M=0,L=d[m],x=l[M];m<g;L=d[++m],x=l[M]){var y=f(x.point,L,1-s);if(!c(x.point,y)){var P=L[2],k=a(t(y,x.point)),b=v(y,x.point);l.push({point:y,pressure:P,vector:k,distance:b,runningLength:x.runningLength+b}),M+=1}}for(var z=l[(g=l.length)-1].runningLength,A=g-2;A>1;A--){var O=l[A],S=O.runningLength,_=O.vector,j=o(l[A-1].vector,l[A].vector);if(z-S>h/2||j<.8){for(var w=A;w<g;w++)l[w].vector=_;break}}return l}function M(p,h){void 0===h&&(h={});var m=h.size,M=void 0===m?8:m,L=h.thinning,x=void 0===L?.5:L,y=h.smoothing,P=void 0===y?.5:y,k=h.simulatePressure,b=void 0===k||k,z=h.easing,A=void 0===z?function(r){return r}:z,O=h.start,S=void 0===O?{}:O,_=h.end,j=void 0===_?{}:_,w=h.last,I=void 0!==w&&w,q=h.streamline,B=void 0===q?.5:q;B/=2;var C=S.taper,D=void 0===C?0:C,E=S.easing,F=void 0===E?function(r){return r*(2-r)}:E,G=j.taper,H=void 0===G?0:G,J=j.easing,K=void 0===J?function(r){return--r*r*r+1}:J,N=p.length;if(0===N)return[];for(var Q=p[N-1].runningLength,R=[],T=[],U=p.slice(0,5).reduce((function(r,n){return(r+n.pressure)/2}),p[0].pressure),V=d(M,x,A,p[N-1].pressure),W=p[0].vector,X=p[0].point,Y=X,Z=X,$=Y,rr=1;rr<N-1;rr++){var nr=p[rr],tr=nr.point,er=nr.pressure,ir=nr.vector,or=nr.distance,ur=nr.runningLength;if(x){if(b){var ar=g(1,1-or/M),vr=g(1,or/M);er=g(1,U+vr/2*(ar-U))}V=d(M,x,A,er)}else V=M/2;var sr=ur<D?F(ur/D):1,fr=Q-ur<H?K((Q-ur)/H):1;V*=Math.min(sr,fr);var cr=p[rr+1].vector,pr=o(ir,cr);if(pr<0){for(var hr=e(i(W),V),dr=0;dr<1;dr+=.2)$=s(r(tr,hr),tr,l*-dr),Z=s(n(tr,hr),tr,l*dr),T.push($),R.push(Z);X=Z,Y=$}else{var gr=e(i(f(cr,ir,pr)),V);Z=n(tr,gr),$=r(tr,gr);var lr=1===rr||pr<.25,mr=Math.pow((ur>M?M:M/2)*P,2);(lr||u(X,Z)>mr)&&(R.push(f(X,Z,B)),X=Z),(lr||u(Y,$)>mr)&&(T.push(f(Y,$,B)),Y=$),U=er,W=ir}}var Mr=p[0],Lr=p[N-1],xr=T.length<2||R.length<2;if(xr&&(!D&&!H||I)){for(var yr=0,Pr=0;Pr<N;Pr++){var kr=p[Pr];if(kr.runningLength>M){yr=d(M,x,A,kr.pressure);break}}for(var br=n(Mr.point,e(i(a(t(Lr.point,Mr.point))),yr||V)),zr=[],Ar=0;Ar<=1;Ar+=.1)zr.push(s(br,Mr.point,2*l*Ar));return zr}var Or=[];if(!(D||H&&xr)){$=T[1];for(var Sr=1;Sr<R.length;Sr++)if(!c($,R[Sr])){Z=R[Sr];break}if(!c($,Z)){for(var _r=n(Mr.point,e(a(t($,Z)),v($,Z)/2)),jr=0;jr<=1;jr+=.2)Or.push(s(_r,Mr.point,l*jr));R.shift(),T.shift()}}var wr=[];if(H||D&&xr)wr.push(Lr.point);else for(var Ir=n(Lr.point,e(i(Lr.vector),V)),qr=0;qr<=1;qr+=.1)wr.push(s(Ir,Lr.point,3*l*qr));return R.concat(wr,T.reverse(),Or)}exports.default=function(r,n){return void 0===n&&(n={}),M(m(r,n),n)},exports.getStrokeOutlinePoints=M,exports.getStrokePoints=m; | ||
//# sourceMappingURL=perfect-freehand.cjs.production.min.js.map |
@@ -1,52 +0,2 @@ | ||
function lerp(y1, y2, mu) { | ||
return y1 * (1 - mu) + y2 * mu; | ||
} | ||
function clamp(n, a, b) { | ||
return Math.max(a, Math.min(b, n)); | ||
} | ||
/** | ||
* Convert an array of points to the correct format ([x, y, radius]) | ||
* @param points | ||
* @returns | ||
*/ | ||
function toPointsArray(points) { | ||
if (Array.isArray(points[0])) { | ||
return points.map(function (_ref) { | ||
var x = _ref[0], | ||
y = _ref[1], | ||
_ref$ = _ref[2], | ||
pressure = _ref$ === void 0 ? 0.5 : _ref$; | ||
return [x, y, pressure]; | ||
}); | ||
} else { | ||
return points.map(function (_ref2) { | ||
var x = _ref2.x, | ||
y = _ref2.y, | ||
_ref2$pressure = _ref2.pressure, | ||
pressure = _ref2$pressure === void 0 ? 0.5 : _ref2$pressure; | ||
return [x, y, pressure]; | ||
}); | ||
} | ||
} | ||
/** | ||
* Compute a radius based on the pressure. | ||
* @param size | ||
* @param thinning | ||
* @param easing | ||
* @param pressure | ||
* @returns | ||
*/ | ||
function getStrokeRadius(size, thinning, easing, pressure) { | ||
if (pressure === void 0) { | ||
pressure = 0.5; | ||
} | ||
if (!thinning) return size / 2; | ||
pressure = clamp(easing(pressure), 0, 1); | ||
return (thinning < 0 ? lerp(size, size + size * clamp(thinning, -0.95, -0.05), pressure) : lerp(size - size * clamp(thinning, 0.05, 0.95), size, pressure)) / 2; | ||
} | ||
/** | ||
* Negate a vector. | ||
@@ -186,3 +136,56 @@ * @param A | ||
} // isLeft: >0 for counterclockwise | ||
function isEqual(a, b) { | ||
return a[0] === b[0] && a[1] === b[1]; | ||
} | ||
function lerp(y1, y2, mu) { | ||
return y1 * (1 - mu) + y2 * mu; | ||
} | ||
function clamp(n, a, b) { | ||
return Math.max(a, Math.min(b, n)); | ||
} | ||
/** | ||
* Convert an array of points to the correct format ([x, y, radius]) | ||
* @param points | ||
* @returns | ||
*/ | ||
function toPointsArray(points) { | ||
if (Array.isArray(points[0])) { | ||
return points.map(function (_ref) { | ||
var x = _ref[0], | ||
y = _ref[1], | ||
_ref$ = _ref[2], | ||
pressure = _ref$ === void 0 ? 0.5 : _ref$; | ||
return [x, y, pressure]; | ||
}); | ||
} else { | ||
return points.map(function (_ref2) { | ||
var x = _ref2.x, | ||
y = _ref2.y, | ||
_ref2$pressure = _ref2.pressure, | ||
pressure = _ref2$pressure === void 0 ? 0.5 : _ref2$pressure; | ||
return [x, y, pressure]; | ||
}); | ||
} | ||
} | ||
/** | ||
* Compute a radius based on the pressure. | ||
* @param size | ||
* @param thinning | ||
* @param easing | ||
* @param pressure | ||
* @returns | ||
*/ | ||
function getStrokeRadius(size, thinning, easing, pressure) { | ||
if (pressure === void 0) { | ||
pressure = 0.5; | ||
} | ||
if (!thinning) return size / 2; | ||
pressure = clamp(easing(pressure), 0, 1); | ||
return (thinning < 0 ? lerp(size, size + size * clamp(thinning, -0.95, -0.05), pressure) : lerp(size - size * clamp(thinning, 0.05, 0.95), size, pressure)) / 2; | ||
} | ||
var min = Math.min, | ||
@@ -199,7 +202,12 @@ PI = Math.PI; | ||
function getStrokePoints(points, options) { | ||
var _options$simulatePres = options.simulatePressure, | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
var _options = options, | ||
_options$simulatePres = _options.simulatePressure, | ||
simulatePressure = _options$simulatePres === void 0 ? true : _options$simulatePres, | ||
_options$streamline = options.streamline, | ||
_options$streamline = _options.streamline, | ||
streamline = _options$streamline === void 0 ? 0.5 : _options$streamline, | ||
_options$size = options.size, | ||
_options$size = _options.size, | ||
size = _options$size === void 0 ? 8 : _options$size; | ||
@@ -224,8 +232,9 @@ streamline /= 2; | ||
for (var i = 1, curr = pts[i], prev = strokePoints[0]; i < pts.length; i++, curr = pts[i], prev = strokePoints[i - 1]) { | ||
var point = lrp(prev.point, curr, 1 - streamline), | ||
pressure = curr[2], | ||
vector = uni(vec(point, prev.point)), | ||
distance = dist(point, prev.point), | ||
runningLength = prev.runningLength + distance; | ||
for (var i = 1, j = 0, curr = pts[i], prev = strokePoints[j]; i < len; i++, curr = pts[i], prev = strokePoints[j]) { | ||
var point = lrp(prev.point, curr, 1 - streamline); | ||
if (isEqual(prev.point, point)) continue; | ||
var pressure = curr[2]; | ||
var vector = uni(vec(point, prev.point)); | ||
var distance = dist(point, prev.point); | ||
var runningLength = prev.runningLength + distance; | ||
strokePoints.push({ | ||
@@ -238,2 +247,3 @@ point: point, | ||
}); | ||
j += 1; // only increment j if we add an item to strokePoints | ||
} | ||
@@ -248,4 +258,6 @@ /* | ||
*/ | ||
// Update the length to the length of the strokePoints array. | ||
len = strokePoints.length; | ||
var totalLength = strokePoints[len - 1].runningLength; | ||
@@ -260,4 +272,4 @@ | ||
if (totalLength - _runningLength > size / 2 || dpr$1 < 0.8) { | ||
for (var j = _i; j < len; j++) { | ||
strokePoints[j].vector = _vector; | ||
for (var _j = _i; _j < len; _j++) { | ||
strokePoints[_j].vector = _vector; | ||
} | ||
@@ -291,24 +303,24 @@ | ||
var _options = options, | ||
_options$size2 = _options.size, | ||
size = _options$size2 === void 0 ? 8 : _options$size2, | ||
_options$thinning = _options.thinning, | ||
thinning = _options$thinning === void 0 ? 0.5 : _options$thinning, | ||
_options$smoothing = _options.smoothing, | ||
smoothing = _options$smoothing === void 0 ? 0.5 : _options$smoothing, | ||
_options$simulatePres2 = _options.simulatePressure, | ||
simulatePressure = _options$simulatePres2 === void 0 ? true : _options$simulatePres2, | ||
_options$easing = _options.easing, | ||
easing = _options$easing === void 0 ? function (t) { | ||
var _options2 = options, | ||
_options2$size = _options2.size, | ||
size = _options2$size === void 0 ? 8 : _options2$size, | ||
_options2$thinning = _options2.thinning, | ||
thinning = _options2$thinning === void 0 ? 0.5 : _options2$thinning, | ||
_options2$smoothing = _options2.smoothing, | ||
smoothing = _options2$smoothing === void 0 ? 0.5 : _options2$smoothing, | ||
_options2$simulatePre = _options2.simulatePressure, | ||
simulatePressure = _options2$simulatePre === void 0 ? true : _options2$simulatePre, | ||
_options2$easing = _options2.easing, | ||
easing = _options2$easing === void 0 ? function (t) { | ||
return t; | ||
} : _options$easing, | ||
_options$start = _options.start, | ||
start = _options$start === void 0 ? {} : _options$start, | ||
_options$end = _options.end, | ||
end = _options$end === void 0 ? {} : _options$end, | ||
_options$last = _options.last, | ||
isComplete = _options$last === void 0 ? false : _options$last; | ||
var _options2 = options, | ||
_options2$streamline = _options2.streamline, | ||
streamline = _options2$streamline === void 0 ? 0.5 : _options2$streamline; | ||
} : _options2$easing, | ||
_options2$start = _options2.start, | ||
start = _options2$start === void 0 ? {} : _options2$start, | ||
_options2$end = _options2.end, | ||
end = _options2$end === void 0 ? {} : _options2$end, | ||
_options2$last = _options2.last, | ||
isComplete = _options2$last === void 0 ? false : _options2$last; | ||
var _options3 = options, | ||
_options3$streamline = _options3.streamline, | ||
streamline = _options3$streamline === void 0 ? 0.5 : _options3$streamline; | ||
streamline /= 2; | ||
@@ -504,12 +516,20 @@ var _start$taper = start.taper, | ||
tr = rightPts[1]; | ||
tl = leftPts[1]; | ||
var _start2 = sub(firstPoint.point, mul(uni(vec(tr, tl)), dist(tr, tl) / 2)); | ||
for (var _i3 = 1; _i3 < leftPts.length; _i3++) { | ||
if (!isEqual(tr, leftPts[_i3])) { | ||
tl = leftPts[_i3]; | ||
break; | ||
} | ||
} | ||
for (var _t2 = 0, _step = 0.2; _t2 <= 1; _t2 += _step) { | ||
startCap.push(rotAround(_start2, firstPoint.point, PI * _t2)); | ||
if (!isEqual(tr, tl)) { | ||
var _start2 = sub(firstPoint.point, mul(uni(vec(tr, tl)), dist(tr, tl) / 2)); | ||
for (var _t2 = 0, _step = 0.2; _t2 <= 1; _t2 += _step) { | ||
startCap.push(rotAround(_start2, firstPoint.point, PI * _t2)); | ||
} | ||
leftPts.shift(); | ||
rightPts.shift(); | ||
} | ||
leftPts.shift(); | ||
rightPts.shift(); | ||
} | ||
@@ -516,0 +536,0 @@ /* |
@@ -22,1 +22,2 @@ export declare function lerp(y1: number, y2: number, mu: number): number; | ||
export declare function getStrokeRadius(size: number, thinning: number, easing: (t: number) => number, pressure?: number): number; | ||
export declare function withoutDuplicates(pts: number[][]): number[][]; |
@@ -96,1 +96,2 @@ /** | ||
export declare function clockwise(p1: number[], pc: number[], p2: number[]): boolean; | ||
export declare function isEqual(a: number[], b: number[]): boolean; |
{ | ||
"version": "0.4.71", | ||
"version": "0.4.91", | ||
"name": "perfect-freehand", | ||
@@ -4,0 +4,0 @@ "author": { |
@@ -5,5 +5,5 @@ # ![Screenshot](screenshot.svg 'Perfect Freehand') | ||
🔗 [Demo](https://perfect-freehand-example.vercel.app/) | ||
🔗 Try out a [demo](https://perfect-freehand-example.vercel.app/). | ||
💰 Want to use this library in your commercial product? [Contact me here](mailto:steveruizok+perfectfreehand@gmail.com). | ||
💰 Using this library in a commercial product? Consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok). | ||
@@ -239,2 +239,3 @@ ## Table of Contents | ||
```js | ||
import { strokePoints } from 'perfect-freehand' | ||
const strokePoints = getStrokePoints(rawInputPoints) | ||
@@ -245,3 +246,3 @@ ``` | ||
#### `getStrokeOutlinePoints` | ||
#### `getOutlinePoints` | ||
@@ -251,2 +252,3 @@ 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. | ||
```js | ||
import { getOutlinePoints } from 'perfect-freehand' | ||
const outlinePoints = getOutlinePoints(strokePoints) | ||
@@ -253,0 +255,0 @@ ``` |
@@ -17,3 +17,3 @@ import { toPointsArray, getStrokeRadius } from './utils' | ||
K extends { x: number; y: number; pressure?: number } | ||
>(points: (T | K)[], options: StrokeOptions): StrokePoint[] { | ||
>(points: (T | K)[], options = {} as StrokeOptions): StrokePoint[] { | ||
let { simulatePressure = true, streamline = 0.5, size = 8 } = options | ||
@@ -29,3 +29,3 @@ | ||
const len = pts.length | ||
let len = pts.length | ||
@@ -47,12 +47,15 @@ if (len === 0) return [] | ||
for ( | ||
let i = 1, curr = pts[i], prev = strokePoints[0]; | ||
i < pts.length; | ||
i++, curr = pts[i], prev = strokePoints[i - 1] | ||
let i = 1, j = 0, curr = pts[i], prev = strokePoints[j]; | ||
i < len; | ||
i++, curr = pts[i], prev = strokePoints[j] | ||
) { | ||
const point = vec.lrp(prev.point, curr, 1 - streamline), | ||
pressure = curr[2], | ||
vector = vec.uni(vec.vec(point, prev.point)), | ||
distance = vec.dist(point, prev.point), | ||
runningLength = prev.runningLength + distance | ||
const point = vec.lrp(prev.point, curr, 1 - streamline) | ||
if (vec.isEqual(prev.point, point)) continue | ||
const pressure = curr[2] | ||
const vector = vec.uni(vec.vec(point, prev.point)) | ||
const distance = vec.dist(point, prev.point) | ||
const runningLength = prev.runningLength + distance | ||
strokePoints.push({ | ||
@@ -65,2 +68,4 @@ point, | ||
}) | ||
j += 1 // only increment j if we add an item to strokePoints | ||
} | ||
@@ -78,2 +83,5 @@ | ||
// Update the length to the length of the strokePoints array. | ||
len = strokePoints.length | ||
const totalLength = strokePoints[len - 1].runningLength | ||
@@ -347,15 +355,23 @@ | ||
tr = rightPts[1] | ||
tl = leftPts[1] | ||
const start = vec.sub( | ||
firstPoint.point, | ||
vec.mul(vec.uni(vec.vec(tr, tl)), vec.dist(tr, tl) / 2) | ||
) | ||
for (let i = 1; i < leftPts.length; i++) { | ||
if (!vec.isEqual(tr, leftPts[i])) { | ||
tl = leftPts[i] | ||
break | ||
} | ||
} | ||
for (let t = 0, step = 0.2; t <= 1; t += step) { | ||
startCap.push(vec.rotAround(start, firstPoint.point, PI * t)) | ||
if (!vec.isEqual(tr, tl)) { | ||
const start = vec.sub( | ||
firstPoint.point, | ||
vec.mul(vec.uni(vec.vec(tr, tl)), vec.dist(tr, tl) / 2) | ||
) | ||
for (let t = 0, step = 0.2; t <= 1; t += step) { | ||
startCap.push(vec.rotAround(start, firstPoint.point, PI * t)) | ||
} | ||
leftPts.shift() | ||
rightPts.shift() | ||
} | ||
leftPts.shift() | ||
rightPts.shift() | ||
} | ||
@@ -362,0 +378,0 @@ |
@@ -0,1 +1,3 @@ | ||
import { isEqual } from './vec' | ||
export function lerp(y1: number, y2: number, mu: number) { | ||
@@ -55,1 +57,15 @@ return y1 * (1 - mu) + y2 * mu | ||
} | ||
export function withoutDuplicates(pts: number[][]) { | ||
const unique: number[][] = [] | ||
let prev: number[] | undefined = undefined | ||
for (let pt of pts) { | ||
if (prev && isEqual(prev, pt)) continue | ||
unique.push(pt) | ||
prev = pt | ||
} | ||
return pts | ||
} |
@@ -162,1 +162,5 @@ /** | ||
} | ||
export function isEqual(a: number[], b: number[]) { | ||
return a[0] === b[0] && a[1] === b[1] | ||
} |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
165107
1783
264