@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering.
1,024 lines • 40 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Path = void 0;
var util_1 = require("../util");
var line_1 = require("../line");
var curve_1 = require("../curve");
var polyline_1 = require("../polyline");
var rectangle_1 = require("../rectangle");
var geometry_1 = require("../geometry");
var close_1 = require("./close");
var lineto_1 = require("./lineto");
var moveto_1 = require("./moveto");
var curveto_1 = require("./curveto");
var normalize_1 = require("./normalize");
var Path = /** @class */ (function (_super) {
__extends(Path, _super);
function Path(args) {
var _this = _super.call(this) || this;
_this.PRECISION = 3;
_this.segments = [];
if (Array.isArray(args)) {
if (line_1.Line.isLine(args[0]) || curve_1.Curve.isCurve(args[0])) {
var previousObj_1 = null;
var arr = args;
arr.forEach(function (o, i) {
if (i === 0) {
_this.appendSegment(Path.createSegment('M', o.start));
}
if (previousObj_1 != null && !previousObj_1.end.equals(o.start)) {
_this.appendSegment(Path.createSegment('M', o.start));
}
if (line_1.Line.isLine(o)) {
_this.appendSegment(Path.createSegment('L', o.end));
}
else if (curve_1.Curve.isCurve(o)) {
_this.appendSegment(Path.createSegment('C', o.controlPoint1, o.controlPoint2, o.end));
}
previousObj_1 = o;
});
}
else {
var arr = args;
arr.forEach(function (s) {
if (s.isSegment) {
_this.appendSegment(s);
}
});
}
}
else if (args != null) {
if (line_1.Line.isLine(args)) {
_this.appendSegment(Path.createSegment('M', args.start));
_this.appendSegment(Path.createSegment('L', args.end));
}
else if (curve_1.Curve.isCurve(args)) {
_this.appendSegment(Path.createSegment('M', args.start));
_this.appendSegment(Path.createSegment('C', args.controlPoint1, args.controlPoint2, args.end));
}
else if (polyline_1.Polyline.isPolyline(args)) {
if (args.points && args.points.length) {
args.points.forEach(function (point, index) {
var segment = index === 0
? Path.createSegment('M', point)
: Path.createSegment('L', point);
_this.appendSegment(segment);
});
}
}
else if (args.isSegment) {
_this.appendSegment(args);
}
}
return _this;
}
Object.defineProperty(Path.prototype, Symbol.toStringTag, {
get: function () {
return Path.toStringTag;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Path.prototype, "start", {
get: function () {
var segments = this.segments;
var count = segments.length;
if (count === 0) {
return null;
}
for (var i = 0; i < count; i += 1) {
var segment = segments[i];
if (segment.isVisible) {
return segment.start;
}
}
// if no visible segment, return last segment end point
return segments[count - 1].end;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Path.prototype, "end", {
get: function () {
var segments = this.segments;
var count = segments.length;
if (count === 0) {
return null;
}
for (var i = count - 1; i >= 0; i -= 1) {
var segment = segments[i];
if (segment.isVisible) {
return segment.end;
}
}
// if no visible segment, return last segment end point
return segments[count - 1].end;
},
enumerable: false,
configurable: true
});
Path.prototype.moveTo = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return this.appendSegment((_a = moveto_1.MoveTo.create).call.apply(_a, __spreadArrays([null], args)));
};
Path.prototype.lineTo = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return this.appendSegment((_a = lineto_1.LineTo.create).call.apply(_a, __spreadArrays([null], args)));
};
Path.prototype.curveTo = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return this.appendSegment((_a = curveto_1.CurveTo.create).call.apply(_a, __spreadArrays([null], args)));
};
Path.prototype.close = function () {
return this.appendSegment(close_1.Close.create());
};
Path.prototype.bbox = function () {
var segments = this.segments;
var count = segments.length;
if (count === 0) {
return null;
}
var bbox;
for (var i = 0; i < count; i += 1) {
var segment = segments[i];
if (segment.isVisible) {
var segmentBBox = segment.bbox();
if (segmentBBox != null) {
bbox = bbox ? bbox.union(segmentBBox) : segmentBBox;
}
}
}
if (bbox != null) {
return bbox;
}
// if the path has only invisible elements, return end point of last segment
var lastSegment = segments[count - 1];
return new rectangle_1.Rectangle(lastSegment.end.x, lastSegment.end.y, 0, 0);
};
Path.prototype.appendSegment = function (seg) {
var count = this.segments.length;
var previousSegment = count !== 0 ? this.segments[count - 1] : null;
var currentSegment;
var nextSegment = null;
if (Array.isArray(seg)) {
for (var i = 0, ii = seg.length; i < ii; i += 1) {
var segment = seg[i];
currentSegment = this.prepareSegment(segment, previousSegment, nextSegment);
this.segments.push(currentSegment);
previousSegment = currentSegment;
}
}
else {
if (seg != null && seg.isSegment) {
currentSegment = this.prepareSegment(seg, previousSegment, nextSegment);
this.segments.push(currentSegment);
}
}
return this;
};
Path.prototype.insertSegment = function (index, seg) {
var count = this.segments.length;
if (index < 0) {
index = count + index + 1; // tslint:disable-line
}
if (index > count || index < 0) {
throw new Error('Index out of range.');
}
var currentSegment;
var previousSegment = null;
var nextSegment = null;
if (count !== 0) {
if (index >= 1) {
previousSegment = this.segments[index - 1];
nextSegment = previousSegment.nextSegment;
}
else {
previousSegment = null;
nextSegment = this.segments[0];
}
}
if (!Array.isArray(seg)) {
currentSegment = this.prepareSegment(seg, previousSegment, nextSegment);
this.segments.splice(index, 0, currentSegment);
}
else {
for (var i = 0, ii = seg.length; i < ii; i += 1) {
var segment = seg[i];
currentSegment = this.prepareSegment(segment, previousSegment, nextSegment);
this.segments.splice(index + i, 0, currentSegment);
previousSegment = currentSegment;
}
}
return this;
};
Path.prototype.removeSegment = function (index) {
var idx = this.fixIndex(index);
var removedSegment = this.segments.splice(idx, 1)[0];
var previousSegment = removedSegment.previousSegment;
var nextSegment = removedSegment.nextSegment;
// link the previous and next segments together (if present)
if (previousSegment) {
previousSegment.nextSegment = nextSegment;
}
if (nextSegment) {
nextSegment.previousSegment = previousSegment;
}
if (removedSegment.isSubpathStart && nextSegment) {
this.updateSubpathStartSegment(nextSegment);
}
return removedSegment;
};
Path.prototype.replaceSegment = function (index, seg) {
var idx = this.fixIndex(index);
var currentSegment;
var replacedSegment = this.segments[idx];
var previousSegment = replacedSegment.previousSegment;
var nextSegment = replacedSegment.nextSegment;
var updateSubpathStart = replacedSegment.isSubpathStart;
if (!Array.isArray(seg)) {
currentSegment = this.prepareSegment(seg, previousSegment, nextSegment);
this.segments.splice(idx, 1, currentSegment);
if (updateSubpathStart && currentSegment.isSubpathStart) {
// already updated by `prepareSegment`
updateSubpathStart = false;
}
}
else {
this.segments.splice(index, 1);
for (var i = 0, ii = seg.length; i < ii; i += 1) {
var segment = seg[i];
currentSegment = this.prepareSegment(segment, previousSegment, nextSegment);
this.segments.splice(index + i, 0, currentSegment);
previousSegment = currentSegment;
if (updateSubpathStart && currentSegment.isSubpathStart) {
updateSubpathStart = false;
}
}
}
if (updateSubpathStart && nextSegment) {
this.updateSubpathStartSegment(nextSegment);
}
};
Path.prototype.getSegment = function (index) {
var idx = this.fixIndex(index);
return this.segments[idx];
};
Path.prototype.fixIndex = function (index) {
var length = this.segments.length;
if (length === 0) {
throw new Error('Path has no segments.');
}
var i = index;
while (i < 0) {
i = length + i;
}
if (i >= length || i < 0) {
throw new Error('Index out of range.');
}
return i;
};
Path.prototype.segmentAt = function (ratio, options) {
if (options === void 0) { options = {}; }
var index = this.segmentIndexAt(ratio, options);
if (!index) {
return null;
}
return this.getSegment(index);
};
Path.prototype.segmentAtLength = function (length, options) {
if (options === void 0) { options = {}; }
var index = this.segmentIndexAtLength(length, options);
if (!index)
return null;
return this.getSegment(index);
};
Path.prototype.segmentIndexAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var rate = util_1.clamp(ratio, 0, 1);
var opt = this.getOptions(options);
var len = this.length(opt);
var length = len * rate;
return this.segmentIndexAtLength(length, opt);
};
Path.prototype.segmentIndexAtLength = function (length, options) {
if (options === void 0) { options = {}; }
var count = this.segments.length;
if (count === 0) {
return null;
}
var fromStart = true;
if (length < 0) {
fromStart = false;
length = -length; // tslint:disable-line
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var memo = 0;
var lastVisibleIndex = null;
for (var i = 0; i < count; i += 1) {
var index = fromStart ? i : count - 1 - i;
var segment = this.segments[index];
var subdivisions = segmentSubdivisions[index];
var len = segment.length({ precision: precision, subdivisions: subdivisions });
if (segment.isVisible) {
if (length <= memo + len) {
return index;
}
lastVisibleIndex = index;
}
memo += len;
}
// If length requested is higher than the length of the path, return
// last visible segment index. If no visible segment, return null.
return lastVisibleIndex;
};
Path.prototype.getSegmentSubdivisions = function (options) {
if (options === void 0) { options = {}; }
var precision = this.getPrecision(options);
var segmentSubdivisions = [];
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var segment = this.segments[i];
var subdivisions = segment.getSubdivisions({ precision: precision });
segmentSubdivisions.push(subdivisions);
}
return segmentSubdivisions;
};
Path.prototype.updateSubpathStartSegment = function (segment) {
var previous = segment.previousSegment;
var current = segment;
while (current && !current.isSubpathStart) {
// assign previous segment's subpath start segment to this segment
if (previous != null) {
current.subpathStartSegment = previous.subpathStartSegment;
}
else {
current.subpathStartSegment = null;
}
previous = current;
current = current.nextSegment;
}
};
Path.prototype.prepareSegment = function (segment, previousSegment, nextSegment) {
segment.previousSegment = previousSegment;
segment.nextSegment = nextSegment;
if (previousSegment != null) {
previousSegment.nextSegment = segment;
}
if (nextSegment != null) {
nextSegment.previousSegment = segment;
}
var updateSubpathStart = segment;
if (segment.isSubpathStart) {
// move to
segment.subpathStartSegment = segment;
updateSubpathStart = nextSegment;
}
// assign previous segment's subpath start (or self if it is a subpath start) to subsequent segments
if (updateSubpathStart != null) {
this.updateSubpathStartSegment(updateSubpathStart);
}
return segment;
};
Path.prototype.closestPoint = function (p, options) {
if (options === void 0) { options = {}; }
var t = this.closestPointT(p, options);
if (!t) {
return null;
}
return this.pointAtT(t);
};
Path.prototype.closestPointLength = function (p, options) {
if (options === void 0) { options = {}; }
var opts = this.getOptions(options);
var t = this.closestPointT(p, opts);
if (!t) {
return 0;
}
return this.lengthAtT(t, opts);
};
Path.prototype.closestPointNormalizedLength = function (p, options) {
if (options === void 0) { options = {}; }
var opts = this.getOptions(options);
var cpLength = this.closestPointLength(p, opts);
if (cpLength === 0) {
return 0;
}
var length = this.length(opts);
if (length === 0) {
return 0;
}
return cpLength / length;
};
Path.prototype.closestPointT = function (p, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var closestPointT;
var minSquaredDistance = Infinity;
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var segment = this.segments[i];
var subdivisions = segmentSubdivisions[i];
if (segment.isVisible) {
var segmentClosestPointT = segment.closestPointT(p, {
precision: precision,
subdivisions: subdivisions,
});
var segmentClosestPoint = segment.pointAtT(segmentClosestPointT);
var squaredDistance = util_1.squaredLength(segmentClosestPoint, p);
if (squaredDistance < minSquaredDistance) {
closestPointT = { segmentIndex: i, value: segmentClosestPointT };
minSquaredDistance = squaredDistance;
}
}
}
if (closestPointT) {
return closestPointT;
}
return { segmentIndex: this.segments.length - 1, value: 1 };
};
Path.prototype.closestPointTangent = function (p, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var closestPointTangent;
var minSquaredDistance = Infinity;
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var segment = this.segments[i];
var subdivisions = segmentSubdivisions[i];
if (segment.isDifferentiable()) {
var segmentClosestPointT = segment.closestPointT(p, {
precision: precision,
subdivisions: subdivisions,
});
var segmentClosestPoint = segment.pointAtT(segmentClosestPointT);
var squaredDistance = util_1.squaredLength(segmentClosestPoint, p);
if (squaredDistance < minSquaredDistance) {
closestPointTangent = segment.tangentAtT(segmentClosestPointT);
minSquaredDistance = squaredDistance;
}
}
}
if (closestPointTangent) {
return closestPointTangent;
}
return null;
};
Path.prototype.containsPoint = function (p, options) {
if (options === void 0) { options = {}; }
var polylines = this.toPolylines(options);
if (!polylines) {
return false;
}
var numIntersections = 0;
for (var i = 0, ii = polylines.length; i < ii; i += 1) {
var polyline = polylines[i];
if (polyline.containsPoint(p)) {
numIntersections += 1;
}
}
// returns `true` for odd numbers of intersections (even-odd algorithm)
return numIntersections % 2 === 1;
};
Path.prototype.pointAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
if (ratio <= 0) {
return this.start.clone();
}
if (ratio >= 1) {
return this.end.clone();
}
var opts = this.getOptions(options);
var pathLength = this.length(opts);
var length = pathLength * ratio;
return this.pointAtLength(length, opts);
};
Path.prototype.pointAtLength = function (length, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
if (length === 0) {
return this.start.clone();
}
var fromStart = true;
if (length < 0) {
fromStart = false;
length = -length; // tslint:disable-line
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var lastVisibleSegment;
var memo = 0;
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var index = fromStart ? i : ii - 1 - i;
var segment = this.segments[index];
var subdivisions = segmentSubdivisions[index];
var d = segment.length({
precision: precision,
subdivisions: subdivisions,
});
if (segment.isVisible) {
if (length <= memo + d) {
return segment.pointAtLength((fromStart ? 1 : -1) * (length - memo), {
precision: precision,
subdivisions: subdivisions,
});
}
lastVisibleSegment = segment;
}
memo += d;
}
// if length requested is higher than the length of the path,
// return last visible segment endpoint
if (lastVisibleSegment) {
return fromStart ? lastVisibleSegment.end : lastVisibleSegment.start;
}
// if no visible segment, return last segment end point
var lastSegment = this.segments[this.segments.length - 1];
return lastSegment.end.clone();
};
Path.prototype.pointAtT = function (t) {
var segments = this.segments;
var numSegments = segments.length;
if (numSegments === 0)
return null; // if segments is an empty array
var segmentIndex = t.segmentIndex;
if (segmentIndex < 0)
return segments[0].pointAtT(0);
if (segmentIndex >= numSegments) {
return segments[numSegments - 1].pointAtT(1);
}
var tValue = util_1.clamp(t.value, 0, 1);
return segments[segmentIndex].pointAtT(tValue);
};
Path.prototype.divideAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var rate = util_1.clamp(ratio, 0, 1);
var opts = this.getOptions(options);
var len = this.length(opts);
var length = len * rate;
return this.divideAtLength(length, opts);
};
Path.prototype.divideAtLength = function (length, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var fromStart = true;
if (length < 0) {
fromStart = false;
length = -length; // tslint:disable-line
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var memo = 0;
var divided;
var dividedSegmentIndex;
var lastValidSegment;
var lastValidSegmentIndex;
var t;
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var index_1 = fromStart ? i : ii - 1 - i;
var segment = this.getSegment(index_1);
var subdivisions = segmentSubdivisions[index_1];
var opts = { precision: precision, subdivisions: subdivisions };
var len = segment.length(opts);
if (segment.isDifferentiable()) {
lastValidSegment = segment;
lastValidSegmentIndex = index_1;
if (length <= memo + len) {
dividedSegmentIndex = index_1;
divided = segment.divideAtLength((fromStart ? 1 : -1) * (length - memo), opts);
break;
}
}
memo += len;
}
if (!lastValidSegment) {
return null;
}
if (!divided) {
dividedSegmentIndex = lastValidSegmentIndex;
t = fromStart ? 1 : 0;
divided = lastValidSegment.divideAtT(t);
}
// create a copy of this path and replace the identified segment with its two divided parts:
var pathCopy = this.clone();
var index = dividedSegmentIndex;
pathCopy.replaceSegment(index, divided);
var divisionStartIndex = index;
var divisionMidIndex = index + 1;
var divisionEndIndex = index + 2;
// do not insert the part if it looks like a point
if (!divided[0].isDifferentiable()) {
pathCopy.removeSegment(divisionStartIndex);
divisionMidIndex -= 1;
divisionEndIndex -= 1;
}
// insert a Moveto segment to ensure secondPath will be valid:
var movetoEnd = pathCopy.getSegment(divisionMidIndex).start;
pathCopy.insertSegment(divisionMidIndex, Path.createSegment('M', movetoEnd));
divisionEndIndex += 1;
// do not insert the part if it looks like a point
if (!divided[1].isDifferentiable()) {
pathCopy.removeSegment(divisionEndIndex - 1);
divisionEndIndex -= 1;
}
// ensure that Closepath segments in secondPath will be assigned correct subpathStartSegment:
var secondPathSegmentIndexConversion = divisionEndIndex - divisionStartIndex - 1;
for (var i = divisionEndIndex, ii = pathCopy.segments.length; i < ii; i += 1) {
var originalSegment = this.getSegment(i - secondPathSegmentIndexConversion);
var segment = pathCopy.getSegment(i);
if (segment.type === 'Z' &&
!originalSegment.subpathStartSegment.end.equals(segment.subpathStartSegment.end)) {
// pathCopy segment's subpathStartSegment is different from original segment's one
// convert this Closepath segment to a Lineto and replace it in pathCopy
var convertedSegment = Path.createSegment('L', originalSegment.end);
pathCopy.replaceSegment(i, convertedSegment);
}
}
// distribute pathCopy segments into two paths and return those:
var firstPath = new Path(pathCopy.segments.slice(0, divisionMidIndex));
var secondPath = new Path(pathCopy.segments.slice(divisionMidIndex));
return [firstPath, secondPath];
};
Path.prototype.intersectsWithLine = function (line, options) {
if (options === void 0) { options = {}; }
var polylines = this.toPolylines(options);
if (polylines == null) {
return null;
}
var intersections = null;
for (var i = 0, ii = polylines.length; i < ii; i += 1) {
var polyline = polylines[i];
var intersection = line.intersect(polyline);
if (intersection) {
if (intersections == null) {
intersections = [];
}
if (Array.isArray(intersection)) {
intersections.push.apply(intersections, intersection);
}
else {
intersections.push(intersection);
}
}
}
return intersections;
};
Path.prototype.isDifferentiable = function () {
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var segment = this.segments[i];
if (segment.isDifferentiable()) {
return true;
}
}
return false;
};
Path.prototype.isValid = function () {
var segments = this.segments;
var isValid = segments.length === 0 || segments[0].type === 'M';
return isValid;
};
Path.prototype.length = function (options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return 0;
}
var segmentSubdivisions = this.getSubdivisions(options);
var length = 0;
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var segment = this.segments[i];
var subdivisions = segmentSubdivisions[i];
length += segment.length({ subdivisions: subdivisions });
}
return length;
};
Path.prototype.lengthAtT = function (t, options) {
if (options === void 0) { options = {}; }
var count = this.segments.length;
if (count === 0) {
return 0;
}
var segmentIndex = t.segmentIndex;
if (segmentIndex < 0) {
return 0;
}
var tValue = util_1.clamp(t.value, 0, 1);
if (segmentIndex >= count) {
segmentIndex = count - 1;
tValue = 1;
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var length = 0;
for (var i = 0; i < segmentIndex; i += 1) {
var segment_1 = this.segments[i];
var subdivisions_1 = segmentSubdivisions[i];
length += segment_1.length({ precision: precision, subdivisions: subdivisions_1 });
}
var segment = this.segments[segmentIndex];
var subdivisions = segmentSubdivisions[segmentIndex];
length += segment.lengthAtT(tValue, { precision: precision, subdivisions: subdivisions });
return length;
};
Path.prototype.tangentAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var rate = util_1.clamp(ratio, 0, 1);
var opts = this.getOptions(options);
var len = this.length(opts);
var length = len * rate;
return this.tangentAtLength(length, opts);
};
Path.prototype.tangentAtLength = function (length, options) {
if (options === void 0) { options = {}; }
if (this.segments.length === 0) {
return null;
}
var fromStart = true;
if (length < 0) {
fromStart = false;
length = -length; // tslint:disable-line
}
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
var lastValidSegment;
var memo = 0;
for (var i = 0, ii = this.segments.length; i < ii; i += 1) {
var index = fromStart ? i : ii - 1 - i;
var segment = this.segments[index];
var subdivisions = segmentSubdivisions[index];
var len = segment.length({ precision: precision, subdivisions: subdivisions });
if (segment.isDifferentiable()) {
if (length <= memo + len) {
return segment.tangentAtLength((fromStart ? 1 : -1) * (length - memo), {
precision: precision,
subdivisions: subdivisions,
});
}
lastValidSegment = segment;
}
memo += len;
}
// if length requested is higher than the length of the path, return tangent of endpoint of last valid segment
if (lastValidSegment) {
var t = fromStart ? 1 : 0;
return lastValidSegment.tangentAtT(t);
}
// if no valid segment, return null
return null;
};
Path.prototype.tangentAtT = function (t) {
var count = this.segments.length;
if (count === 0) {
return null;
}
var segmentIndex = t.segmentIndex;
if (segmentIndex < 0) {
return this.segments[0].tangentAtT(0);
}
if (segmentIndex >= count) {
return this.segments[count - 1].tangentAtT(1);
}
var tValue = util_1.clamp(t.value, 0, 1);
return this.segments[segmentIndex].tangentAtT(tValue);
};
Path.prototype.getPrecision = function (options) {
if (options === void 0) { options = {}; }
return options.precision == null ? this.PRECISION : options.precision;
};
Path.prototype.getSubdivisions = function (options) {
if (options === void 0) { options = {}; }
if (options.segmentSubdivisions == null) {
var precision = this.getPrecision(options);
return this.getSegmentSubdivisions({ precision: precision });
}
return options.segmentSubdivisions;
};
Path.prototype.getOptions = function (options) {
if (options === void 0) { options = {}; }
var precision = this.getPrecision(options);
var segmentSubdivisions = this.getSubdivisions(options);
return { precision: precision, segmentSubdivisions: segmentSubdivisions };
};
Path.prototype.toPoints = function (options) {
if (options === void 0) { options = {}; }
var segments = this.segments;
var count = segments.length;
if (count === 0) {
return null;
}
var segmentSubdivisions = this.getSubdivisions(options);
var points = [];
var partialPoints = [];
for (var i = 0; i < count; i += 1) {
var segment = segments[i];
if (segment.isVisible) {
var divisions = segmentSubdivisions[i];
if (divisions.length > 0) {
divisions.forEach(function (c) { return partialPoints.push(c.start); });
}
else {
partialPoints.push(segment.start);
}
}
else if (partialPoints.length > 0) {
partialPoints.push(segments[i - 1].end);
points.push(partialPoints);
partialPoints = [];
}
}
if (partialPoints.length > 0) {
partialPoints.push(this.end);
points.push(partialPoints);
}
return points;
};
Path.prototype.toPolylines = function (options) {
if (options === void 0) { options = {}; }
var points = this.toPoints(options);
if (!points) {
return null;
}
return points.map(function (arr) { return new polyline_1.Polyline(arr); });
};
Path.prototype.scale = function (sx, sy, origin) {
this.segments.forEach(function (s) { return s.scale(sx, sy, origin); });
return this;
};
Path.prototype.translate = function (tx, ty) {
if (typeof tx === 'number') {
this.segments.forEach(function (s) { return s.translate(tx, ty); });
}
else {
this.segments.forEach(function (s) { return s.translate(tx); });
}
return this;
};
Path.prototype.clone = function () {
var path = new Path();
this.segments.forEach(function (s) { return path.appendSegment(s.clone()); });
return path;
};
Path.prototype.equals = function (p) {
if (p == null) {
return false;
}
var segments = this.segments;
var otherSegments = p.segments;
var count = segments.length;
if (otherSegments.length !== count) {
return false;
}
for (var i = 0; i < count; i += 1) {
var a = segments[i];
var b = otherSegments[i];
if (a.type !== b.type || !a.equals(b)) {
return false;
}
}
return true;
};
Path.prototype.toJSON = function () {
return this.segments.map(function (s) { return s.toJSON(); });
};
Path.prototype.serialize = function () {
if (!this.isValid()) {
throw new Error('Invalid path segments.');
}
return this.segments.map(function (s) { return s.serialize(); }).join(' ');
};
return Path;
}(geometry_1.Geometry));
exports.Path = Path;
(function (Path) {
Path.toStringTag = "X6.Geometry." + Path.name;
function isPath(instance) {
if (instance == null) {
return false;
}
if (instance instanceof Path) {
return true;
}
var tag = instance[Symbol.toStringTag];
var path = instance;
if ((tag == null || tag === Path.toStringTag) &&
Array.isArray(path.segments) &&
typeof path.moveTo === 'function' &&
typeof path.lineTo === 'function' &&
typeof path.curveTo === 'function') {
return true;
}
return false;
}
Path.isPath = isPath;
})(Path = exports.Path || (exports.Path = {}));
exports.Path = Path;
(function (Path) {
var regexSupportedData = new RegExp("^[\\s\\dLMCZz,.]*$");
function isSupported(data) {
if (typeof data !== 'string') {
return false;
}
return regexSupportedData.test(data);
}
Path.isSupported = isSupported;
Path.normalize = normalize_1.normalizePathData;
function parse(pathData) {
if (!pathData) {
return new Path();
}
var path = new Path();
var commandRe = /(?:[a-zA-Z] *)(?:(?:-?\d+(?:\.\d+)?(?:e[-+]?\d+)? *,? *)|(?:-?\.\d+ *,? *))+|(?:[a-zA-Z] *)(?! |\d|-|\.)/g;
var commands = Path.normalize(pathData).match(commandRe);
if (commands != null) {
for (var i = 0, ii = commands.length; i < ii; i += 1) {
var command = commands[i];
var argRe = /(?:[a-zA-Z])|(?:(?:-?\d+(?:\.\d+)?(?:e[-+]?\d+)?))|(?:(?:-?\.\d+))/g;
// args = [type, coordinate1, coordinate2...]
var args = command.match(argRe);
if (args != null) {
var type = args[0];
var coords = args.slice(1).map(function (a) { return +a; });
var segment = createSegment.call.apply(createSegment, __spreadArrays([null, type], coords));
path.appendSegment(segment);
}
}
}
return path;
}
Path.parse = parse;
function createSegment(type) {
var _a, _b, _c;
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (type === 'M') {
return (_a = moveto_1.MoveTo.create).call.apply(_a, __spreadArrays([null], args));
}
if (type === 'L') {
return (_b = lineto_1.LineTo.create).call.apply(_b, __spreadArrays([null], args));
}
if (type === 'C') {
return (_c = curveto_1.CurveTo.create).call.apply(_c, __spreadArrays([null], args));
}
if (type === 'z' || type === 'Z') {
return close_1.Close.create();
}
throw new Error("Invalid path segment type \"" + type + "\"");
}
Path.createSegment = createSegment;
})(Path = exports.Path || (exports.Path = {}));
exports.Path = Path;
//# sourceMappingURL=path.js.map