UNPKG

js-draw

Version:

Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.

129 lines (128 loc) 4.71 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.makePolylineBuilder = void 0; const math_1 = require("@js-draw/math"); const Stroke_1 = __importDefault(require("../Stroke")); const Viewport_1 = __importDefault(require("../../Viewport")); const makeShapeFitAutocorrect_1 = __importDefault(require("./autocorrect/makeShapeFitAutocorrect")); /** * Creates a freehand line builder that creates strokes from line segments * rather than Bézier curves. * * Example: * [[include:doc-pages/inline-examples/changing-pen-types.md]] */ exports.makePolylineBuilder = (0, makeShapeFitAutocorrect_1.default)((initialPoint, viewport) => { // Fit to a value slightly smaller than the pixel size. A larger value can // cause the stroke to appear jagged at some zoom levels. const minFit = viewport.getSizeOfPixelOnCanvas() * 0.65; return new PolylineBuilder(initialPoint, minFit, viewport); }); class PolylineBuilder { constructor(startPoint, minFitAllowed, viewport) { this.minFitAllowed = minFitAllowed; this.viewport = viewport; this.parts = []; this.widthAverageNumSamples = 1; this.lastLineSegment = null; this.averageWidth = startPoint.width; this.startPoint = { ...startPoint, pos: this.roundPoint(startPoint.pos), }; this.lastPoint = this.startPoint.pos; this.bbox = new math_1.Rect2(this.startPoint.pos.x, this.startPoint.pos.y, 0, 0); this.parts = [ { kind: math_1.PathCommandType.MoveTo, point: this.startPoint.pos, }, ]; } getBBox() { return this.bbox.grownBy(this.averageWidth); } getRenderingStyle() { return { fill: math_1.Color4.transparent, stroke: { color: this.startPoint.color, width: this.roundDistance(this.averageWidth), }, }; } previewCurrentPath() { const startPoint = this.startPoint.pos; const commands = [...this.parts]; // TODO: For now, this is necesary for the path to be visible. if (commands.length <= 1) { commands.push({ kind: math_1.PathCommandType.LineTo, point: startPoint.plus(math_1.Vec2.of(this.averageWidth / 4, 0)), }); } return { startPoint, commands, style: this.getRenderingStyle(), }; } previewFullPath() { return [this.previewCurrentPath()]; } preview(renderer) { const paths = this.previewFullPath(); if (paths) { const approxBBox = this.viewport.visibleRect; renderer.startObject(approxBBox); for (const path of paths) { renderer.drawPath(path); } renderer.endObject(); } } build() { return new Stroke_1.default(this.previewFullPath()); } getMinFit() { let minFit = Math.min(this.minFitAllowed, this.averageWidth / 4); if (minFit < 1e-10) { minFit = this.minFitAllowed; } return minFit; } roundPoint(point) { const minFit = this.getMinFit(); return Viewport_1.default.roundPoint(point, minFit); } roundDistance(dist) { const minFit = this.getMinFit(); return Viewport_1.default.roundPoint(dist, minFit); } addPoint(newPoint) { this.widthAverageNumSamples++; this.averageWidth = (this.averageWidth * (this.widthAverageNumSamples - 1)) / this.widthAverageNumSamples + newPoint.width / this.widthAverageNumSamples; const roundedPoint = this.roundPoint(newPoint.pos); if (!roundedPoint.eq(this.lastPoint)) { // If almost exactly in the same line as the previous if (this.lastLineSegment && this.lastLineSegment.direction.dot(roundedPoint.minus(this.lastPoint).normalized()) > 0.997) { this.parts.pop(); this.lastPoint = this.lastLineSegment.p1; } this.parts.push({ kind: math_1.PathCommandType.LineTo, point: this.roundPoint(newPoint.pos), }); this.bbox = this.bbox.grownToPoint(roundedPoint); this.lastLineSegment = new math_1.LineSegment2(this.lastPoint, roundedPoint); this.lastPoint = roundedPoint; } } } exports.default = PolylineBuilder;