UNPKG

@visactor/vrender-core

Version:
371 lines (339 loc) 17.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: !0 }), exports.CustomPath2D = void 0; const bounds_context_1 = require("./bounds-context"), path_1 = require("./segment/curve/path"), path_svg_1 = require("./path-svg"), vutils_1 = require("@visactor/vutils"), enums_1 = require("./enums"), arc_1 = require("./shape/arc"), render_command_list_1 = require("./render-command-list"), segment_1 = require("./segment"); class CustomPath2D extends path_1.CurvePath { constructor(ctx) { super(), this.commandList = [], ctx && (this._ctx = ctx), this._boundsContext = new bounds_context_1.BoundsContext(this.bounds); } get curves() { return this.tryBuildCurves(); } setCtx(ctx) { this._ctx = ctx; } moveTo(x, y) { return this.commandList.push([ path_svg_1.enumCommandMap.M, x, y ]), this._ctx && this._ctx.moveTo(x, y), this; } lineTo(x, y) { return this.commandList.push([ path_svg_1.enumCommandMap.L, x, y ]), this._ctx && this._ctx.lineTo(x, y), this; } quadraticCurveTo(aCPx, aCPy, aX, aY) { return this.commandList.push([ path_svg_1.enumCommandMap.Q, aCPx, aCPy, aX, aY ]), this._ctx && this._ctx.quadraticCurveTo(aCPx, aCPy, aX, aY), this; } bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) { return this.commandList.push([ path_svg_1.enumCommandMap.C, aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ]), this._ctx && this._ctx.bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY), this; } arcTo(aX1, aY1, aX2, aY2, aRadius) { return this.commandList.push([ path_svg_1.enumCommandMap.AT, aX1, aY1, aX2, aY2, aRadius ]), this._ctx && this._ctx.arcTo(aX1, aY1, aX2, aY2, aRadius), this; } ellipse(aX, aY, xRadius, yRadius, aRotation, aStartAngle, aEndAngle, aClockwise) { return this.commandList.push([ path_svg_1.enumCommandMap.E, aX, aY, xRadius, yRadius, aRotation, aStartAngle, aEndAngle, aClockwise ]), this._ctx && this._ctx.ellipse(aX, aY, xRadius, yRadius, aRotation, aStartAngle, aEndAngle, aClockwise), this; } rect(x, y, w, h) { return this.commandList.push([ path_svg_1.enumCommandMap.R, x, y, w, h ]), this._ctx && this._ctx.rect(x, y, w, h), this; } arc(x, y, radius, startAngle, endAngle, counterclockwise) { return this.commandList.push([ path_svg_1.enumCommandMap.A, x, y, radius, startAngle, endAngle, counterclockwise ]), this._ctx && this._ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise), this; } closePath() { return this.commandList.push([ path_svg_1.enumCommandMap.Z ]), this._ctx && this._ctx.closePath(), this; } addCurve(curve) { this._curves.push(curve); } clear() { this.transformCbList = null, this.commandList.length = 0, this._curves.length = 0; } beginPath() { this.clear(); } tryBuildCurves() { if (!this._curves || !this._curves.length) { const curveContext = new segment_1.CurveContext(this); (0, render_command_list_1.renderCommandList)(this.commandList, curveContext, 0, 0, 1, 1); } return this._curves; } toString() { if (!this.toStringCbList) { const list = []; list[path_svg_1.enumCommandMap.M] = cmd => `M${cmd[1]} ${cmd[2]}`, list[path_svg_1.enumCommandMap.L] = cmd => `L${cmd[1]} ${cmd[2]}`, list[path_svg_1.enumCommandMap.Q] = cmd => `Q${cmd[1]} ${cmd[2]} ${cmd[3]} ${cmd[4]}`, list[path_svg_1.enumCommandMap.C] = cmd => `C${cmd[1]} ${cmd[2]} ${cmd[3]} ${cmd[4]} ${cmd[5]} ${cmd[6]}`, list[path_svg_1.enumCommandMap.A] = cmd => { const bezierPathList = []; (0, arc_1.addArcToBezierPath)(bezierPathList, cmd[4], cmd[5], cmd[1], cmd[2], cmd[3], cmd[3]); let path = ""; for (let i = 0; i < bezierPathList.length; i += 6) path += `C${bezierPathList[i]} ${bezierPathList[i + 1]} ${bezierPathList[i + 2]} ${bezierPathList[i + 3]} ${bezierPathList[i + 4]} ${bezierPathList[i + 5]}`; return path; }, list[path_svg_1.enumCommandMap.R] = cmd => `M${cmd[1]} ${cmd[2]} h${cmd[3]} v${cmd[4]} H${cmd[1]}Z`, list[path_svg_1.enumCommandMap.Z] = cmd => "Z", this.toStringCbList = list; } const list = this.toStringCbList; let path = ""; return this.commandList.forEach((c => { path += list[c[0]](c); })), path; } fromString(str, x, y, sX, sY) { this.clear(); const commandStrList = (0, path_svg_1.parseSvgPath)(str); return this._runCommandStrList(commandStrList, x, y, sX, sY), this._updateBounds(), this; } fromLine(line) { const {points: points, curveType: curveType, clipRangeByDimension: clipRangeByDimension} = line.attribute; if (!points) return; const cache = (0, segment_1.calcLineCache)(points, curveType); "x" === clipRangeByDimension ? this.direction = enums_1.Direction.ROW : "y" === clipRangeByDimension ? this.direction = enums_1.Direction.COLUMN : "auto" === clipRangeByDimension && (this.direction = cache.direction), this._curves = cache.curves; } fromCustomPath2D(path, x, y, sX, sY) { return this.clear(), this._runCommandList(path.commandList, x, y, sX, sY), this._updateBounds(), this; } transform(x, y, sx, sy) { const commandList = this.commandList; if (!this.transformCbList) { const list = []; list[path_svg_1.enumCommandMap.M] = this.moveToTransform, list[path_svg_1.enumCommandMap.L] = this.lineToTransform, list[path_svg_1.enumCommandMap.Q] = this.quadraticCurveToTransform, list[path_svg_1.enumCommandMap.C] = this.bezierCurveToTransform, list[path_svg_1.enumCommandMap.AT] = this.arcToTransform, list[path_svg_1.enumCommandMap.E] = this.ellipseTransform, list[path_svg_1.enumCommandMap.R] = this.rectTransform, list[path_svg_1.enumCommandMap.A] = this.arcTransform, list[path_svg_1.enumCommandMap.Z] = this.closePathTransform, this.transformCbList = list; } commandList.forEach((cmd => { this.transformCbList[cmd[0]](cmd, x, y, sx, sy); })), this._updateBounds(); } moveToTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y; } lineToTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y; } quadraticCurveToTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y, cmd[3] = cmd[3] * sx + x, cmd[4] = cmd[4] * sy + y; } bezierCurveToTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y, cmd[3] = cmd[3] * sx + x, cmd[4] = cmd[4] * sy + y, cmd[5] = cmd[5] * sx + x, cmd[6] = cmd[6] * sy + y; } arcToTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y, cmd[3] = cmd[3] * sx + x, cmd[4] = cmd[4] * sy + y, cmd[5] = cmd[5] * (sx + sy) / 2; } ellipseTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y, cmd[3] = cmd[3] * sx, cmd[4] = cmd[4] * sy; } rectTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y, cmd[3] = cmd[3] * sx, cmd[4] = cmd[4] * sy; } arcTransform(cmd, x, y, sx, sy) { cmd[1] = cmd[1] * sx + x, cmd[2] = cmd[2] * sy + y, cmd[3] = cmd[3] * (sx + sy) / 2; } closePathTransform() {} _runCommandStrList(commandStrList, l = 0, t = 0, sX = 1, sY = 1) { let current, tempX, tempY, tempControlX, tempControlY, previous = null, x = 0, y = 0, controlX = 0, controlY = 0; for (let i = 0, len = commandStrList.length; i < len; ++i) { switch (current = commandStrList[i], 1 === sX && 1 === sY || (current = scale(current, sX, sY)), current[0]) { case "l": x += current[1], y += current[2], this.lineTo(x + l, y + t); break; case "L": x = current[1], y = current[2], this.lineTo(x + l, y + t); break; case "h": x += current[1], this.lineTo(x + l, y + t); break; case "H": x = current[1], this.lineTo(x + l, y + t); break; case "v": y += current[1], this.lineTo(x + l, y + t); break; case "V": y = current[1], this.lineTo(x + l, y + t); break; case "m": x += current[1], y += current[2], this.moveTo(x + l, y + t); break; case "M": x = current[1], y = current[2], this.moveTo(x + l, y + t); break; case "c": tempX = x + current[5], tempY = y + current[6], controlX = x + current[3], controlY = y + current[4], this.bezierCurveTo(x + current[1] + l, y + current[2] + t, controlX + l, controlY + t, tempX + l, tempY + t), x = tempX, y = tempY; break; case "C": x = current[5], y = current[6], controlX = current[3], controlY = current[4], this.bezierCurveTo(current[1] + l, current[2] + t, controlX + l, controlY + t, x + l, y + t); break; case "s": tempX = x + current[3], tempY = y + current[4], null === previous[0].match(/[CcSs]/) ? (controlX = x, controlY = y) : (controlX = 2 * x - controlX, controlY = 2 * y - controlY), tempControlX = x + current[1], tempControlY = y + current[2], this.bezierCurveTo(controlX + l, controlY + t, tempControlX + l, tempControlY + t, tempX + l, tempY + t), controlX = tempControlX, controlY = tempControlY, x = tempX, y = tempY; break; case "S": tempX = current[3], tempY = current[4], null === previous[0].match(/[CcSs]/) ? (controlX = x, controlY = y) : (controlX = 2 * x - controlX, controlY = 2 * y - controlY), tempControlX = current[1], tempControlY = current[2], this.bezierCurveTo(controlX + l, controlY + t, tempControlX + l, tempControlY + t, tempX + l, tempY + t), controlX = tempControlX, controlY = tempControlY, x = tempX, y = tempY; break; case "q": tempX = x + current[3], tempY = y + current[4], controlX = x + current[1], controlY = y + current[2], this.quadraticCurveTo(controlX + l, controlY + t, tempX + l, tempY + t), x = tempX, y = tempY; break; case "Q": tempX = current[3], tempY = current[4], this.quadraticCurveTo(current[1] + l, current[2] + t, tempX + l, tempY + t), x = tempX, y = tempY, controlX = current[1], controlY = current[2]; break; case "t": tempX = x + current[1], tempY = y + current[2], null === previous[0].match(/[QqTt]/) ? (controlX = x, controlY = y) : "t" === previous[0] ? (controlX = 2 * x - tempControlX, controlY = 2 * y - tempControlY) : "q" === previous[0] && (controlX = 2 * x - controlX, controlY = 2 * y - controlY), tempControlX = controlX, tempControlY = controlY, this.quadraticCurveTo(controlX + l, controlY + t, tempX + l, tempY + t), x = tempX, y = tempY, controlX = x + current[1], controlY = y + current[2]; break; case "T": tempX = current[1], tempY = current[2], controlX = 2 * x - controlX, controlY = 2 * y - controlY, this.quadraticCurveTo(controlX + l, controlY + t, tempX + l, tempY + t), x = tempX, y = tempY; break; case "a": (0, arc_1.drawArc)(this, x + l, y + t, [ current[1], current[2], current[3], current[4], current[5], current[6] + x + l, current[7] + y + t ]), x += current[6], y += current[7]; break; case "A": (0, arc_1.drawArc)(this, x + l, y + t, [ current[1], current[2], current[3], current[4], current[5], current[6] + l, current[7] + t ]), x = current[6], y = current[7]; break; case "z": case "Z": this.closePath(); } previous = current; } } _runCommandList(commandList, l = 0, t = 0, sX = 1, sY = 1) { if (0 !== l || 0 !== t || 1 !== sX || 1 !== sY) for (let i = 0, len = commandList.length; i < len; ++i) { const current = commandList[i].slice(); switch (current[0]) { case path_svg_1.enumCommandMap.L: this.lineToTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.M: this.moveToTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.C: this.bezierCurveToTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.Q: this.quadraticCurveToTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.A: this.arcToTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.E: this.ellipseTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.R: this.rectTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.AT: this.arcToTransform(current, l, t, sX, sY); break; case path_svg_1.enumCommandMap.Z: this.closePath(); } } else this.commandList = commandList.map((entry => entry.slice())); } _updateBounds() { this.bounds.clear(), (0, render_command_list_1.renderCommandList)(this.commandList, this._boundsContext); } release() { this.commandList = [], this._boundsContext = null, this._ctx = null; } getLength() { if (this.direction === enums_1.Direction.COLUMN) { if (!this._curves.length) return 0; const sc = this._curves[0], ec = this._curves[this._curves.length - 1]; return (0, vutils_1.abs)(sc.p0.y - ec.p1.y); } if (this.direction === enums_1.Direction.ROW) { if (!this._curves.length) return 0; const sc = this._curves[0], ec = this._curves[this._curves.length - 1]; return (0, vutils_1.abs)(sc.p0.x - ec.p1.x); } return this._curves.reduce(((l, c) => l + c.getLength()), 0); } getYAt(x) { if (!this.curves) return 1 / 0; for (let i = 0; i < this.curves.length; i++) { const curve = this.curves[i]; if (curve.includeX(x)) return curve.getYAt(x); } return 1 / 0; } getAttrAt(distance) { if (!this._curves) return { pos: { x: 0, y: 0 }, angle: 0 }; let curve, _dis = 0; for (let i = 0; i < this._curves.length; i++) { curve = this._curves[i]; const cl = curve.getLength(this.direction); if (_dis + cl >= distance) break; _dis += cl; } const t = (distance - _dis) / curve.getLength(this.direction); return { pos: curve.getPointAt(t), angle: curve.getAngleAt(t) }; } drawWithClipRange(ctx, size, x, y, clipRange) { this.tryBuildCurves(); const totalLen = this.getLength() * clipRange; let currLen = 0; for (let i = 0; i < this._curves.length; i++) { const curve = this._curves[i], cl = curve.getLength(this.direction); if (!(currLen + cl <= totalLen)) { const percent = 1 - (currLen + cl - totalLen) / cl; curve.draw(ctx, x, y, size, size, percent); break; } curve.draw(ctx, x, y, size, size, 1), currLen += cl; } } } exports.CustomPath2D = CustomPath2D; const temp = [ "l", 0, 0, 0, 0, 0, 0, 0 ]; function scale(current, sX, sY) { const c = temp[0] = current[0]; if ("a" === c || "A" === c) temp[1] = sX * current[1], temp[2] = sY * current[2], temp[3] = current[3], temp[4] = current[4], temp[5] = current[5], temp[6] = sX * current[6], temp[7] = sY * current[7]; else if ("h" === c || "H" === c) temp[1] = sX * current[1]; else if ("v" === c || "V" === c) temp[1] = sY * current[1]; else for (let i = 1, n = current.length; i < n; ++i) temp[i] = (i % 2 == 1 ? sX : sY) * current[i]; return temp; } //# sourceMappingURL=custom-path2d.js.map