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 0.3.0 to 0.3.1

4

CHANGELOG.md

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

# 0.3.1
- Improves sharp corners that aren't sharp enough for caps, but are still sharp enough to confuse the distance-checking part of the algorithm.
# 0.3.0

@@ -2,0 +6,0 @@

42

dist/perfect-freehand.cjs.development.js

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

TAU = PI$1 / 2,
SHARP = PI$1 * 0.7;
SHARP = PI$1 * 0.8,
DULL = SHARP / 2;
/**

@@ -121,8 +122,8 @@ * ## getStrokePoints

x = px + (ix - px) * (1 - streamline);
y = py + (iy - py) * (1 - streamline); // Distance
x = lerp(px, ix, 1 - streamline);
y = lerp(py, iy, 1 - streamline); // Distance
distance = getDistance([x, y], prev); // Angle
angle = getAngle(prev, [x, y]); // Increment total length
angle = getAngle([x, y], prev); // Increment total length

@@ -187,3 +188,3 @@ totalLength += distance;

if (len === 1 || totalLength < size / 2) {
if (len === 1 || totalLength <= size / 4) {
var first = points[0],

@@ -194,4 +195,4 @@ last = points[len - 1],

if (thinning) {
var pressure = last[3] ? clamp(last[3], 0, 1) : 0.5;
r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(pressure, 0, 1)) : lerp(size, size + size * thinning, clamp(pressure, 0, 1))) / 2;
var pressure = last[2] ? clamp(last[2], 0, 1) : 0.5;
r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(pressure, 0.01, 0.99)) : lerp(size, size + size * thinning, clamp(pressure, 0.01, 0.99))) / 2;
}

@@ -231,3 +232,3 @@

r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(_pressure, 0, 1)) : lerp(size, size + size * thinning, clamp(_pressure, 0, 1))) / 2;
r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(_pressure, 0.05, 0.95)) : lerp(size, size + size * thinning, clamp(_pressure, 0.05, 0.95))) / 2;
} // 2.

@@ -238,3 +239,3 @@ // Draw a cap once we've reached the minimum length.

if (_short) {
if (clen < size / 2) {
if (clen < size / 4) {
continue;

@@ -249,3 +250,3 @@ } // The first point after we've reached the minimum length.

for (var _t = 0, _step = 0.1; _t <= 1; _t += _step) {
tl = projectPoint(_first, _angle + TAU + _t * PI$1, r - 1);
tl = projectPoint(_first, _angle + TAU - _t * PI$1, r - 1);
leftPts.push(tl);

@@ -264,3 +265,3 @@ }

for (var _t2 = 0, _step2 = 0.1; _t2 <= 1; _t2 += _step2) {
tr = projectPoint([x, y], _angle + TAU - _t2 * PI$1, r - 1);
tr = projectPoint([x, y], _angle + TAU + _t2 * PI$1, r * 0.9);
rightPts.push(tr);

@@ -270,12 +271,13 @@ }

// Find the delta between the current and previous angle.
var delta = getAngleDelta(prev[3], _angle);
var delta = getAngleDelta(prev[3], _angle),
absDelta = abs(delta);
if (abs(delta) > SHARP && clen > r) {
if (absDelta > SHARP && clen > r) {
// A sharp corner.
// Project points (left and right) for a cap.
var mid = getPointBetween(prev, [x, y], 0.5);
var mid = getPointBetween(prev, [x, y]);
for (var _t3 = 0, _step3 = 0.25; _t3 <= 1; _t3 += _step3) {
tl = projectPoint(mid, pa - TAU + _t3 * PI$1, r - 1);
tr = projectPoint(mid, pa + TAU + _t3 * -PI$1, r - 1);
tl = projectPoint(mid, pa - TAU + _t3 * -PI$1, r * 0.9);
tr = projectPoint(mid, pa + TAU + _t3 * PI$1, r * 0.9);
leftPts.push(tl);

@@ -290,4 +292,4 @@ rightPts.push(tr);

if (getDistance(pl, tl) > minDist) {
leftPts.push(getPointBetween(tl, pl, 0.5));
if (absDelta > DULL || getDistance(pl, tl) > minDist) {
leftPts.push(getPointBetween(tl, pl));
tl = pl;

@@ -297,4 +299,4 @@ } // Add point if far enough away from last right point

if (getDistance(pr, tr) > minDist) {
rightPts.push(getPointBetween(tr, pr, 0.5));
if (absDelta > DULL || getDistance(pr, tr) > minDist) {
rightPts.push(getPointBetween(tr, pr));
tr = pr;

@@ -301,0 +303,0 @@ }

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

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var r=Math.hypot,t=Math.cos,n=Math.max,e=Math.min,i=Math.sin,u=Math.atan2,o=Math.PI;function a(r,t,n){return r*(1-n)+t*n}function s(r,n,e){return[t(n)*e+r[0],i(n)*e+r[1]]}function f(r,t,n){return void 0===n&&(n=.5),[r[0]+(t[0]-r[0])*n,r[1]+(t[1]-r[1])*n]}function v(r,t){return u(t[1]-r[1],t[0]-r[0])}function h(t,n){return r(n[1]-t[1],n[0]-t[0])}function c(r,t,i){return n(t,e(i,r))}var p=Math.abs,d=Math.min,M=Math.PI,l=M/2,m=.7*M;function g(r,t){void 0===t&&(t=.5);var n,e,i,u=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),o=0,a=.01,s=u.length,f=[].concat(u[0],[0,0,0]),c=[f];if(0===s)return[];for(var p=1;p<s;p++){var d=u[p],M=d[2],l=f[0],m=f[1];a=h([n=l+(d[0]-l)*(1-t),e=m+(d[1]-m)*(1-t)],f),i=v(f,[n,e]),c.push(f=[n,e,M,i,a,o+=a])}return c}function x(r,t){void 0===t&&(t={});var n=t.size,e=void 0===n?8:n,i=t.thinning,u=void 0===i?.5:i,g=t.smoothing,x=t.simulatePressure,P=void 0===x||x,y=r.length,b=e*(void 0===g?.5:g),k=[],A=[],I=r[0],O=r[0],S=I,_=O,j=0,z=e/2,q=!0;if(0===y)return[];if(1===y||r[y-1][5]<e/2){var w=r[0],B=r[y-1],C=v(w,B);if(u){var D=B[3]?c(B[3],0,1):.5;z=(u>0?a(e-e*u,e,c(D,0,1)):a(e,e+e*u,c(D,0,1)))/2}for(var E=0;E<=1;E+=.1)S=s(w,C+M+l-E*M,z-1),_=s(B,C+l-E*M,z-1),k.push(S),A.push(_);return k.concat(A)}for(var F=1;F<y;F++){var G=r[F-1],H=G[3],J=r[F],K=J[0],L=J[1],N=J[2],Q=J[3],R=J[4],T=J[5];if(u){if(P){var U=d(1-R/e,1),V=d(R/e,1);N=d(1,j+V/2*(U-j))}z=(u>0?a(e-e*u,e,c(N,0,1)):a(e,e+e*u,c(N,0,1)))/2}if(q){if(T<e/2)continue;q=!1;for(var W=r[0],X=0;X<=1;X+=.1)S=s(W,Q+l+X*M,z-1),k.push(S);_=s(W,Q+l,z-1),A.push(_)}if(F===y-1)for(var Y=0;Y<=1;Y+=.1)_=s([K,L],Q+l-Y*M,z-1),A.push(_);else{var Z=function(r,t){var n=2*o,e=(t-r)%n;return 2*e%n-e}(G[3],Q);if(p(Z)>m&&T>z)for(var $=f(G,[K,L],.5),rr=0;rr<=1;rr+=.25)S=s($,H-l+rr*M,z-1),_=s($,H+l+rr*-M,z-1),k.push(S),A.push(_);else I=s([K,L],Q-l,z),O=s([K,L],Q+l,z),h(I,S)>b&&(k.push(f(S,I,.5)),S=I),h(O,_)>b&&(A.push(f(_,O,.5)),_=O);j=N}}return k.concat(A.reverse())}exports.default=function(r,t){return void 0===t&&(t={}),x(g(r,t.streamline),t)},exports.getStrokeOutlinePoints=x,exports.getStrokePoints=g;
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var r=Math.hypot,t=Math.cos,n=Math.max,e=Math.min,i=Math.sin,u=Math.atan2,o=Math.PI;function a(r,t,n){return r*(1-n)+t*n}function s(r,n,e){return[t(n)*e+r[0],i(n)*e+r[1]]}function f(r,t,n){return void 0===n&&(n=.5),[r[0]+(t[0]-r[0])*n,r[1]+(t[1]-r[1])*n]}function v(r,t){return u(t[1]-r[1],t[0]-r[0])}function h(t,n){return r(n[1]-t[1],n[0]-t[0])}function c(r,t,i){return n(t,e(i,r))}var p=Math.abs,d=Math.min,M=Math.PI,l=M/2,m=.8*M,g=m/2;function x(r,t){void 0===t&&(t=.5);var n,e,i,u=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),o=0,s=.01,f=u.length,c=[].concat(u[0],[0,0,0]),p=[c];if(0===f)return[];for(var d=1;d<f;d++){var M=u[d],l=M[1],m=M[2],g=c[1];s=h([n=a(c[0],M[0],1-t),e=a(g,l,1-t)],c),i=v([n,e],c),p.push(c=[n,e,m,i,s,o+=s])}return p}function P(r,t){void 0===t&&(t={});var n=t.size,e=void 0===n?8:n,i=t.thinning,u=void 0===i?.5:i,x=t.smoothing,P=t.simulatePressure,y=void 0===P||P,b=r.length,k=e*(void 0===x?.5:x),A=[],I=[],O=r[0],S=r[0],_=O,j=S,z=0,q=e/2,w=!0;if(0===b)return[];if(1===b||r[b-1][5]<=e/4){var B=r[0],C=r[b-1],D=v(B,C);if(u){var E=C[2]?c(C[2],0,1):.5;q=(u>0?a(e-e*u,e,c(E,.01,.99)):a(e,e+e*u,c(E,.01,.99)))/2}for(var F=0;F<=1;F+=.1)_=s(B,D+M+l-F*M,q-1),j=s(C,D+l-F*M,q-1),A.push(_),I.push(j);return A.concat(I)}for(var G=1;G<b;G++){var H=r[G-1],J=H[3],K=r[G],L=K[0],N=K[1],Q=K[2],R=K[3],T=K[4],U=K[5];if(u){if(y){var V=d(1-T/e,1),W=d(T/e,1);Q=d(1,z+W/2*(V-z))}q=(u>0?a(e-e*u,e,c(Q,.05,.95)):a(e,e+e*u,c(Q,.05,.95)))/2}if(w){if(U<e/4)continue;w=!1;for(var X=r[0],Y=0;Y<=1;Y+=.1)_=s(X,R+l-Y*M,q-1),A.push(_);j=s(X,R+l,q-1),I.push(j)}if(G===b-1)for(var Z=0;Z<=1;Z+=.1)j=s([L,N],R+l+Z*M,.9*q),I.push(j);else{var $=function(r,t){var n=2*o,e=(t-r)%n;return 2*e%n-e}(H[3],R),rr=p($);if(rr>m&&U>q)for(var tr=f(H,[L,N]),nr=0;nr<=1;nr+=.25)_=s(tr,J-l+nr*-M,.9*q),j=s(tr,J+l+nr*M,.9*q),A.push(_),I.push(j);else O=s([L,N],R-l,q),S=s([L,N],R+l,q),(rr>g||h(O,_)>k)&&(A.push(f(_,O)),_=O),(rr>g||h(S,j)>k)&&(I.push(f(j,S)),j=S);z=Q}}return A.concat(I.reverse())}exports.default=function(r,t){return void 0===t&&(t={}),P(x(r,t.streamline),t)},exports.getStrokeOutlinePoints=P,exports.getStrokePoints=x;
//# sourceMappingURL=perfect-freehand.cjs.production.min.js.map

@@ -80,3 +80,4 @@ var hypot = Math.hypot,

TAU = PI$1 / 2,
SHARP = PI$1 * 0.7;
SHARP = PI$1 * 0.8,
DULL = SHARP / 2;
/**

@@ -117,8 +118,8 @@ * ## getStrokePoints

x = px + (ix - px) * (1 - streamline);
y = py + (iy - py) * (1 - streamline); // Distance
x = lerp(px, ix, 1 - streamline);
y = lerp(py, iy, 1 - streamline); // Distance
distance = getDistance([x, y], prev); // Angle
angle = getAngle(prev, [x, y]); // Increment total length
angle = getAngle([x, y], prev); // Increment total length

@@ -183,3 +184,3 @@ totalLength += distance;

if (len === 1 || totalLength < size / 2) {
if (len === 1 || totalLength <= size / 4) {
var first = points[0],

@@ -190,4 +191,4 @@ last = points[len - 1],

if (thinning) {
var pressure = last[3] ? clamp(last[3], 0, 1) : 0.5;
r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(pressure, 0, 1)) : lerp(size, size + size * thinning, clamp(pressure, 0, 1))) / 2;
var pressure = last[2] ? clamp(last[2], 0, 1) : 0.5;
r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(pressure, 0.01, 0.99)) : lerp(size, size + size * thinning, clamp(pressure, 0.01, 0.99))) / 2;
}

@@ -227,3 +228,3 @@

r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(_pressure, 0, 1)) : lerp(size, size + size * thinning, clamp(_pressure, 0, 1))) / 2;
r = (thinning > 0 ? lerp(size - size * thinning, size, clamp(_pressure, 0.05, 0.95)) : lerp(size, size + size * thinning, clamp(_pressure, 0.05, 0.95))) / 2;
} // 2.

@@ -234,3 +235,3 @@ // Draw a cap once we've reached the minimum length.

if (_short) {
if (clen < size / 2) {
if (clen < size / 4) {
continue;

@@ -245,3 +246,3 @@ } // The first point after we've reached the minimum length.

for (var _t = 0, _step = 0.1; _t <= 1; _t += _step) {
tl = projectPoint(_first, _angle + TAU + _t * PI$1, r - 1);
tl = projectPoint(_first, _angle + TAU - _t * PI$1, r - 1);
leftPts.push(tl);

@@ -260,3 +261,3 @@ }

for (var _t2 = 0, _step2 = 0.1; _t2 <= 1; _t2 += _step2) {
tr = projectPoint([x, y], _angle + TAU - _t2 * PI$1, r - 1);
tr = projectPoint([x, y], _angle + TAU + _t2 * PI$1, r * 0.9);
rightPts.push(tr);

@@ -266,12 +267,13 @@ }

// Find the delta between the current and previous angle.
var delta = getAngleDelta(prev[3], _angle);
var delta = getAngleDelta(prev[3], _angle),
absDelta = abs(delta);
if (abs(delta) > SHARP && clen > r) {
if (absDelta > SHARP && clen > r) {
// A sharp corner.
// Project points (left and right) for a cap.
var mid = getPointBetween(prev, [x, y], 0.5);
var mid = getPointBetween(prev, [x, y]);
for (var _t3 = 0, _step3 = 0.25; _t3 <= 1; _t3 += _step3) {
tl = projectPoint(mid, pa - TAU + _t3 * PI$1, r - 1);
tr = projectPoint(mid, pa + TAU + _t3 * -PI$1, r - 1);
tl = projectPoint(mid, pa - TAU + _t3 * -PI$1, r * 0.9);
tr = projectPoint(mid, pa + TAU + _t3 * PI$1, r * 0.9);
leftPts.push(tl);

@@ -286,4 +288,4 @@ rightPts.push(tr);

if (getDistance(pl, tl) > minDist) {
leftPts.push(getPointBetween(tl, pl, 0.5));
if (absDelta > DULL || getDistance(pl, tl) > minDist) {
leftPts.push(getPointBetween(tl, pl));
tl = pl;

@@ -293,4 +295,4 @@ } // Add point if far enough away from last right point

if (getDistance(pr, tr) > minDist) {
rightPts.push(getPointBetween(tr, pr, 0.5));
if (absDelta > DULL || getDistance(pr, tr) > minDist) {
rightPts.push(getPointBetween(tr, pr));
tr = pr;

@@ -297,0 +299,0 @@ }

{
"version": "0.3.0",
"version": "0.3.1",
"license": "MIT",

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

@@ -79,4 +79,2 @@ # Perfect Freehand

```js
import getStroke from 'perfect-freehand'
// Create SVG path data using the points from perfect-freehand.

@@ -109,3 +107,3 @@ function getSvgPathFromStroke(stroke) {

import getStroke from 'perfect-freehand'
import getSvgPathFromStroke from './utils' // See "Rendering" section above.
import { getSvgPathFromStroke } from './utils'

@@ -116,7 +114,5 @@ export default function Example() {

function handlePointerDown(e) {
const point = [e.pageX, e.pageY, e.pressure]
setCurrentMark({
type: e.pointerType,
points: [point],
points: [[e.pageX, e.pageY, e.pressure]],
})

@@ -126,8 +122,6 @@ }

function handlePointerMove(e) {
const point = [e.pageX, e.pageY, e.pressure]
if (e.buttons === 1) {
setCurrentMark({
...currentMark,
points: [...currentMark.points, point],
points: [...currentMark.points, [e.pageX, e.pageY, e.pressure]],
})

@@ -137,9 +131,11 @@ }

const stroke = getStroke(currentMark.points, {
size: 8,
thinning: 0.5,
smoothing: 0.5,
streamline: 0.5,
simulatePressure: currentMark.type !== 'pen',
})
const stroke = currentMark
? getStroke(currentMark.points, {
size: 16,
thinning: 0.75,
smoothing: 0.5,
streamline: 0.5,
simulatePressure: currentMark.type !== 'pen',
})
: []

@@ -146,0 +142,0 @@ return (

@@ -15,3 +15,4 @@ import {

TAU = PI / 2,
SHARP = PI * 0.7
SHARP = PI * 0.8,
DULL = SHARP / 2

@@ -44,8 +45,8 @@ /**

for (let i = 1; i < len; i++) {
let [ix, iy, ip] = aPoints[i]
let [px, py] = prev
const [ix, iy, ip] = aPoints[i]
const [px, py] = prev
// Point
x = px + (ix - px) * (1 - streamline)
y = py + (iy - py) * (1 - streamline)
x = lerp(px, ix, 1 - streamline)
y = lerp(py, iy, 1 - streamline)

@@ -56,3 +57,3 @@ // Distance

// Angle
angle = getAngle(prev, [x, y])
angle = getAngle([x, y], prev)

@@ -111,3 +112,3 @@ // Increment total length

// If the point is only one point long, draw two caps at either end.
if (len === 1 || totalLength < size / 2) {
if (len === 1 || totalLength <= size / 4) {
let first = points[0],

@@ -118,8 +119,8 @@ last = points[len - 1],

if (thinning) {
const pressure = last[3] ? clamp(last[3], 0, 1) : 0.5
const pressure = last[2] ? clamp(last[2], 0, 1) : 0.5
r =
(thinning > 0
? lerp(size - size * thinning, size, clamp(pressure, 0, 1))
: lerp(size, size + size * thinning, clamp(pressure, 0, 1))) / 2
? lerp(size - size * thinning, size, clamp(pressure, 0.01, 0.99))
: lerp(size, size + size * thinning, clamp(pressure, 0.01, 0.99))) / 2
}

@@ -157,4 +158,4 @@

(thinning > 0
? lerp(size - size * thinning, size, clamp(pressure, 0, 1))
: lerp(size, size + size * thinning, clamp(pressure, 0, 1))) / 2
? lerp(size - size * thinning, size, clamp(pressure, 0.05, 0.95))
: lerp(size, size + size * thinning, clamp(pressure, 0.05, 0.95))) / 2
}

@@ -165,3 +166,3 @@

if (short) {
if (clen < size / 2) {
if (clen < size / 4) {
continue

@@ -177,3 +178,3 @@ }

for (let t = 0, step = 0.1; t <= 1; t += step) {
tl = projectPoint(first, angle + TAU + t * PI, r - 1)
tl = projectPoint(first, angle + TAU - t * PI, r - 1)
leftPts.push(tl)

@@ -193,3 +194,3 @@ }

for (let t = 0, step = 0.1; t <= 1; t += step) {
tr = projectPoint([x, y], angle + TAU - t * PI, r - 1)
tr = projectPoint([x, y], angle + TAU + t * PI, r * 0.9)
rightPts.push(tr)

@@ -199,13 +200,14 @@ }

// Find the delta between the current and previous angle.
const delta = getAngleDelta(prev[3], angle)
const delta = getAngleDelta(prev[3], angle),
absDelta = abs(delta)
if (abs(delta) > SHARP && clen > r) {
if (absDelta > SHARP && clen > r) {
// A sharp corner.
// Project points (left and right) for a cap.
const mid = getPointBetween(prev, [x, y], 0.5)
const mid = getPointBetween(prev, [x, y])
for (let t = 0, step = 0.25; t <= 1; t += step) {
tl = projectPoint(mid, pa - TAU + t * PI, r - 1)
tr = projectPoint(mid, pa + TAU + t * -PI, r - 1)
tl = projectPoint(mid, pa - TAU + t * -PI, r * 0.9)
tr = projectPoint(mid, pa + TAU + t * PI, r * 0.9)

@@ -223,4 +225,4 @@ leftPts.push(tl)

// Add projected point if far enough away from last left point
if (getDistance(pl, tl) > minDist) {
leftPts.push(getPointBetween(tl, pl, 0.5))
if (absDelta > DULL || getDistance(pl, tl) > minDist) {
leftPts.push(getPointBetween(tl, pl))
tl = pl

@@ -230,4 +232,4 @@ }

// Add point if far enough away from last right point
if (getDistance(pr, tr) > minDist) {
rightPts.push(getPointBetween(tr, pr, 0.5))
if (absDelta > DULL || getDistance(pr, tr) > minDist) {
rightPts.push(getPointBetween(tr, pr))
tr = pr

@@ -234,0 +236,0 @@ }

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