@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
204 lines (203 loc) • 7.42 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var Group2d_exports = {};
__export(Group2d_exports, {
Group2d: () => Group2d
});
module.exports = __toCommonJS(Group2d_exports);
var import_state = require("@tldraw/state");
var import_utils = require("@tldraw/utils");
var import_Box = require("../Box");
var import_Vec = require("../Vec");
var import_Geometry2d = require("./Geometry2d");
class Group2d extends import_Geometry2d.Geometry2d {
children = [];
ignoredChildren = [];
constructor(config) {
super({ ...config, isClosed: true, isFilled: false });
const addChildren = (children) => {
for (const child of children) {
if (child instanceof Group2d) {
addChildren(child.children);
} else if (child.ignore) {
this.ignoredChildren.push(child);
} else {
this.children.push(child);
}
}
};
addChildren(config.children);
if (this.children.length === 0) throw Error("Group2d must have at least one child");
}
getVertices(filters) {
if (this.isExcludedByFilter(filters)) return [];
return this.children.filter((c) => !c.isExcludedByFilter(filters)).flatMap((c) => c.getVertices(filters));
}
nearestPoint(point, filters) {
let dist = Infinity;
let nearest;
const { children } = this;
if (children.length === 0) {
throw Error("no children");
}
let p;
let d;
for (const child of children) {
if (child.isExcludedByFilter(filters)) continue;
p = child.nearestPoint(point, filters);
d = import_Vec.Vec.Dist2(p, point);
if (d < dist) {
dist = d;
nearest = p;
}
}
if (!nearest) throw Error("nearest point not found");
return nearest;
}
distanceToPoint(point, hitInside = false, filters) {
let smallestDistance = Infinity;
for (const child of this.children) {
if (child.isExcludedByFilter(filters)) continue;
const distance = child.distanceToPoint(point, hitInside, filters);
if (distance < smallestDistance) {
smallestDistance = distance;
}
}
return smallestDistance;
}
hitTestPoint(point, margin, hitInside, filters = import_Geometry2d.Geometry2dFilters.EXCLUDE_LABELS) {
return !!this.children.filter((c) => !c.isExcludedByFilter(filters)).find((c) => c.hitTestPoint(point, margin, hitInside));
}
hitTestLineSegment(A, B, zoom, filters = import_Geometry2d.Geometry2dFilters.EXCLUDE_LABELS) {
return !!this.children.filter((c) => !c.isExcludedByFilter(filters)).find((c) => c.hitTestLineSegment(A, B, zoom));
}
intersectLineSegment(A, B, filters) {
return this.children.flatMap((child) => {
if (child.isExcludedByFilter(filters)) return import_state.EMPTY_ARRAY;
return child.intersectLineSegment(A, B, filters);
});
}
intersectCircle(center, radius, filters) {
return this.children.flatMap((child) => {
if (child.isExcludedByFilter(filters)) return import_state.EMPTY_ARRAY;
return child.intersectCircle(center, radius, filters);
});
}
intersectPolygon(polygon, filters) {
return this.children.flatMap((child) => {
if (child.isExcludedByFilter(filters)) return import_state.EMPTY_ARRAY;
return child.intersectPolygon(polygon, filters);
});
}
intersectPolyline(polyline, filters) {
return this.children.flatMap((child) => {
if (child.isExcludedByFilter(filters)) return import_state.EMPTY_ARRAY;
return child.intersectPolyline(polyline, filters);
});
}
interpolateAlongEdge(t, filters) {
const totalLength = this.getLength(filters);
const distanceToTravel = t * totalLength;
let distanceTraveled = 0;
for (const child of this.children) {
if (child.isExcludedByFilter(filters)) continue;
const childLength = child.length;
const newDistanceTraveled = distanceTraveled + childLength;
if (newDistanceTraveled >= distanceToTravel) {
return child.interpolateAlongEdge(
(0, import_utils.invLerp)(distanceTraveled, newDistanceTraveled, distanceToTravel),
filters
);
}
distanceTraveled = newDistanceTraveled;
}
return this.children[this.children.length - 1].interpolateAlongEdge(1, filters);
}
uninterpolateAlongEdge(point, filters) {
const totalLength = this.getLength(filters);
let closestChild = null;
let closestDistance = Infinity;
let distanceTraveled = 0;
for (const child of this.children) {
if (child.isExcludedByFilter(filters)) continue;
const childLength = child.getLength(filters);
const newDistanceTraveled = distanceTraveled + childLength;
const distance = child.distanceToPoint(point, false, filters);
if (distance < closestDistance) {
closestDistance = distance;
closestChild = {
startLength: distanceTraveled,
endLength: newDistanceTraveled,
child
};
}
distanceTraveled = newDistanceTraveled;
}
(0, import_utils.assert)(closestChild);
const normalizedDistanceInChild = closestChild.child.uninterpolateAlongEdge(point, filters);
const childTLength = (0, import_utils.lerp)(
closestChild.startLength,
closestChild.endLength,
normalizedDistanceInChild
);
return childTLength / totalLength;
}
transform(transform) {
return new Group2d({
children: this.children.map((c) => c.transform(transform)),
isLabel: this.isLabel,
debugColor: this.debugColor,
ignore: this.ignore
});
}
getArea() {
return this.children[0].area;
}
toSimpleSvgPath() {
let path = "";
for (const child of this.children) {
path += child.toSimpleSvgPath();
}
const corners = import_Box.Box.FromPoints(this.vertices).corners;
for (let i = 0, n = corners.length; i < n; i++) {
const corner = corners[i];
const prevCorner = corners[(i - 1 + n) % n];
const prevDist = corner.dist(prevCorner);
const nextCorner = corners[(i + 1) % n];
const nextDist = corner.dist(nextCorner);
const A = corner.clone().lrp(prevCorner, 4 / prevDist);
const B = corner;
const C = corner.clone().lrp(nextCorner, 4 / nextDist);
path += `M${A.x},${A.y} L${B.x},${B.y} L${C.x},${C.y} `;
}
return path;
}
getLength(filters) {
let length = 0;
for (const child of this.children) {
if (child.isExcludedByFilter(filters)) continue;
length += child.length;
}
return length;
}
getSvgPathData() {
return this.children.map((c, i) => c.isLabel ? "" : c.getSvgPathData(i === 0)).join(" ");
}
}
//# sourceMappingURL=Group2d.js.map