UNPKG

@remotion/paths

Version:

Utilities for working with SVG paths

392 lines (391 loc) 15.1 kB
"use strict"; // Copied from: https://github.com/rveciana/svg-path-properties Object.defineProperty(exports, "__esModule", { value: true }); exports.construct = exports.constructFromInstructions = void 0; const parse_path_1 = require("../parse-path"); const arc_1 = require("./arc"); const bezier_1 = require("./bezier"); const linear_1 = require("./linear"); const constructFromInstructions = (instructions) => { let totalLength = 0; const partialLengths = []; const functions = []; let initialPoint = null; let cur = [0, 0]; let prev_point = [0, 0]; let curve; let ringStart = [0, 0]; const segments = []; for (let i = 0; i < instructions.length; i++) { const instruction = instructions[i]; if (instruction.type !== 'm' && instruction.type !== 'M' && segments.length > 0) { segments[segments.length - 1].push(instruction); } // moveTo if (instruction.type === 'M') { cur = [instruction.x, instruction.y]; ringStart = [cur[0], cur[1]]; segments.push([instruction]); functions.push(null); if (i === 0) { initialPoint = { x: instruction.x, y: instruction.y }; } } if (instruction.type === 'm') { cur = [instruction.dx + cur[0], instruction.dy + cur[1]]; ringStart = [cur[0], cur[1]]; segments.push([{ type: 'M', x: cur[0], y: cur[1] }]); functions.push(null); // lineTo } if (instruction.type === 'L') { totalLength += Math.sqrt((cur[0] - instruction.x) ** 2 + (cur[1] - instruction.y) ** 2); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: instruction.x, y0: cur[1], y1: instruction.y, })); cur = [instruction.x, instruction.y]; } if (instruction.type === 'l') { totalLength += Math.sqrt(instruction.dx ** 2 + instruction.dy ** 2); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: instruction.dx + cur[0], y0: cur[1], y1: instruction.dy + cur[1], })); cur = [instruction.dx + cur[0], instruction.dy + cur[1]]; } if (instruction.type === 'H') { totalLength += Math.abs(cur[0] - instruction.x); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: instruction.x, y0: cur[1], y1: cur[1], })); cur[0] = instruction.x; } if (instruction.type === 'h') { totalLength += Math.abs(instruction.dx); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: cur[0] + instruction.dx, y0: cur[1], y1: cur[1], })); cur[0] = instruction.dx + cur[0]; } else if (instruction.type === 'V') { totalLength += Math.abs(cur[1] - instruction.y); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: cur[0], y0: cur[1], y1: instruction.y, })); cur[1] = instruction.y; } if (instruction.type === 'v') { totalLength += Math.abs(instruction.dy); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: cur[0], y0: cur[1], y1: cur[1] + instruction.dy, })); cur[1] = instruction.dy + cur[1]; // Close path } else if (instruction.type === 'Z') { totalLength += Math.sqrt((ringStart[0] - cur[0]) ** 2 + (ringStart[1] - cur[1]) ** 2); functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: ringStart[0], y0: cur[1], y1: ringStart[1], })); cur = [ringStart[0], ringStart[1]]; // Cubic Bezier curves } if (instruction.type === 'C') { curve = (0, bezier_1.makeCubic)({ startX: cur[0], startY: cur[1], cp1x: instruction.cp1x, cp1y: instruction.cp1y, cp2x: instruction.cp2x, cp2y: instruction.cp2y, x: instruction.x, y: instruction.y, }); totalLength += curve.getTotalLength(); cur = [instruction.x, instruction.y]; functions.push(curve); } else if (instruction.type === 'c') { curve = (0, bezier_1.makeCubic)({ startX: cur[0], startY: cur[1], cp1x: cur[0] + instruction.cp1dx, cp1y: cur[1] + instruction.cp1dy, cp2x: cur[0] + instruction.cp2dx, cp2y: cur[1] + instruction.cp2dy, x: cur[0] + instruction.dx, y: cur[1] + instruction.dy, }); if (curve.getTotalLength() > 0) { totalLength += curve.getTotalLength(); functions.push(curve); cur = [instruction.dx + cur[0], instruction.dy + cur[1]]; } else { functions.push((0, linear_1.makeLinearPosition)({ x0: cur[0], x1: cur[0], y0: cur[1], y1: cur[1] })); } } if (instruction.type === 'S') { const prev = instructions[i - 1]; const prevWasCurve = prev.type === 'C' || prev.type === 'c' || prev.type === 'S' || prev.type === 's'; if (i > 0 && prevWasCurve) { if (curve) { const c = curve.getC(); curve = (0, bezier_1.makeCubic)({ startX: cur[0], startY: cur[1], cp1x: 2 * cur[0] - c.x, cp1y: 2 * cur[1] - c.y, cp2x: instruction.cpx, cp2y: instruction.cpy, x: instruction.x, y: instruction.y, }); } } else { curve = (0, bezier_1.makeCubic)({ startX: cur[0], startY: cur[1], cp1x: cur[0], cp1y: cur[1], cp2x: instruction.cpx, cp2y: instruction.cpy, x: instruction.x, y: instruction.y, }); } if (curve) { totalLength += curve.getTotalLength(); cur = [instruction.x, instruction.y]; functions.push(curve); } } if (instruction.type === 's') { const prev = instructions[i - 1]; const prevWasCurve = prev.type === 'C' || prev.type === 'c' || prev.type === 'S' || prev.type === 's'; if (i > 0 && prevWasCurve) { if (curve) { const c = curve.getC(); const d = curve.getD(); curve = (0, bezier_1.makeCubic)({ startX: cur[0], startY: cur[1], cp1x: cur[0] + d.x - c.x, cp1y: cur[1] + d.y - c.y, cp2x: cur[0] + instruction.cpdx, cp2y: cur[1] + instruction.cpdy, x: cur[0] + instruction.dx, y: cur[1] + instruction.dy, }); } } else { curve = (0, bezier_1.makeCubic)({ startX: cur[0], startY: cur[1], cp1x: cur[0], cp1y: cur[1], cp2x: cur[0] + instruction.cpdx, cp2y: cur[1] + instruction.cpdy, x: cur[0] + instruction.dx, y: cur[1] + instruction.dy, }); } if (curve) { totalLength += curve.getTotalLength(); cur = [instruction.dx + cur[0], instruction.dy + cur[1]]; functions.push(curve); } } // Quadratic Bezier curves if (instruction.type === 'Q') { if (cur[0] === instruction.cpx && cur[1] === instruction.cpy) { const linearCurve = (0, linear_1.makeLinearPosition)({ x0: instruction.cpx, x1: instruction.x, y0: instruction.cpy, y1: instruction.y, }); totalLength += linearCurve.getTotalLength(); functions.push(linearCurve); } else { curve = (0, bezier_1.makeQuadratic)({ startX: cur[0], startY: cur[1], cpx: instruction.cpx, cpy: instruction.cpy, x: instruction.x, y: instruction.y, }); totalLength += curve.getTotalLength(); functions.push(curve); } cur = [instruction.x, instruction.y]; prev_point = [instruction.cpx, instruction.cpy]; } if (instruction.type === 'q') { if (instruction.cpdx === 0 && instruction.cpdy === 0) { const linearCurve = (0, linear_1.makeLinearPosition)({ x0: cur[0] + instruction.cpdx, x1: cur[0] + instruction.cpdy, y0: cur[1] + instruction.dx, y1: cur[1] + instruction.dy, }); totalLength += linearCurve.getTotalLength(); functions.push(linearCurve); } else { curve = (0, bezier_1.makeQuadratic)({ startX: cur[0], startY: cur[1], cpx: cur[0] + instruction.cpdx, cpy: cur[1] + instruction.cpdy, x: cur[0] + instruction.dx, y: cur[1] + instruction.dy, }); totalLength += curve.getTotalLength(); functions.push(curve); } prev_point = [cur[0] + instruction.cpdx, cur[1] + instruction.cpdy]; cur = [instruction.dx + cur[0], instruction.dy + cur[1]]; } if (instruction.type === 'T') { const prev = instructions[i - 1]; const prevWasQ = prev.type === 'Q' || prev.type === 'q' || prev.type === 'T' || prev.type === 't'; if (i > 0 && prevWasQ) { curve = (0, bezier_1.makeQuadratic)({ startX: cur[0], startY: cur[1], cpx: 2 * cur[0] - prev_point[0], cpy: 2 * cur[1] - prev_point[1], x: instruction.x, y: instruction.y, }); functions.push(curve); totalLength += curve.getTotalLength(); } else { const linearCurve = (0, linear_1.makeLinearPosition)({ x0: cur[0], x1: instruction.x, y0: cur[1], y1: instruction.y, }); functions.push(linearCurve); totalLength += linearCurve.getTotalLength(); } prev_point = [2 * cur[0] - prev_point[0], 2 * cur[1] - prev_point[1]]; cur = [instruction.x, instruction.y]; } if (instruction.type === 't') { const prev = instructions[i - 1]; const prevWasQ = prev.type === 'Q' || prev.type === 'q' || prev.type === 'T' || prev.type === 't'; if (i > 0 && prevWasQ) { curve = (0, bezier_1.makeQuadratic)({ startX: cur[0], startY: cur[1], cpx: 2 * cur[0] - prev_point[0], cpy: 2 * cur[1] - prev_point[1], x: cur[0] + instruction.dx, y: cur[1] + instruction.dy, }); totalLength += curve.getTotalLength(); functions.push(curve); } else { const linearCurve = (0, linear_1.makeLinearPosition)({ x0: cur[0], x1: cur[0] + instruction.dx, y0: cur[1], y1: cur[1] + instruction.dy, }); totalLength += linearCurve.getTotalLength(); functions.push(linearCurve); } prev_point = [2 * cur[0] - prev_point[0], 2 * cur[1] - prev_point[1]]; cur = [instruction.dx + cur[0], instruction.dy + cur[1]]; } if (instruction.type === 'A') { const arcCurve = (0, arc_1.makeArc)({ x0: cur[0], y0: cur[1], rx: instruction.rx, ry: instruction.ry, xAxisRotate: instruction.xAxisRotation, LargeArcFlag: instruction.largeArcFlag, SweepFlag: instruction.sweepFlag, x1: instruction.x, y1: instruction.y, }); totalLength += arcCurve.getTotalLength(); cur = [instruction.x, instruction.y]; functions.push(arcCurve); } if (instruction.type === 'a') { const arcCurve = (0, arc_1.makeArc)({ x0: cur[0], y0: cur[1], rx: instruction.rx, ry: instruction.ry, xAxisRotate: instruction.xAxisRotation, LargeArcFlag: instruction.largeArcFlag, SweepFlag: instruction.sweepFlag, x1: cur[0] + instruction.dx, y1: cur[1] + instruction.dy, }); totalLength += arcCurve.getTotalLength(); cur = [cur[0] + instruction.dx, cur[1] + instruction.dy]; functions.push(arcCurve); } partialLengths.push(totalLength); } return { segments, initialPoint, totalLength, partialLengths, functions, }; }; exports.constructFromInstructions = constructFromInstructions; const construct = (string) => { const parsed = (0, parse_path_1.parsePath)(string); return (0, exports.constructFromInstructions)(parsed); }; exports.construct = construct;