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.3.3 to 0.3.4

32

CHANGELOG.md

@@ -1,14 +0,18 @@

# 0.3.4
## 0.3.4
- Fixes bug in short strokes.
## 0.3.3
- Adds the `easing` property. This property accepts an [easing function](https://gist.github.com/gre/1650294) that will apply to all pressure measurements (real or simulated). Defaults to a linear easing (`t => t`).
# 0.3.2
## 0.3.2
- Superficial changes.
# 0.3.1
## 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
## 0.3.0

@@ -34,3 +38,3 @@ This version has breaking changes.

# 0.2.5
## 0.2.5

@@ -40,19 +44,19 @@ - Improves caps for start and end.

# 0.2.4
## 0.2.4
- Improves sharp corners.
# 0.2.3
## 0.2.3
- Brings back `simulatePressure` until I have a better way of guessing.
# 0.2.2
## 0.2.2
- Slight fix to line starts.
# 0.2.1
## 0.2.1
- Fixes actual pressure sensitivity.
# 0.2.0
## 0.2.0

@@ -70,16 +74,16 @@ - Breaks up algorithm into smaller functions. Because `getPath` returns an SVG path data, you can use `getPath` only with the Path2D element (for HTML Canvas) or SVG paths. These new functions will allow you to create paths in other rendering technologies.

# 0.1.3
## 0.1.3
- Removes hidden options, uses `maxSize` for velocity calculations.
# 0.1.2
## 0.1.2
- Fixes bug in pressure.
# 0.1.2
## 0.1.2
- Fixes bug with empty input array.
# 0.1.0
## 0.1.0
- Hey world.

@@ -168,3 +168,3 @@ 'use strict';

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

@@ -171,0 +171,0 @@ last = points[len - 1],

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

@@ -164,3 +164,3 @@ var hypot = Math.hypot,

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

@@ -167,0 +167,0 @@ last = points[len - 1],

{
"version": "0.3.3",
"version": "0.3.4",
"name": "perfect-freehand",

@@ -4,0 +4,0 @@ "author": {

@@ -1,9 +0,15 @@

# Perfect Freehand
# ![Screenshot](screenshot.svg 'Perfect Freehand')
Perfect freehand is a library for generating freehand strokes.
Draw perfect pressure-sensitive freehand strokes.
![Screenshot](https://github.com/steveruizok/perfect-freehand/raw/main/screenshot.png)
🔗 [Demo](https://perfect-freehand-example.vercel.app/)
## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Support](#support)
- [Discussion](#discussion)
- [Author](#Author)
## Installation

@@ -23,3 +29,3 @@

This library's default export is a function that:
This package's default export is a function that:

@@ -81,19 +87,19 @@ - accepts an array of points and an (optional) options object

For example, here is a function that takes in a stroke and returns SVG path data. You can use the string returned by this function in two ways. For SVG, you can pass the data into `path` element's [`d` property](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d). For HTML canvas, you can pass the string into the [`Path2D` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths) and then stroke or fill the path.
For example, the function below will turn a stroke into SVG path data for use with either [SVG paths](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) or HTML Canvas (using the [`Path2D` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths)).
```js
// Create SVG path data using the points from perfect-freehand.
function getSvgPathFromStroke(stroke) {
function getSvgPathFromStroke(points) {
if (points.length === 0) return ''
const d = []
let [p0, p1] = stroke
let [p0, p1] = points
d.push(`M ${p0[0]} ${p0[1]} Q`)
d.push('M', p0[0], p0[1], 'Q')
for (let i = 1; i < stroke.length; i++) {
const mpx = p0[0] + (p1[0] - p0[0]) / 2
const mpy = p0[1] + (p1[1] - p0[1]) / 2
d.push(`${p0[0]},${p0[1]} ${mpx},${mpy}`)
for (let i = 1; i < points.length; i++) {
d.push(p0[0], p0[1], (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2)
p0 = p1
p1 = stroke[i + 1]
p1 = points[i]
}

@@ -107,4 +113,26 @@

# Example
To render a stroke as a flat polygon, add the [`polygon-clipping`](https://github.com/mfogel/polygon-clipping) package and use the following function together with the `getSvgPathFromStroke`.
```js
import polygonClipping from 'polygon-clipping'
function getFlatSvgPathFromStroke(stroke) {
const poly = polygonClipping.union([stroke])
const d = []
for (let face of poly) {
for (let points of face) {
d.push(getSvgPathFromStroke(points))
}
}
return d.join(' ')
}
```
> **Tip:** For implementations in Typescript, see the example project included in this repository.
### Example
```jsx

@@ -119,2 +147,3 @@ import * as React from 'react'

function handlePointerDown(e) {
e.preventDefault()
setCurrentMark({

@@ -127,2 +156,3 @@ type: e.pointerType,

function handlePointerMove(e) {
e.preventDefault()
if (e.buttons === 1) {

@@ -136,17 +166,4 @@ setCurrentMark({

const stroke = currentMark
? getStroke(currentMark.points, {
size: 16,
thinning: 0.75,
smoothing: 0.5,
streamline: 0.5,
easing: t => t * t * t,
simulatePressure: currentMark.type !== 'pen',
})
: []
return (
<svg
width={800}
height={600}
onPointerDown={handlePointerDown}

@@ -156,3 +173,15 @@ onPointerMove={handlePointerMove}

>
{currentMark && <path d={getSvgPathFromStroke(stroke)} />}
{currentMark && (
<path
d={getSvgPathFromStroke(
getStroke(currentMark.points, {
size: 24,
thinning: 0.75,
smoothing: 0.5,
streamline: 0.5,
simulatePressure: currentMark.type !== 'pen',
})
)}
/>
)}
</svg>

@@ -165,6 +194,12 @@ )

# Advanced Usage
### Advanced Usage
## Functions
#### `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.

@@ -175,2 +210,3 @@

```js
const strokePoints = getStrokePoints(rawInputPoints)
```

@@ -184,40 +220,16 @@

## Rendering a Flattened Stroke
To render a stroke as a flat polygon, add the `polygon-clipping` package and use (or refer to) the following function.
```js
import getStroke from 'perfect-freehand'
import polygonClipping from 'polygon-clipping'
const outlinePoints = getOutlinePoints(strokePoints)
```
function getFlatSvgPathFromStroke(stroke) {
## Support
const poly = polygonClipping.union([stroke] as any)
Please [open an issue](https://github.com/steveruizok/perfect-freehand/issues/new) for support.
const d = []
## Discussion
for (let face of poly) {
for (let pts of face) {
let [p0, p1] = pts
Have an idea or casual question? Visit the [discussion page](https://github.com/steveruizok/perfect-freehand/discussions).
d.push(`M ${p0[0]} ${p0[1]} Q`)
for (let i = 1; i < pts.length; i++) {
const mpx = p0[0] + (p1[0] - p0[0]) / 2
const mpy = p0[1] + (p1[1] - p0[1]) / 2
d.push(`${p0[0]},${p0[1]} ${mpx},${mpy}`)
p0 = p1
p1 = pts[i + 1]
}
d.push('Z')
}
}
return d.join(' ')
}
```
## Author
- [@steveruizok](https://twitter.com/steveruizok)

@@ -109,3 +109,3 @@ import {

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

@@ -112,0 +112,0 @@ last = points[len - 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

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