UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

204 lines (203 loc) • 7.42 kB
"use strict"; 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