All Projects → steveruizok → Perfect Freehand

steveruizok / Perfect Freehand

Licence: mit
Draw perfect pressure-sensitive freehand strokes.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Perfect Freehand

Macaw
Powerful and easy-to-use vector graphics Swift library with SVG support
Stars: ✭ 5,756 (+476.18%)
Mutual labels:  graphics, drawing, svg
Openvg
Tools for exploring OpenVG
Stars: ✭ 371 (-62.86%)
Mutual labels:  graphics, drawing
Luxor.jl
Simple drawings using vector graphics; Cairo "for tourists!"
Stars: ✭ 293 (-70.67%)
Mutual labels:  graphics, drawing
Scour
Scour - An SVG Optimizer / Cleaner
Stars: ✭ 443 (-55.66%)
Mutual labels:  graphics, svg
Rough
Create graphics with a hand-drawn, sketchy, appearance
Stars: ✭ 16,472 (+1548.85%)
Mutual labels:  graphics, svg
Go Chart
go chart is a basic charting library in go.
Stars: ✭ 3,254 (+225.73%)
Mutual labels:  drawing, svg
Pts
A library for visualization and creative-coding
Stars: ✭ 4,628 (+363.26%)
Mutual labels:  graphics, svg
Oshmi
SCADA HMI for substations and automation applications.
Stars: ✭ 180 (-81.98%)
Mutual labels:  graphics, svg
Bounty
Javascript and SVG odometer effect library with motion blur
Stars: ✭ 724 (-27.53%)
Mutual labels:  graphics, svg
Imagesharp
📷 A modern, cross-platform, 2D Graphics library for .NET
Stars: ✭ 5,186 (+419.12%)
Mutual labels:  graphics, drawing
Sketch
Sketch have a lot of basic functions to develop a drawing app for iPhone. Anyone can easily create drawing iOS Application.
Stars: ✭ 229 (-77.08%)
Mutual labels:  graphics, drawing
Nn Svg
Publication-ready NN-architecture schematics.
Stars: ✭ 805 (-19.42%)
Mutual labels:  drawing, svg
Gooey React
The gooey effect for React, used for shape blobbing / metaballs (0.5 KB) 🧽
Stars: ✭ 219 (-78.08%)
Mutual labels:  graphics, svg
Mojs
The motion graphics toolbelt for the web
Stars: ✭ 17,189 (+1620.62%)
Mutual labels:  graphics, svg
Picasso
Picasso is a high quality 2D vector graphic rendering library. It support path , matrix , gradient , pattern , image and truetype font.
Stars: ✭ 205 (-79.48%)
Mutual labels:  graphics, svg
Oblivion
The language of Art
Stars: ✭ 414 (-58.56%)
Mutual labels:  graphics, svg
Godot Texture Painter
A GPU-accelerated texture painter written in Godot 3.0
Stars: ✭ 155 (-84.48%)
Mutual labels:  graphics, drawing
Gerbolyze
Render high-resolution bitmap images to PCB gerber files
Stars: ✭ 169 (-83.08%)
Mutual labels:  graphics, svg
Azure Design
Here you will find my complete Azure Visio Stencil and bonus SVG and PNG versions for all of the Azure Service and configuration items.
Stars: ✭ 470 (-52.95%)
Mutual labels:  drawing, svg
Macsvg
macSVG - An open-source macOS app for designing HTML5 SVG (Scalable Vector Graphics) art and animation with a WebKit web view ➤➤➤
Stars: ✭ 789 (-21.02%)
Mutual labels:  graphics, svg

Screenshot

Draw perfect pressure-sensitive freehand strokes.

🔗 Demo

Table of Contents

Installation

npm install perfect-freehand

or

yarn add perfect-freehand

Usage

This package's default export is a function that:

  • accepts an array of points and an (optional) options object
  • returns a stroke as an array of points formatted as [x, y]
import getStroke from 'perfect-freehand'

You may format your input points as array or an object. In both cases, the value for pressure is optional (it will default to .5).

getStroke([
  [0, 0, 0],
  [10, 5, 0.5],
  [20, 8, 0.3],
])

getStroke([
  { x: 0, y: 0, pressure: 0 },
  { x: 10, y: 5, pressure: 0.5 },
  { x: 20, y: 8, pressure: 0.3 },
])

Options

The options object is optional, as are each of its properties.

Property Type Default Description
size number 8 The base size (diameter) of the stroke.
thinning number .5 The effect of pressure on the stroke's size.
smoothing number .5 How much to soften the stroke's edges.
streamline number .5 How much to streamline the stroke.
simulatePressure boolean true Whether to simulate pressure based on velocity.
easing function t => t An easing function to apply to each point's pressure.
getStroke(myPoints, {
  size: 8,
  thinning: 0.5,
  smoothing: 0.5,
  streamline: 0.5,
  easing: t => t * t * t,
  simulatePressure: true,
})

Tip: To create a stroke with a steady line, set the thinning option to 0.

Tip: To create a stroke that gets thinner with pressure instead of thicker, use a negative number for the thinning option.

Rendering

While getStroke returns an array of points representing a stroke, it's up to you to decide how you will render the stroke. The library does not export any rendering solutions.

For example, the function below will turn a stroke into SVG path data for use with either SVG paths or HTML Canvas (using the Path2D constructor).

// Create SVG path data using the points from perfect-freehand.
function getSvgPathFromStroke(points) {
  if (points.length === 0) return ''

  const d = []

  let [p0, p1] = points

  d.push('M', p0[0], p0[1], 'Q')

  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 = points[i]
  }

  d.push('Z')

  return d.join(' ')
}

To render a stroke as a flat polygon, add the polygon-clipping package and use the following function together with the getSvgPathFromStroke.

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

import * as React from 'react'
import getStroke from 'perfect-freehand'
import { getSvgPathFromStroke } from './utils'

export default function Example() {
  const [currentMark, setCurrentMark] = React.useState()

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

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

  return (
    <svg
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      style={{ touchAction: 'none' }}
    >
      {currentMark && (
        <path
          d={getSvgPathFromStroke(
            getStroke(currentMark.points, {
              size: 24,
              thinning: 0.75,
              smoothing: 0.5,
              streamline: 0.5,
              simulatePressure: currentMark.type !== 'pen',
            })
          )}
        />
      )}
    </svg>
  )
}

Edit perfect-freehand-example

Advanced Usage

StrokeOptions

A TypeScript type for the options object.

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.

getStrokePoints

const strokePoints = getStrokePoints(rawInputPoints)

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.

getStrokeOutlinePoints

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.

const outlinePoints = getOutlinePoints(strokePoints)

Support

Please open an issue for support.

Discussion

Have an idea or casual question? Visit the discussion page.

Author

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].