UNPKG

svg-path-d

Version:

SVG path data (path[d] attribute content) manipulation library.

155 lines 5.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCurveBoundingRect = exports.getQCurveBoundingRect = exports.getLastControlY = exports.getLastControlX = exports.getFirstControlY = exports.getFirstControlX = exports.getReflectedY1 = exports.getReflectedX1 = void 0; var math1d_1 = require("./utils/math1d"); var math2d_1 = require("./utils/math2d"); var command_assertion_1 = require("./command-assertion"); var path_node_1 = require("./path-node"); function isReflectable(node, prev) { return (prev.name === node.name || (command_assertion_1.isCurveTo(prev) && command_assertion_1.isSmoothCurveTo(node)) || (command_assertion_1.isQCurveTo(prev) && command_assertion_1.isSmoothQCurveTo(node))); } /** * The S/s and T/t commands indicate that the first control point of the given cubic/quadratic * Bézier curve is calculated by reflecting the previous path segment's final control point * relative to the current point. * * The exact math is as follows. * If the current point is (curx, cury) * and the final control point of the previous path segment is (oldx2, oldy2), * then the first control point of the current path segment (reflected point) is: * * (newx1, newy1) = (curx - (oldx2 - curx), cury - (oldy2 - cury)) = (2*curx - oldx2, 2*cury - oldy2) */ function getReflectedX1(node) { var prev = node.prev; var x = path_node_1.getX(prev); if (prev && isReflectable(node, prev)) { x += x - getLastControlX(prev); } return x; } exports.getReflectedX1 = getReflectedX1; function getReflectedY1(node) { var prev = node.prev; var y = path_node_1.getY(prev); if (prev && isReflectable(node, prev)) { y += y - getLastControlY(prev); } return y; } exports.getReflectedY1 = getReflectedY1; function getFirstControlX(node) { if (command_assertion_1.hasControlPoint1(node)) { return node.x1; } else { return getReflectedX1(node); } } exports.getFirstControlX = getFirstControlX; function getFirstControlY(node) { if (command_assertion_1.hasControlPoint1(node)) { return node.y1; } else { return getReflectedY1(node); } } exports.getFirstControlY = getFirstControlY; function getLastControlX(node) { if (command_assertion_1.hasControlPoint2(node)) { return node.x2; } else if (command_assertion_1.isQCurveTo(node)) { return node.x1; } else { return getReflectedX1(node); } } exports.getLastControlX = getLastControlX; function getLastControlY(node) { if (command_assertion_1.hasControlPoint2(node)) { return node.y2; } else if (command_assertion_1.isQCurveTo(node)) { return node.y1; } else { return getReflectedY1(node); } } exports.getLastControlY = getLastControlY; function getQCurveBoundingRect(node) { var x0 = path_node_1.getX(node.prev); var y0 = path_node_1.getY(node.prev); var x1 = getFirstControlX(node); var y1 = getFirstControlY(node); var x2 = node.x; var y2 = node.y; var rc = math2d_1.fromPoint(x0, y0); math2d_1.addPoint(rc, x2, y2); if (math2d_1.isPointOut(rc, x1, y1)) { // p(t) = (1 - t)^2 * p0 + 2 * (1 - t) * t * p1 + t^2 * p2, where t is in the range of [0,1] // When the first derivative is 0, the point is the location of a local minimum or maximum. // p'(t) = 2 * (t - 1) * p0 + 2 * (1 - 2 * t) * p1 + 2 * t * p2 // = t * (2 * p0 - 4 * p1 + 2 * p2) + 2 * (p1-p0) // = 0 => // t * (p0 - 2 * p1 + p2) = (p0 - p1) // t = (p0 - p1) / (p0 - 2 * p1 + p2) var tx = math1d_1.clamp((x0 - x1) / (x0 - 2 * x1 + x2) || 0, 0, 1); var px = math1d_1.bezier2(x0, x1, x2, tx); var ty = math1d_1.clamp((y0 - y1) / (y0 - 2 * y1 + y2) || 0, 0, 1); var py = math1d_1.bezier2(y0, y1, y2, ty); math2d_1.addPoint(rc, px, py); } return rc; } exports.getQCurveBoundingRect = getQCurveBoundingRect; function getCurveBoundingRect(node) { var x0 = path_node_1.getX(node.prev); var y0 = path_node_1.getY(node.prev); var x1 = getFirstControlX(node); var y1 = getFirstControlY(node); var x2 = node.x2; var y2 = node.y2; var x3 = node.x; var y3 = node.y; var rc = math2d_1.fromPoint(x0, y0); math2d_1.addPoint(rc, x3, y3); var kx0 = -x0 + x1; var kx1 = x0 - 2 * x1 + x2; var kx2 = -x0 + 3 * x1 - 3 * x2 + x3; var hx = kx1 * kx1 - kx0 * kx2; if (hx > 0) { hx = Math.sqrt(hx); var t = -kx0 / (kx1 + hx); if (t > 0 && t < 1) { math2d_1.addX(rc, math1d_1.bezier3(x0, x1, x2, x3, t)); } t = -kx0 / (kx1 - hx); if (t > 0 && t < 1) { math2d_1.addX(rc, math1d_1.bezier3(x0, x1, x2, x3, t)); } } var ky0 = -y0 + y1; var ky1 = y0 - 2 * y1 + y2; var ky2 = -y0 + 3 * y1 - 3 * y2 + y3; var hy = ky1 * ky1 - ky0 * ky2; if (hy > 0) { hy = Math.sqrt(hy); var t = -ky0 / (ky1 + hy); if (t > 0 && t < 1) { math2d_1.addY(rc, math1d_1.bezier3(y0, y1, y2, y3, t)); } t = -ky0 / (ky1 - hy); if (t > 0 && t < 1) { math2d_1.addY(rc, math1d_1.bezier3(y0, y1, y2, y3, t)); } } return rc; } exports.getCurveBoundingRect = getCurveBoundingRect; //# sourceMappingURL=curve-node.js.map