1 | ;
|
2 | var __extends = (this && this.__extends) || (function () {
|
3 | var extendStatics = Object.setPrototypeOf ||
|
4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
6 | return function (d, b) {
|
7 | extendStatics(d, b);
|
8 | function __() { this.constructor = d; }
|
9 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
10 | };
|
11 | })();
|
12 | Object.defineProperty(exports, "__esModule", { value: true });
|
13 | //import * as createSVGPathCalculator from "point-at-length";
|
14 | var createSVGPathCalculator = require("point-at-length");
|
15 | var svg_points_1 = require("svg-points");
|
16 | var SVGPointElement = /** @class */ (function () {
|
17 | function SVGPointElement(x, y) {
|
18 | this.x = x;
|
19 | this.y = y;
|
20 | }
|
21 | return SVGPointElement;
|
22 | }());
|
23 | exports.SVGPointElement = SVGPointElement;
|
24 | var SVGPathSegment = /** @class */ (function () {
|
25 | function SVGPathSegment(type, values) {
|
26 | this.type = type;
|
27 | this.values = values;
|
28 | }
|
29 | return SVGPathSegment;
|
30 | }());
|
31 | exports.SVGPathSegment = SVGPathSegment;
|
32 | var SVGPath = /** @class */ (function () {
|
33 | function SVGPath(points, getPathDataFromPoints) {
|
34 | var _this = this;
|
35 | this.getPathStringFromPathData = function (pathData) {
|
36 | return pathData
|
37 | .map(function (pathSegment) {
|
38 | return pathSegment.type + pathSegment.values.join(",");
|
39 | })
|
40 | .join("");
|
41 | };
|
42 | this.getPointAtLength = function (length) {
|
43 | var _a = _this.pathCalculator.at(length), x = _a[0], y = _a[1];
|
44 | return new SVGPointElement(x, y);
|
45 | };
|
46 | this.getTotalLength = function () {
|
47 | return _this.pathCalculator.length();
|
48 | };
|
49 | this.getPathData = function (settings) {
|
50 | return _this.pathData;
|
51 | };
|
52 | this.setPathData = function (pathData) {
|
53 | _this.pathData = pathData;
|
54 | _this.d = _this.getPathStringFromPathData(_this.pathData);
|
55 | _this.pathCalculator = createSVGPathCalculator(_this.d);
|
56 | };
|
57 | this.getPointAtPosition = function (position) {
|
58 | var totalLength = _this.getTotalLength();
|
59 | return _this.getPointAtLength(position * totalLength);
|
60 | };
|
61 | this.getPathDataFromPoints = getPathDataFromPoints;
|
62 | this.pathData = getPathDataFromPoints(points);
|
63 | this.d = this.getPathStringFromPathData(this.pathData);
|
64 | this.points = svg_points_1.toPoints({
|
65 | type: "path",
|
66 | d: this.d
|
67 | });
|
68 | this.pathCalculator = createSVGPathCalculator(this.d);
|
69 | }
|
70 | return SVGPath;
|
71 | }());
|
72 | exports.SVGPath = SVGPath;
|
73 | // Returns the dot product of the given four-element vectors.
|
74 | function d3_svg_lineDot4(a, b) {
|
75 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
76 | }
|
77 | var StraightLine = /** @class */ (function (_super) {
|
78 | __extends(StraightLine, _super);
|
79 | function StraightLine(points) {
|
80 | return _super.call(this, points, function getPathDataFromPoints(points) {
|
81 | var _a = points[0], x0 = _a.x, y0 = _a.y;
|
82 | var _b = points[points.length - 1], x1 = _b.x, y1 = _b.y;
|
83 | return [
|
84 | new SVGPathSegment("M", [x0, y0]),
|
85 | new SVGPathSegment("L", [x1, y1])
|
86 | ];
|
87 | }) || this;
|
88 | }
|
89 | return StraightLine;
|
90 | }(SVGPath));
|
91 | exports.StraightLine = StraightLine;
|
92 | // Matrix to transform basis (b-spline) control points to bezier
|
93 | // control points. Derived from FvD 11.2.8.
|
94 | var d3_svg_lineBasisBezier1 = [0, 2 / 3, 1 / 3, 0];
|
95 | var d3_svg_lineBasisBezier2 = [0, 1 / 3, 2 / 3, 0];
|
96 | var d3_svg_lineBasisBezier3 = [0, 1 / 6, 2 / 3, 1 / 6];
|
97 | // Pushes a "C" Bézier curve onto the specified path array, given the
|
98 | // two specified four-element arrays which define the control points.
|
99 | function lineBasisBezier(pathData, x, y) {
|
100 | var pointsForBezier = [];
|
101 | pointsForBezier.push([
|
102 | d3_svg_lineDot4(d3_svg_lineBasisBezier1, x),
|
103 | d3_svg_lineDot4(d3_svg_lineBasisBezier1, y)
|
104 | ]);
|
105 | pointsForBezier.push([
|
106 | d3_svg_lineDot4(d3_svg_lineBasisBezier2, x),
|
107 | d3_svg_lineDot4(d3_svg_lineBasisBezier2, y)
|
108 | ]);
|
109 | pointsForBezier.push([
|
110 | d3_svg_lineDot4(d3_svg_lineBasisBezier3, x),
|
111 | d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)
|
112 | ]);
|
113 | pathData.push(new SVGPathSegment("C", pointsForBezier));
|
114 | }
|
115 | function changeDirection(currentDirection) {
|
116 | var xDirection = Math.abs(Math.abs(currentDirection[0]) - 1);
|
117 | var yDirection = Math.abs(Math.abs(currentDirection[1]) - 1);
|
118 | return [xDirection, yDirection];
|
119 | }
|
120 | var CurvedLine = /** @class */ (function (_super) {
|
121 | __extends(CurvedLine, _super);
|
122 | function CurvedLine(points, markerStart, markerEnd) {
|
123 | var _this = _super.call(this, points, function getPathDataFromPoints(elbowPoints, markerStart, markerEnd) {
|
124 | // modified from d3js: https://github.com/mbostock/d3/blob/ed54503fc7781d8bfe9e9fe125b76b9bbb5ac05c/src/svg/line.js
|
125 | // TODO this code is kind of hacky. it seems to work OK, but it's probably confusing and should be refactored for readability/maintainability.
|
126 | var elbowPointCount = elbowPoints.length;
|
127 | var firstPoint = elbowPoints[0];
|
128 | var lastPoint = elbowPoints[elbowPointCount - 1];
|
129 | var points = [];
|
130 | points.push(firstPoint);
|
131 | var lastSegment = [];
|
132 | var pathData = [new SVGPathSegment("M", [firstPoint.x, firstPoint.y])];
|
133 | var direction = [];
|
134 | if (firstPoint.orientation) {
|
135 | var orientation_1 = firstPoint.orientation;
|
136 | direction.push(orientation_1[0]);
|
137 | direction.push(orientation_1[1]);
|
138 | }
|
139 | else {
|
140 | console.error("points");
|
141 | console.error(points);
|
142 | throw new Error("No orientation specified for curvedline edge w/ points logged above");
|
143 | }
|
144 | // for curves, I'm calculating and using the points representing the elbow vertices, from the given points (which represent the first point, any elbow segment mid-points and the last point).
|
145 | // I'm making sure the curve passes through the midpoint of the marker side that is furthest away from the node it is attached to
|
146 | // TODO this code might be confusing, because it involves redefining the points. Look at refactoring it for readability.
|
147 | var markerHeightFactor = 0.75;
|
148 | if (!!markerStart &&
|
149 | firstPoint.orientation &&
|
150 | typeof firstPoint.orientation[0] !== "undefined" &&
|
151 | typeof firstPoint.orientation[1] !== "undefined") {
|
152 | var firstPointWithOffset = {};
|
153 | var firstOffset;
|
154 | var firstMarkerData = { x: 0, y: 0, markerWidth: 12, markerHeight: 12 };
|
155 | if (!!firstMarkerData) {
|
156 | firstOffset = markerHeightFactor * firstMarkerData.markerHeight;
|
157 | }
|
158 | else {
|
159 | firstOffset = 12;
|
160 | }
|
161 | firstPointWithOffset.x =
|
162 | firstPoint.orientation[0] * firstOffset + firstPoint.x;
|
163 | firstPointWithOffset.y =
|
164 | firstPoint.orientation[1] * firstOffset + firstPoint.y;
|
165 | pathData.push(new SVGPathSegment("L", [
|
166 | firstPointWithOffset.x,
|
167 | firstPointWithOffset.y
|
168 | ]));
|
169 | points[0] = firstPointWithOffset;
|
170 | }
|
171 | if (!!markerEnd &&
|
172 | lastPoint.orientation &&
|
173 | typeof lastPoint.orientation[0] !== "undefined" &&
|
174 | typeof lastPoint.orientation[1] !== "undefined") {
|
175 | lastSegment.push(new SVGPathSegment("L", [lastPoint.x, lastPoint.y]));
|
176 | var lastPointWithOffset = {};
|
177 | var lastOffset;
|
178 | var lastMarkerData = { x: 0, y: 0, markerWidth: 12, markerHeight: 12 };
|
179 | if (!!lastMarkerData) {
|
180 | lastOffset = markerHeightFactor * lastMarkerData.markerHeight;
|
181 | }
|
182 | else {
|
183 | lastOffset = 12;
|
184 | }
|
185 | lastPointWithOffset.x =
|
186 | lastPoint.orientation[0] * lastOffset + lastPoint.x;
|
187 | lastPointWithOffset.y =
|
188 | lastPoint.orientation[1] * lastOffset + lastPoint.y;
|
189 | elbowPoints[elbowPointCount - 1] = lastPoint = lastPointWithOffset;
|
190 | }
|
191 | elbowPoints.forEach(function (elbowPoint, index) {
|
192 | var x0, y0, x1, y1;
|
193 | if (index > 0 && index < elbowPointCount) {
|
194 | x0 =
|
195 | Math.abs(direction[0]) *
|
196 | (elbowPoints[index].x - elbowPoints[index - 1].x) +
|
197 | elbowPoints[index - 1].x;
|
198 | y0 =
|
199 | Math.abs(direction[1]) *
|
200 | (elbowPoints[index].y - elbowPoints[index - 1].y) +
|
201 | elbowPoints[index - 1].y;
|
202 | points.push({ x: x0, y: y0 });
|
203 | direction = changeDirection(direction);
|
204 | }
|
205 | });
|
206 | points.push(lastPoint);
|
207 | var i = 1, n = points.length, pi = points[0], x0 = pi.x, y0 = pi.y, px = [x0, x0, x0, (pi = points[1]).x], py = [y0, y0, y0, pi.y];
|
208 | pathData.push(new SVGPathSegment("L", [
|
209 | d3_svg_lineDot4(d3_svg_lineBasisBezier3, px),
|
210 | d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)
|
211 | ]));
|
212 | points.push(points[n - 1]);
|
213 | while (++i <= n) {
|
214 | pi = points[i];
|
215 | px.shift();
|
216 | px.push(pi.x);
|
217 | py.shift();
|
218 | py.push(pi.y);
|
219 | lineBasisBezier(pathData, px, py);
|
220 | }
|
221 | points.pop();
|
222 | pathData.push(new SVGPathSegment("L", [pi.x, pi.y]));
|
223 | pathData = pathData.concat(lastSegment);
|
224 | return pathData;
|
225 | }) || this;
|
226 | _this.pathData = _this.getPathDataFromPoints(points, markerStart, markerEnd);
|
227 | _this.d = _this.getPathStringFromPathData(_this.pathData);
|
228 | return _this;
|
229 | }
|
230 | return CurvedLine;
|
231 | }(SVGPath));
|
232 | exports.CurvedLine = CurvedLine;
|
233 | var ElbowLine = /** @class */ (function (_super) {
|
234 | __extends(ElbowLine, _super);
|
235 | function ElbowLine(points) {
|
236 | return _super.call(this, points, function getPathDataFromPoints(points) {
|
237 | function changeDirection(currentDirection) {
|
238 | var xDirection = Math.abs(Math.abs(currentDirection[0]) - 1);
|
239 | var yDirection = Math.abs(Math.abs(currentDirection[1]) - 1);
|
240 | return [xDirection, yDirection];
|
241 | }
|
242 | var pointCount = points.length;
|
243 | var firstPoint = points[0], lastPoint = points[pointCount - 1];
|
244 | var pathData = [new SVGPathSegment("M", [firstPoint.x, firstPoint.y])];
|
245 | var direction = [];
|
246 | if (firstPoint.orientation) {
|
247 | direction.push(firstPoint.orientation[0]);
|
248 | direction.push(firstPoint.orientation[1]);
|
249 | }
|
250 | else {
|
251 | console.error("points");
|
252 | console.error(points);
|
253 | throw new Error("No orientation specified for elbowline edge w/ points logged above");
|
254 | }
|
255 | points.forEach(function (point, index) {
|
256 | if (index > 0 && index < pointCount) {
|
257 | var x0 = Math.abs(direction[0]) * (points[index].x - points[index - 1].x) +
|
258 | points[index - 1].x, y0 = Math.abs(direction[1]) * (points[index].y - points[index - 1].y) +
|
259 | points[index - 1].y;
|
260 | pathData.push(new SVGPathSegment("L", [x0, y0]));
|
261 | direction = changeDirection(direction);
|
262 | }
|
263 | });
|
264 | pathData.push(new SVGPathSegment("L", [lastPoint.x, lastPoint.y]));
|
265 | return pathData;
|
266 | }) || this;
|
267 | }
|
268 | return ElbowLine;
|
269 | }(SVGPath));
|
270 | exports.ElbowLine = ElbowLine;
|
271 | var SegmentedLine = /** @class */ (function (_super) {
|
272 | __extends(SegmentedLine, _super);
|
273 | function SegmentedLine(points) {
|
274 | return _super.call(this, points, function getPathDataFromPoints(points) {
|
275 | var firstPoint = points[0];
|
276 | var pathData = [new SVGPathSegment("M", [firstPoint.x, firstPoint.y])];
|
277 | points.forEach(function (point, index) {
|
278 | if (index > 0) {
|
279 | pathData.push(new SVGPathSegment("L", [point.x, point.y]));
|
280 | }
|
281 | });
|
282 | return pathData;
|
283 | }) || this;
|
284 | }
|
285 | return SegmentedLine;
|
286 | }(SVGPath));
|
287 | exports.SegmentedLine = SegmentedLine;
|
288 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRnZURyYXdlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZWRnZS9lZGdlRHJhd2Vycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSw2REFBNkQ7QUFDN0QsSUFBTSx1QkFBdUIsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUMzRCx5Q0FBc0M7QUFTdEM7SUFNRSx5QkFBWSxDQUFTLEVBQUUsQ0FBUztRQUM5QixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNYLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2IsQ0FBQztJQUNILHNCQUFDO0FBQUQsQ0FBQyxBQVZELElBVUM7QUFWWSwwQ0FBZTtBQW9DNUI7SUFHRSx3QkFBWSxJQUFxQixFQUFFLE1BQWdCO1FBQ2pELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3ZCLENBQUM7SUFDSCxxQkFBQztBQUFELENBQUMsQUFQRCxJQU9DO0FBUFksd0NBQWM7QUFlM0I7SUFhRSxpQkFBWSxNQUF5QixFQUFFLHFCQUFxQjtRQUE1RCxpQkFTQztRQUNELDhCQUF5QixHQUFHLFVBQUMsUUFBMEI7WUFDckQsTUFBTSxDQUFDLFFBQVE7aUJBQ1osR0FBRyxDQUFDLFVBQVMsV0FBVztnQkFDdkIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDekQsQ0FBQyxDQUFDO2lCQUNELElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNkLENBQUMsQ0FBQztRQUNGLHFCQUFnQixHQUFHLFVBQUMsTUFBYztZQUMxQixJQUFBLG9DQUF1QyxFQUF0QyxTQUFDLEVBQUUsU0FBQyxDQUFtQztZQUM5QyxNQUFNLENBQUMsSUFBSSxlQUFlLENBQUMsQ0FBQyxFQUFF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 |
\ | No newline at end of file |