diff --git a/src/canvas.js b/src/canvas.js index 0f6cafd462eb7e40bfccf228357fe876c32c3362..a03c9d5bf1afa0ee17ed11beddac9da7829fb19c 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -2,7 +2,7 @@ // Emit input events and receive draw calls seperately - these must be piped // together externally if desired. -import { line, curveLinear } from "d3-shape" +import { line, curveBasis } from "d3-shape" import { canvas } from "./elements.js" @@ -12,22 +12,20 @@ const SVG_URL = "http://www.w3.org/2000/svg" const lineFn = line() .x((d) => d[0]) .y((d) => d[1]) - .curve(curveLinear) + .curve(curveBasis) const pathGroupElems = new Map() -let stroke_colour = "blue" -export let stroke_radius = 1 -export const MIN_STROKE_RADIUS = 0.1 -export const MAX_STROKE_RADIUS = 3.9 +let strokeColour = "blue" +let strokeRadius = 5 const MAX_POINT_DISTANCE = 5 -const MAX_PRESSURE_DELTA = 0.05 +const MAX_RADIUS_DELTA = 0.05 // Interpolate a path so that: // - The distance between two adjacent points is capped at MAX_POINT_DISTANCE. -// - The pressure delta between two adjacent points is capped at -// MAX_PRESSURE_DELTA +// - The radius delta between two adjacent points is capped at +// MAX_RADIUS_DELTA // If paths are too choppy, try decreasing these constants. const smoothPath = ([...path]) => { // Apply MAX_POINT_DISTANCE. @@ -51,13 +49,12 @@ const smoothPath = ([...path]) => { i += newPoints.length } - // Apply MAX_PRESSURE_DELTA. + // Apply MAX_RADIUS_DELTA. for (let i = 1; i < path.length; i++) { const dx = path[i][0] - path[i - 1][0] const dy = path[i][1] - path[i - 1][1] const dw = path[i][2] - path[i - 1][2] - const normdw = dw / Math.max(0.05, Math.max(path[i][2], path[i - 1][2])) - const segmentsToSplit = Math.ceil(normdw / MAX_PRESSURE_DELTA) + const segmentsToSplit = Math.ceil(dw / MAX_RADIUS_DELTA) const newPoints = [] for (let j = 1; j < segmentsToSplit; j++) { newPoints.push([ @@ -173,24 +170,36 @@ canvas.addEventListener("pointermove", dispatchPointerEvent("strokemove")) canvas.addEventListener("touchmove", (e) => e.preventDefault()) export function setStrokeColour(colour) { - stroke_colour = colour + strokeColour = colour } export function getStrokeColour() { - return stroke_colour + return strokeColour } -export function setStrokeRadius(radius) { - stroke_radius = radius +const MIN_PRESSURE_FACTOR = 0.1 +const MAX_PRESSURE_FACTOR = 1.5 + +// This is a quadratic such that: +// - getPressureFactor(0.0) = MIN_PRESSURE_FACTOR +// - getPressureFactor(0.5) = 1.0 +// - getPressureFactor(1.0) = MAX_PRESSURE_FACTOR +// For sensible results, maintain that: +// - 0.0 <= MIN_PRESSURE_FACTOR <= 1.0 +// - 1.0 <= MAX_PRESSURE_FACTOR +// For intuitive results, maintain that: +// - MAX_PRESSURE_FACTOR <= ~2.0 +const getPressureFactor = (pressure) => { + const a = 2 * (MAX_PRESSURE_FACTOR + MIN_PRESSURE_FACTOR) - 4 + const b = -MAX_PRESSURE_FACTOR - 3 * MIN_PRESSURE_FACTOR + 4 + const c = MIN_PRESSURE_FACTOR + return a * pressure ** 2 + b * pressure + c } -const calculateStrokeRadius = (pressure, radius) => { - return ( - MIN_STROKE_RADIUS + - (radius + pressure) * (MAX_STROKE_RADIUS - MIN_STROKE_RADIUS) - ) +export function getStrokeRadius(pressure) { + return strokeRadius * getPressureFactor(pressure) } -export function getStrokeRadius(pressure) { - return calculateStrokeRadius(pressure, stroke_radius) +export function setStrokeRadius(radius) { + strokeRadius = radius }