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 0.2.4 to 0.2.5

9

CHANGELOG.md

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

# 0.2.5
- Improves caps for start and end.
- Improves handling of short moves.
# 0.2.4
- Improves sharp corners.
# 0.2.3

@@ -2,0 +11,0 @@

1

dist/index.d.ts
import polygonClipping from 'polygon-clipping';
export declare function lerpAngles(a0: number, a1: number, t: number): number;
export interface StrokePointsOptions {

@@ -3,0 +4,0 @@ streamline?: number;

190

dist/perfect-freehand.cjs.development.js

@@ -53,3 +53,4 @@ 'use strict';

var hypot = Math.hypot,
var abs = Math.abs,
hypot = Math.hypot,
cos = Math.cos,

@@ -60,4 +61,5 @@ max = Math.max,

atan2 = Math.atan2,
PI = Math.PI;
var TAU = PI / 2;
PI = Math.PI,
TAU = PI / 2,
PI2 = PI * 2;

@@ -69,3 +71,3 @@ function projectPoint(x0, y0, a, d) {

function shortAngleDist(a0, a1) {
var max = Math.PI * 2;
var max = PI2;
var da = (a1 - a0) % max;

@@ -75,2 +77,6 @@ return 2 * da % max - da;

function lerpAngles(a0, a1, t) {
return a0 + shortAngleDist(a0, a1) * t;
}
function angleDelta(a0, a1) {

@@ -88,2 +94,10 @@ return shortAngleDist(a0, a1);

function getAngle(x0, y0, x1, y1) {
return atan2(y1 - y0, x1 - x0);
}
function getDistance(x0, y0, x1, y1) {
return hypot(y1 - y0, x1 - x0);
}
function clamp(n, a, b) {

@@ -154,9 +168,11 @@ return max(a, min(b, n));

x = px + (ix - px) * (1 - streamline);
y = py + (iy - py) * (1 - streamline); // Angle
y = py + (iy - py) * (1 - streamline); // Distance
angle = atan2(y - py, x - px); // Distance
distance = getDistance(x, y, px, py); // Angle
distance = hypot(y - py, x - px);
angle = getAngle(px, py, x, y); // If distance is very short, blend the angles
if (distance < 1) angle = lerpAngles(prev[2], angle, 0.5);
length += distance;
prev = [x, y, ip, angle, distance, length];
prev = [x, y, angle, ip, distance, length];
pts.push(prev);

@@ -193,11 +209,22 @@ } // Assign second angle to first point

return [];
} // Draw a kind of shitty shape around the start and end points.
}
var _points$ = points[0],
x0 = _points$[0],
y0 = _points$[1],
_points = points[len - 1],
x1 = _points[0],
y1 = _points[1],
p = points[len - 1][3],
leftPts = [],
rightPts = [],
size = clamp(minSize + (maxSize - minSize) * (p ? p : 0.5), minSize, maxSize),
angle = x0 === x1 ? 0 : getAngle(x0, y0, x1, y1);
var p0 = points[0],
p1 = points[len - 1],
size = p0[2] === p1[2] ? maxSize : minSize + (maxSize - minSize) * p1[2],
a = p0 === p1 ? Math.random() * (PI * 2) : atan2(p1[1] - p0[1], p1[0] - p0[0]),
m = getPointBetween(p0[0], p0[1], p1[0], p1[1], 0.5);
return [projectPoint(m[0], m[1], a + TAU, size), projectPoint(p0[0], p0[1], a + PI, size), projectPoint(m[0], m[1], a - TAU, size), projectPoint(p1[0], p1[1], a, size), projectPoint(m[0], m[1], a + TAU, size)];
for (var t = 0, step = 0.1; t <= 1; t += step) {
leftPts.push(projectPoint(x1, y1, angle + TAU - t * PI, size - 1));
rightPts.push(projectPoint(x0, y0, angle + TAU + t * PI, size - 1));
}
return leftPts.concat(rightPts.reverse());
}

@@ -236,6 +263,6 @@ /**

pp = 0.5,
prev = p1,
started = false,
length = 0,
leftPts = [],
rightPts = [],
leftPts = [p0],
rightPts = [p0],
d0,

@@ -251,9 +278,14 @@ d1;

for (var i = 1; i < len; i++) {
var _points2 = points[i - 1],
px = _points2[0],
py = _points2[1],
pa = _points2[2];
var _points$i = points[i],
x = _points$i[0],
y = _points$i[1],
ip = _points$i[2],
angle = _points$i[3],
distance = _points$i[4];
length += distance; // Size
angle = _points$i[2],
ip = _points$i[3],
distance = _points$i[4],
clen = _points$i[5];
length += clen; // Size

@@ -272,2 +304,19 @@ if (pressure) {

size = maxSize;
} // Handle line start
if (!started && length > size / 2) {
var _points$2 = points[0],
sx = _points$2[0],
sy = _points$2[1];
for (var t = 0, step = 0.25; t <= 1; t += step) {
m0 = projectPoint(sx, sy, angle + TAU + t * PI, size - 1);
leftPts.push(m0);
m1 = projectPoint(sx, sy, angle - TAU + t * -PI, size - 1);
rightPts.push(m1);
}
started = true;
continue;
} // 3. Shape

@@ -279,55 +328,35 @@

p1 = projectPoint(x, y, angle + TAU, size); // right
// // Add more points to the first and p1 points
if (i === 0) {
t0 = p0;
t1 = p1;
var delta = angleDelta(pa, angle); // Handle sharp corners differently
for (var t = 0, step = 0.33; t <= 1; t += step) {
m1 = projectPoint(prev[0], prev[1], angle - TAU + t * -PI, size * 2);
if (i === points.length - 1 || abs(delta) > PI * 0.75 && length > size) {
var _getPointBetween = getPointBetween(px, py, x, y, 0.5),
mx = _getPointBetween[0],
my = _getPointBetween[1];
for (var _t = 0, _step = 0.25; _t <= 1; _t += _step) {
m0 = projectPoint(mx, my, pa - TAU + _t * PI, size - 1);
leftPts.push(m0);
m1 = projectPoint(mx, my, pa + TAU + _t * -PI, size - 1);
rightPts.push(m1);
t1 = m1;
}
t0 = m0;
t1 = m1;
} else {
var delta = angleDelta(angle, prev[2]); // Handle sharp corners differently
// Project sideways
d0 = getDistance(p0[0], p0[1], t0[0], t0[1]);
if (Math.abs(delta) > PI * 0.72 && length > size * 2) {
if (delta > 0) {
m0 = prev;
leftPts.push(m0);
t0 = m0;
if (d0 > smooth) {
leftPts.push(m0);
m0 = getPointBetween(t0[0], t0[1], p0[0], p0[1], 0.5);
t0 = p0;
}
for (var _t = 0, _step = 0.3; _t <= 1; _t += _step) {
m1 = projectPoint(prev[0], prev[1], angle - TAU + _t * -PI, size);
rightPts.push(m1);
t1 = m1;
}
} else {
for (var _t2 = 0, _step2 = 0.3; _t2 <= 1; _t2 += _step2) {
m0 = projectPoint(prev[0], prev[1], angle + TAU + _t2 * PI, size);
leftPts.push(m0);
t0 = m0;
}
d1 = getDistance(p1[0], p1[1], t1[0], t1[1]);
m1 = prev;
rightPts.push(m1);
t1 = m1;
}
} else {
// Project sideways
d0 = Math.hypot(p0[0] - t0[0], p0[1] - t0[1]);
if (d0 > smooth) {
leftPts.push(m0);
m0 = getPointBetween(t0[0], t0[1], p0[0], p0[1], 0.5);
t0 = p0;
}
d1 = Math.hypot(p1[0] - t1[0], p1[1] - t1[1]);
if (d1 > smooth) {
rightPts.push(m1);
m1 = getPointBetween(t1[0], t1[1], p1[0], p1[1], 0.5);
t1 = p1;
}
if (d1 > smooth) {
rightPts.push(m1);
m1 = getPointBetween(t1[0], t1[1], p1[0], p1[1], 0.5);
t1 = p1;
}

@@ -337,7 +366,4 @@ }

pp = ip;
prev = [x, y, angle];
}
leftPts.push(prev);
rightPts.push(prev);
return leftPts.concat(rightPts.reverse());

@@ -377,3 +403,3 @@ }

totalLength = ps[ps.length - 1][5],
pts = totalLength < maxSize * 2 ? getShortStrokeOutlinePoints(ps, options) : getStrokeOutlinePoints(ps, options),
pts = totalLength < maxSize ? getShortStrokeOutlinePoints(ps, options) : getStrokeOutlinePoints(ps, options),
d = []; // If the length is too short, just draw a dot.

@@ -385,7 +411,7 @@ // If we're clipping the path, then find the polygon and add its faces.

for (var _iterator = _createForOfIteratorHelperLoose(poly), _step3; !(_step3 = _iterator()).done;) {
var face = _step3.value;
for (var _iterator = _createForOfIteratorHelperLoose(poly), _step2; !(_step2 = _iterator()).done;) {
var face = _step2.value;
for (var _iterator2 = _createForOfIteratorHelperLoose(face), _step4; !(_step4 = _iterator2()).done;) {
var verts = _step4.value;
for (var _iterator2 = _createForOfIteratorHelperLoose(face), _step3; !(_step3 = _iterator2()).done;) {
var verts = _step3.value;
var v0 = verts[0];

@@ -397,5 +423,5 @@ var v1 = verts[1];

for (var i = 1; i < verts.length; i++) {
var _getPointBetween = getPointBetween(v0[0], v0[1], v1[0], v1[1], 0.5),
mpx = _getPointBetween[0],
mpy = _getPointBetween[1];
var _getPointBetween2 = getPointBetween(v0[0], v0[1], v1[0], v1[1], 0.5),
mpx = _getPointBetween2[0],
mpy = _getPointBetween2[1];

@@ -416,5 +442,5 @@ d.push(" Q " + v0[0] + "," + v0[1] + " " + mpx + "," + mpy);

for (var _i = 1; _i < pts.length; _i++) {
var _getPointBetween2 = getPointBetween(_v[0], _v[1], _v2[0], _v2[1], 0.5),
_mpx = _getPointBetween2[0],
_mpy = _getPointBetween2[1];
var _getPointBetween3 = getPointBetween(_v[0], _v[1], _v2[0], _v2[1], 0.5),
_mpx = _getPointBetween3[0],
_mpy = _getPointBetween3[1];

@@ -427,2 +453,3 @@ d.push("Q " + _v[0] + "," + _v[1] + " " + _mpx + "," + _mpy);

d.push('Z');
return d.join(' ');

@@ -436,2 +463,3 @@ }

exports.getStrokePoints = getStrokePoints;
exports.lerpAngles = lerpAngles;
//# sourceMappingURL=perfect-freehand.cjs.development.js.map

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

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var r,t=(r=require("polygon-clipping"))&&"object"==typeof r&&"default"in r?r.default:r;function e(r,t){(null==t||t>r.length)&&(t=r.length);for(var e=0,n=new Array(t);e<t;e++)n[e]=r[e];return n}function n(r,t){var n;if("undefined"==typeof Symbol||null==r[Symbol.iterator]){if(Array.isArray(r)||(n=function(r,t){if(r){if("string"==typeof r)return e(r,void 0);var n=Object.prototype.toString.call(r).slice(8,-1);return"Object"===n&&r.constructor&&(n=r.constructor.name),"Map"===n||"Set"===n?Array.from(r):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?e(r,void 0):void 0}}(r))||t&&r&&"number"==typeof r.length){n&&(r=n);var o=0;return function(){return o>=r.length?{done:!0}:{done:!1,value:r[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=r[Symbol.iterator]()).next.bind(n)}var o=Math.hypot,i=Math.cos,a=Math.max,u=Math.min,v=Math.sin,s=Math.atan2,f=Math.PI,h=f/2;function l(r,t,e,n){return[i(e)*n+r,v(e)*n+t]}function p(r,t,e,n,o){return void 0===o&&(o=.5),[r+(e-r)*o,t+(n-t)*o]}function d(r,t){void 0===t&&(t={});var e,n,i,a=t.streamline,u=void 0===a?.5:a,v=function(r){return Array.isArray(r[0])?r.map((function(r){var t=r[2];return[r[0],r[1],void 0===t?.5:t]})):r.map((function(r){var t=r.pressure;return[r.x,r.y,void 0===t?.5:t]}))}(r),f=0,h=.01,l=v.length,p=[].concat(v[0],[0,0,0]),d=[p];if(0===l)return[];for(var c=1;c<l;c++){var m=v[c],y=m[2],g=p[0],M=p[1];i=s((n=M+(m[1]-M)*(1-u))-M,(e=g+(m[0]-g)*(1-u))-g),h=o(n-M,e-g),d.push(p=[e,n,y,i,h,f+=h])}return d.length>1&&(d[0][2]=d[1][2]),d}function c(r,t){void 0===t&&(t={});var e=t.minSize,n=void 0===e?2.5:e,o=t.maxSize,i=void 0===o?8:o,a=r.length;if(0===a)return[];var u=r[0],v=r[a-1],d=u[2]===v[2]?i:n+(i-n)*v[2],c=u===v?Math.random()*(2*f):s(v[1]-u[1],v[0]-u[0]),m=p(u[0],u[1],v[0],v[1],.5);return[l(m[0],m[1],c+h,d),l(u[0],u[1],c+f,d),l(m[0],m[1],c-h,d),l(v[0],v[1],c,d),l(m[0],m[1],c+h,d)]}function m(r,t){void 0===t&&(t={});var e=t.simulatePressure,n=void 0===e||e,o=t.pressure,i=void 0===o||o,v=t.minSize,s=void 0===v?2.5:v,d=t.maxSize,c=void 0===d?8:d,m=t.smooth,y=void 0===m?8:m,g=r.length,M=r[0],b=r[0],S=M,x=b,A=M,P=M,j=0,z=.5,I=b,O=0,k=[],w=[];if(0===g)return[];for(var Q=1;Q<g;Q++){var _=r[Q],q=_[0],C=_[1],E=_[2],T=_[3],U=_[4];if(O+=U,i){if(n){var $=u(1-U/c,1),B=u(U/c,1);E=u(1,z+B/2*($-z))}j=a(s,u(c,s+E*(c-s)))}else j=c;if(M=l(q,C,T-h,j),b=l(q,C,T+h,j),0===Q){S=M,x=b;for(var D=0;D<=1;D+=.33)P=l(I[0],I[1],T-h+D*-f,2*j),w.push(P),x=P}else{var F=function(r,t){var e=2*Math.PI,n=(t-r)%e;return 2*n%e-n}(T,I[2]);if(Math.abs(F)>.72*f&&O>2*j)if(F>0){k.push(A=I),S=A;for(var G=0;G<=1;G+=.3)P=l(I[0],I[1],T-h+G*-f,j),w.push(P),x=P}else{for(var H=0;H<=1;H+=.3)A=l(I[0],I[1],T+h+H*f,j),k.push(A),S=A;w.push(P=I),x=P}else Math.hypot(M[0]-S[0],M[1]-S[1])>y&&(k.push(A),A=p(S[0],S[1],M[0],M[1],.5),S=M),Math.hypot(b[0]-x[0],b[1]-x[1])>y&&(w.push(P),P=p(x[0],x[1],b[0],b[1],.5),x=b)}z=E,I=[q,C,T]}return k.push(I),w.push(I),k.concat(w.reverse())}function y(r){return t.union([r])}exports.clipPath=y,exports.default=function(r,t){if(void 0===t&&(t={}),0===r.length)return"";var e=t.clip,o=void 0===e||e,i=t.maxSize,a=void 0===i?8:i,u=d(r,t),v=u[u.length-1][5]<2*a?c(u,t):m(u,t),s=[];if(o)for(var f,h=n(y(v));!(f=h()).done;)for(var l,g=n(f.value);!(l=g()).done;){var M=l.value,b=M[0],S=M[1];M.push(b),s.push("M "+b[0]+" "+b[1]);for(var x=1;x<M.length;x++){var A=p(b[0],b[1],S[0],S[1],.5);s.push(" Q "+b[0]+","+b[1]+" "+A[0]+","+A[1]),b=S,S=M[x+1]}}else{var P=v[0],j=v[1];v.push(P),s.push("M "+P[0]+" "+P[1]);for(var z=1;z<v.length;z++){var I=p(P[0],P[1],j[0],j[1],.5);s.push("Q "+P[0]+","+P[1]+" "+I[0]+","+I[1]),P=j,j=v[z+1]}}return s.join(" ")},exports.getShortStrokeOutlinePoints=c,exports.getStrokeOutlinePoints=m,exports.getStrokePoints=d;
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var r,t=(r=require("polygon-clipping"))&&"object"==typeof r&&"default"in r?r.default:r;function e(r,t){(null==t||t>r.length)&&(t=r.length);for(var e=0,n=new Array(t);e<t;e++)n[e]=r[e];return n}function n(r,t){var n;if("undefined"==typeof Symbol||null==r[Symbol.iterator]){if(Array.isArray(r)||(n=function(r,t){if(r){if("string"==typeof r)return e(r,void 0);var n=Object.prototype.toString.call(r).slice(8,-1);return"Object"===n&&r.constructor&&(n=r.constructor.name),"Map"===n||"Set"===n?Array.from(r):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?e(r,void 0):void 0}}(r))||t&&r&&"number"==typeof r.length){n&&(r=n);var o=0;return function(){return o>=r.length?{done:!0}:{done:!1,value:r[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=r[Symbol.iterator]()).next.bind(n)}var o=Math.abs,i=Math.hypot,u=Math.cos,a=Math.max,s=Math.min,v=Math.sin,f=Math.atan2,l=Math.PI,p=l/2,h=2*l;function c(r,t,e,n){return[u(e)*n+r,v(e)*n+t]}function d(r,t){var e=(t-r)%h;return 2*e%h-e}function m(r,t,e){return r+d(r,t)*e}function g(r,t,e,n,o){return void 0===o&&(o=.5),[r+(e-r)*o,t+(n-t)*o]}function y(r,t,e,n){return f(n-t,e-r)}function b(r,t,e,n){return i(n-t,e-r)}function S(r,t,e){return a(t,s(e,r))}function x(r,t){void 0===t&&(t={});var e,n,o,i=t.streamline,u=void 0===i?.5:i,a=function(r){return Array.isArray(r[0])?r.map((function(r){var t=r[2];return[r[0],r[1],void 0===t?.5:t]})):r.map((function(r){var t=r.pressure;return[r.x,r.y,void 0===t?.5:t]}))}(r),s=0,v=.01,f=a.length,l=[].concat(a[0],[0,0,0]),p=[l];if(0===f)return[];for(var h=1;h<f;h++){var c=a[h],d=c[2],g=l[0],S=l[1];v=b(e=g+(c[0]-g)*(1-u),n=S+(c[1]-S)*(1-u),g,S),o=y(g,S,e,n),v<1&&(o=m(l[2],o,.5)),p.push(l=[e,n,o,d,v,s+=v])}return p.length>1&&(p[0][2]=p[1][2]),p}function M(r,t){void 0===t&&(t={});var e=t.minSize,n=void 0===e?2.5:e,o=t.maxSize,i=void 0===o?8:o,u=r.length;if(0===u)return[];for(var a=r[0],s=a[0],v=a[1],f=r[u-1],h=f[0],d=f[1],m=[],g=[],b=S(n+(i-n)*(r[u-1][3]||.5),n,i),x=s===h?0:y(s,v,h,d),M=0;M<=1;M+=.1)m.push(c(h,d,x+p-M*l,b-1)),g.push(c(s,v,x+p+M*l,b-1));return m.concat(g.reverse())}function A(r,t){void 0===t&&(t={});var e=t.simulatePressure,n=void 0===e||e,i=t.pressure,u=void 0===i||i,a=t.minSize,v=void 0===a?2.5:a,f=t.maxSize,h=void 0===f?8:f,m=t.smooth,y=void 0===m?8:m,x=r.length,M=r[0],A=r[0],P=M,j=A,z=M,O=M,I=0,k=.5,w=!1,Q=0,_=[M],q=[M];if(0===x)return[];for(var C=1;C<x;C++){var E=r[C-1],T=E[0],U=E[1],Z=E[2],$=r[C],B=$[0],D=$[1],F=$[2],G=$[3],H=$[4];if(Q+=$[5],u){if(n){var J=s(1-H/h,1),K=s(H/h,1);G=s(1,k+K/2*(J-k))}I=S(v+G*(h-v),v,h)}else I=h;if(!w&&Q>I/2){for(var L=r[0],N=L[0],R=L[1],V=0;V<=1;V+=.25)z=c(N,R,F+p+V*l,I-1),_.push(z),O=c(N,R,F-p+V*-l,I-1),q.push(O);w=!0}else{M=c(B,D,F-p,I),A=c(B,D,F+p,I);var W=d(Z,F);if(C===r.length-1||o(W)>.75*l&&Q>I){for(var X=g(T,U,B,D,.5),Y=X[0],rr=X[1],tr=0;tr<=1;tr+=.25)z=c(Y,rr,Z-p+tr*l,I-1),_.push(z),O=c(Y,rr,Z+p+tr*-l,I-1),q.push(O);P=z,j=O}else b(M[0],M[1],P[0],P[1])>y&&(_.push(z),z=g(P[0],P[1],M[0],M[1],.5),P=M),b(A[0],A[1],j[0],j[1])>y&&(q.push(O),O=g(j[0],j[1],A[0],A[1],.5),j=A);k=G}}return _.concat(q.reverse())}function P(r){return t.union([r])}exports.clipPath=P,exports.default=function(r,t){if(void 0===t&&(t={}),0===r.length)return"";var e=t.clip,o=void 0===e||e,i=t.maxSize,u=void 0===i?8:i,a=x(r,t),s=a[a.length-1][5]<u?M(a,t):A(a,t),v=[];if(o)for(var f,l=n(P(s));!(f=l()).done;)for(var p,h=n(f.value);!(p=h()).done;){var c=p.value,d=c[0],m=c[1];c.push(d),v.push("M "+d[0]+" "+d[1]);for(var y=1;y<c.length;y++){var b=g(d[0],d[1],m[0],m[1],.5);v.push(" Q "+d[0]+","+d[1]+" "+b[0]+","+b[1]),d=m,m=c[y+1]}}else{var S=s[0],j=s[1];s.push(S),v.push("M "+S[0]+" "+S[1]);for(var z=1;z<s.length;z++){var O=g(S[0],S[1],j[0],j[1],.5);v.push("Q "+S[0]+","+S[1]+" "+O[0]+","+O[1]),S=j,j=s[z+1]}}return v.push("Z"),v.join(" ")},exports.getShortStrokeOutlinePoints=M,exports.getStrokeOutlinePoints=A,exports.getStrokePoints=x,exports.lerpAngles=m;
//# sourceMappingURL=perfect-freehand.cjs.production.min.js.map

@@ -47,3 +47,4 @@ import polygonClipping from 'polygon-clipping';

var hypot = Math.hypot,
var abs = Math.abs,
hypot = Math.hypot,
cos = Math.cos,

@@ -54,4 +55,5 @@ max = Math.max,

atan2 = Math.atan2,
PI = Math.PI;
var TAU = PI / 2;
PI = Math.PI,
TAU = PI / 2,
PI2 = PI * 2;

@@ -63,3 +65,3 @@ function projectPoint(x0, y0, a, d) {

function shortAngleDist(a0, a1) {
var max = Math.PI * 2;
var max = PI2;
var da = (a1 - a0) % max;

@@ -69,2 +71,6 @@ return 2 * da % max - da;

function lerpAngles(a0, a1, t) {
return a0 + shortAngleDist(a0, a1) * t;
}
function angleDelta(a0, a1) {

@@ -82,2 +88,10 @@ return shortAngleDist(a0, a1);

function getAngle(x0, y0, x1, y1) {
return atan2(y1 - y0, x1 - x0);
}
function getDistance(x0, y0, x1, y1) {
return hypot(y1 - y0, x1 - x0);
}
function clamp(n, a, b) {

@@ -148,9 +162,11 @@ return max(a, min(b, n));

x = px + (ix - px) * (1 - streamline);
y = py + (iy - py) * (1 - streamline); // Angle
y = py + (iy - py) * (1 - streamline); // Distance
angle = atan2(y - py, x - px); // Distance
distance = getDistance(x, y, px, py); // Angle
distance = hypot(y - py, x - px);
angle = getAngle(px, py, x, y); // If distance is very short, blend the angles
if (distance < 1) angle = lerpAngles(prev[2], angle, 0.5);
length += distance;
prev = [x, y, ip, angle, distance, length];
prev = [x, y, angle, ip, distance, length];
pts.push(prev);

@@ -187,11 +203,22 @@ } // Assign second angle to first point

return [];
} // Draw a kind of shitty shape around the start and end points.
}
var _points$ = points[0],
x0 = _points$[0],
y0 = _points$[1],
_points = points[len - 1],
x1 = _points[0],
y1 = _points[1],
p = points[len - 1][3],
leftPts = [],
rightPts = [],
size = clamp(minSize + (maxSize - minSize) * (p ? p : 0.5), minSize, maxSize),
angle = x0 === x1 ? 0 : getAngle(x0, y0, x1, y1);
var p0 = points[0],
p1 = points[len - 1],
size = p0[2] === p1[2] ? maxSize : minSize + (maxSize - minSize) * p1[2],
a = p0 === p1 ? Math.random() * (PI * 2) : atan2(p1[1] - p0[1], p1[0] - p0[0]),
m = getPointBetween(p0[0], p0[1], p1[0], p1[1], 0.5);
return [projectPoint(m[0], m[1], a + TAU, size), projectPoint(p0[0], p0[1], a + PI, size), projectPoint(m[0], m[1], a - TAU, size), projectPoint(p1[0], p1[1], a, size), projectPoint(m[0], m[1], a + TAU, size)];
for (var t = 0, step = 0.1; t <= 1; t += step) {
leftPts.push(projectPoint(x1, y1, angle + TAU - t * PI, size - 1));
rightPts.push(projectPoint(x0, y0, angle + TAU + t * PI, size - 1));
}
return leftPts.concat(rightPts.reverse());
}

@@ -230,6 +257,6 @@ /**

pp = 0.5,
prev = p1,
started = false,
length = 0,
leftPts = [],
rightPts = [],
leftPts = [p0],
rightPts = [p0],
d0,

@@ -245,9 +272,14 @@ d1;

for (var i = 1; i < len; i++) {
var _points2 = points[i - 1],
px = _points2[0],
py = _points2[1],
pa = _points2[2];
var _points$i = points[i],
x = _points$i[0],
y = _points$i[1],
ip = _points$i[2],
angle = _points$i[3],
distance = _points$i[4];
length += distance; // Size
angle = _points$i[2],
ip = _points$i[3],
distance = _points$i[4],
clen = _points$i[5];
length += clen; // Size

@@ -266,2 +298,19 @@ if (pressure) {

size = maxSize;
} // Handle line start
if (!started && length > size / 2) {
var _points$2 = points[0],
sx = _points$2[0],
sy = _points$2[1];
for (var t = 0, step = 0.25; t <= 1; t += step) {
m0 = projectPoint(sx, sy, angle + TAU + t * PI, size - 1);
leftPts.push(m0);
m1 = projectPoint(sx, sy, angle - TAU + t * -PI, size - 1);
rightPts.push(m1);
}
started = true;
continue;
} // 3. Shape

@@ -273,55 +322,35 @@

p1 = projectPoint(x, y, angle + TAU, size); // right
// // Add more points to the first and p1 points
if (i === 0) {
t0 = p0;
t1 = p1;
var delta = angleDelta(pa, angle); // Handle sharp corners differently
for (var t = 0, step = 0.33; t <= 1; t += step) {
m1 = projectPoint(prev[0], prev[1], angle - TAU + t * -PI, size * 2);
if (i === points.length - 1 || abs(delta) > PI * 0.75 && length > size) {
var _getPointBetween = getPointBetween(px, py, x, y, 0.5),
mx = _getPointBetween[0],
my = _getPointBetween[1];
for (var _t = 0, _step = 0.25; _t <= 1; _t += _step) {
m0 = projectPoint(mx, my, pa - TAU + _t * PI, size - 1);
leftPts.push(m0);
m1 = projectPoint(mx, my, pa + TAU + _t * -PI, size - 1);
rightPts.push(m1);
t1 = m1;
}
t0 = m0;
t1 = m1;
} else {
var delta = angleDelta(angle, prev[2]); // Handle sharp corners differently
// Project sideways
d0 = getDistance(p0[0], p0[1], t0[0], t0[1]);
if (Math.abs(delta) > PI * 0.72 && length > size * 2) {
if (delta > 0) {
m0 = prev;
leftPts.push(m0);
t0 = m0;
if (d0 > smooth) {
leftPts.push(m0);
m0 = getPointBetween(t0[0], t0[1], p0[0], p0[1], 0.5);
t0 = p0;
}
for (var _t = 0, _step = 0.3; _t <= 1; _t += _step) {
m1 = projectPoint(prev[0], prev[1], angle - TAU + _t * -PI, size);
rightPts.push(m1);
t1 = m1;
}
} else {
for (var _t2 = 0, _step2 = 0.3; _t2 <= 1; _t2 += _step2) {
m0 = projectPoint(prev[0], prev[1], angle + TAU + _t2 * PI, size);
leftPts.push(m0);
t0 = m0;
}
d1 = getDistance(p1[0], p1[1], t1[0], t1[1]);
m1 = prev;
rightPts.push(m1);
t1 = m1;
}
} else {
// Project sideways
d0 = Math.hypot(p0[0] - t0[0], p0[1] - t0[1]);
if (d0 > smooth) {
leftPts.push(m0);
m0 = getPointBetween(t0[0], t0[1], p0[0], p0[1], 0.5);
t0 = p0;
}
d1 = Math.hypot(p1[0] - t1[0], p1[1] - t1[1]);
if (d1 > smooth) {
rightPts.push(m1);
m1 = getPointBetween(t1[0], t1[1], p1[0], p1[1], 0.5);
t1 = p1;
}
if (d1 > smooth) {
rightPts.push(m1);
m1 = getPointBetween(t1[0], t1[1], p1[0], p1[1], 0.5);
t1 = p1;
}

@@ -331,7 +360,4 @@ }

pp = ip;
prev = [x, y, angle];
}
leftPts.push(prev);
rightPts.push(prev);
return leftPts.concat(rightPts.reverse());

@@ -371,3 +397,3 @@ }

totalLength = ps[ps.length - 1][5],
pts = totalLength < maxSize * 2 ? getShortStrokeOutlinePoints(ps, options) : getStrokeOutlinePoints(ps, options),
pts = totalLength < maxSize ? getShortStrokeOutlinePoints(ps, options) : getStrokeOutlinePoints(ps, options),
d = []; // If the length is too short, just draw a dot.

@@ -379,7 +405,7 @@ // If we're clipping the path, then find the polygon and add its faces.

for (var _iterator = _createForOfIteratorHelperLoose(poly), _step3; !(_step3 = _iterator()).done;) {
var face = _step3.value;
for (var _iterator = _createForOfIteratorHelperLoose(poly), _step2; !(_step2 = _iterator()).done;) {
var face = _step2.value;
for (var _iterator2 = _createForOfIteratorHelperLoose(face), _step4; !(_step4 = _iterator2()).done;) {
var verts = _step4.value;
for (var _iterator2 = _createForOfIteratorHelperLoose(face), _step3; !(_step3 = _iterator2()).done;) {
var verts = _step3.value;
var v0 = verts[0];

@@ -391,5 +417,5 @@ var v1 = verts[1];

for (var i = 1; i < verts.length; i++) {
var _getPointBetween = getPointBetween(v0[0], v0[1], v1[0], v1[1], 0.5),
mpx = _getPointBetween[0],
mpy = _getPointBetween[1];
var _getPointBetween2 = getPointBetween(v0[0], v0[1], v1[0], v1[1], 0.5),
mpx = _getPointBetween2[0],
mpy = _getPointBetween2[1];

@@ -410,5 +436,5 @@ d.push(" Q " + v0[0] + "," + v0[1] + " " + mpx + "," + mpy);

for (var _i = 1; _i < pts.length; _i++) {
var _getPointBetween2 = getPointBetween(_v[0], _v[1], _v2[0], _v2[1], 0.5),
_mpx = _getPointBetween2[0],
_mpy = _getPointBetween2[1];
var _getPointBetween3 = getPointBetween(_v[0], _v[1], _v2[0], _v2[1], 0.5),
_mpx = _getPointBetween3[0],
_mpy = _getPointBetween3[1];

@@ -421,2 +447,3 @@ d.push("Q " + _v[0] + "," + _v[1] + " " + _mpx + "," + _mpy);

d.push('Z');
return d.join(' ');

@@ -426,3 +453,3 @@ }

export default getPath;
export { clipPath, getShortStrokeOutlinePoints, getStrokeOutlinePoints, getStrokePoints };
export { clipPath, getShortStrokeOutlinePoints, getStrokeOutlinePoints, getStrokePoints, lerpAngles };
//# sourceMappingURL=perfect-freehand.esm.js.map
{
"version": "0.2.4",
"version": "0.2.5",
"license": "MIT",

@@ -4,0 +4,0 @@ "main": "dist/index.js",

@@ -5,4 +5,5 @@ import polygonClipping from 'polygon-clipping'

const { hypot, cos, max, min, sin, atan2, PI } = Math
const TAU = PI / 2
const { abs, hypot, cos, max, min, sin, atan2, PI } = Math,
TAU = PI / 2,
PI2 = PI * 2

@@ -14,3 +15,3 @@ function projectPoint(x0: number, y0: number, a: number, d: number) {

function shortAngleDist(a0: number, a1: number) {
var max = Math.PI * 2
var max = PI2
var da = (a1 - a0) % max

@@ -20,2 +21,6 @@ return ((2 * da) % max) - da

export function lerpAngles(a0: number, a1: number, t: number) {
return a0 + shortAngleDist(a0, a1) * t
}
function angleDelta(a0: number, a1: number) {

@@ -34,3 +39,10 @@ return shortAngleDist(a0, a1)

}
function getAngle(x0: number, y0: number, x1: number, y1: number) {
return atan2(y1 - y0, x1 - x0)
}
function getDistance(x0: number, y0: number, x1: number, y1: number) {
return hypot(y1 - y0, x1 - x0)
}
function clamp(n: number, a: number, b: number) {

@@ -117,9 +129,13 @@ return max(a, min(b, n))

// Distance
distance = getDistance(x, y, px, py)
// Angle
angle = atan2(y - py, x - px)
angle = getAngle(px, py, x, y)
// Distance
distance = hypot(y - py, x - px)
// If distance is very short, blend the angles
if (distance < 1) angle = lerpAngles(prev[2], angle, 0.5)
length += distance
prev = [x, y, ip, angle, distance, length]
prev = [x, y, angle, ip, distance, length]
pts.push(prev)

@@ -147,3 +163,2 @@ }

const { minSize = 2.5, maxSize = 8 } = options
const len = points.length

@@ -156,19 +171,20 @@

// Draw a kind of shitty shape around the start and end points.
const p0 = points[0],
p1 = points[len - 1],
size = p0[2] === p1[2] ? maxSize : minSize + (maxSize - minSize) * p1[2],
a =
p0 === p1
? Math.random() * (PI * 2)
: atan2(p1[1] - p0[1], p1[0] - p0[0]),
m = getPointBetween(p0[0], p0[1], p1[0], p1[1], 0.5)
const [x0, y0] = points[0],
[x1, y1] = points[len - 1],
p = points[len - 1][3],
leftPts: number[][] = [],
rightPts: number[][] = [],
size = clamp(
minSize + (maxSize - minSize) * (p ? p : 0.5),
minSize,
maxSize
),
angle = x0 === x1 ? 0 : getAngle(x0, y0, x1, y1)
return [
projectPoint(m[0], m[1], a + TAU, size),
projectPoint(p0[0], p0[1], a + PI, size),
projectPoint(m[0], m[1], a - TAU, size),
projectPoint(p1[0], p1[1], a, size),
projectPoint(m[0], m[1], a + TAU, size),
]
for (let t = 0, step = 0.1; t <= 1; t += step) {
leftPts.push(projectPoint(x1, y1, angle + TAU - t * PI, size - 1))
rightPts.push(projectPoint(x0, y0, angle + TAU + t * PI, size - 1))
}
return leftPts.concat(rightPts.reverse())
}

@@ -203,6 +219,6 @@

pp = 0.5,
prev = p1,
started = false,
length = 0,
leftPts: number[][] = [],
rightPts: number[][] = [],
leftPts: number[][] = [p0],
rightPts: number[][] = [p0],
d0: number,

@@ -219,5 +235,7 @@ d1: number

for (let i = 1; i < len; i++) {
let [x, y, ip, angle, distance] = points[i]
length += distance
const [px, py, pa] = points[i - 1]
let [x, y, angle, ip, distance, clen] = points[i]
length += clen
// Size

@@ -227,3 +245,3 @@ if (pressure) {

// Simulate pressure by accellerating the reported pressure.
let rp = min(1 - distance / maxSize, 1)
const rp = min(1 - distance / maxSize, 1)
const sp = min(distance / maxSize, 1)

@@ -238,2 +256,17 @@ ip = min(1, pp + (rp - pp) * (sp / 2))

// Handle line start
if (!started && length > size / 2) {
const [sx, sy] = points[0]
for (let t = 0, step = 0.25; t <= 1; t += step) {
m0 = projectPoint(sx, sy, angle + TAU + t * PI, size - 1)
leftPts.push(m0)
m1 = projectPoint(sx, sy, angle - TAU + t * -PI, size - 1)
rightPts.push(m1)
}
started = true
continue
}
// 3. Shape

@@ -243,53 +276,31 @@ p0 = projectPoint(x, y, angle - TAU, size) // left

// // Add more points to the first and p1 points
if (i === 0) {
t0 = p0
t1 = p1
const delta = angleDelta(pa, angle)
for (let t = 0, step = 0.33; t <= 1; t += step) {
m1 = projectPoint(prev[0], prev[1], angle - TAU + t * -PI, size * 2)
// Handle sharp corners differently
if (i === points.length - 1 || (abs(delta) > PI * 0.75 && length > size)) {
const [mx, my] = getPointBetween(px, py, x, y, 0.5)
for (let t = 0, step = 0.25; t <= 1; t += step) {
m0 = projectPoint(mx, my, pa - TAU + t * PI, size - 1)
leftPts.push(m0)
m1 = projectPoint(mx, my, pa + TAU + t * -PI, size - 1)
rightPts.push(m1)
t1 = m1
}
t0 = m0
t1 = m1
} else {
const delta = angleDelta(angle, prev[2])
// Project sideways
d0 = getDistance(p0[0], p0[1], t0[0], t0[1])
if (d0 > smooth) {
leftPts.push(m0)
m0 = getPointBetween(t0[0], t0[1], p0[0], p0[1], 0.5)
t0 = p0
}
// Handle sharp corners differently
if (Math.abs(delta) > PI * 0.72 && length > size * 2) {
if (delta > 0) {
m0 = prev
leftPts.push(m0)
t0 = m0
for (let t = 0, step = 0.3; t <= 1; t += step) {
m1 = projectPoint(prev[0], prev[1], angle - TAU + t * -PI, size)
rightPts.push(m1)
t1 = m1
}
} else {
for (let t = 0, step = 0.3; t <= 1; t += step) {
m0 = projectPoint(prev[0], prev[1], angle + TAU + t * PI, size)
leftPts.push(m0)
t0 = m0
}
m1 = prev
rightPts.push(m1)
t1 = m1
}
} else {
// Project sideways
d0 = Math.hypot(p0[0] - t0[0], p0[1] - t0[1])
if (d0 > smooth) {
leftPts.push(m0)
m0 = getPointBetween(t0[0], t0[1], p0[0], p0[1], 0.5)
t0 = p0
}
d1 = Math.hypot(p1[0] - t1[0], p1[1] - t1[1])
if (d1 > smooth) {
rightPts.push(m1)
m1 = getPointBetween(t1[0], t1[1], p1[0], p1[1], 0.5)
t1 = p1
}
d1 = getDistance(p1[0], p1[1], t1[0], t1[1])
if (d1 > smooth) {
rightPts.push(m1)
m1 = getPointBetween(t1[0], t1[1], p1[0], p1[1], 0.5)
t1 = p1
}

@@ -299,8 +310,4 @@ }

pp = ip
prev = [x, y, angle]
}
leftPts.push(prev)
rightPts.push(prev)
return leftPts.concat(rightPts.reverse())

@@ -337,3 +344,3 @@ }

pts =
totalLength < maxSize * 2
totalLength < maxSize
? getShortStrokeOutlinePoints(ps, options)

@@ -378,3 +385,5 @@ : getStrokeOutlinePoints(ps, options),

d.push('Z')
return d.join(' ')
}

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