@mathboard-ai/math
Version:
Excalidraw math functions for MathBoard
1,812 lines (1,771 loc) • 49.4 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// <define:import.meta.env>
var init_define_import_meta_env = __esm({
"<define:import.meta.env>"() {
}
});
// ../../node_modules/es6-promise-pool/es6-promise-pool.js
var require_es6_promise_pool = __commonJS({
"../../node_modules/es6-promise-pool/es6-promise-pool.js"(exports, module) {
init_define_import_meta_env();
(function(root, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.PromisePool = factory();
root.promisePool = root.PromisePool;
}
})(exports, function() {
"use strict";
var EventTarget = function() {
this._listeners = {};
};
EventTarget.prototype.addEventListener = function(type, listener) {
this._listeners[type] = this._listeners[type] || [];
if (this._listeners[type].indexOf(listener) < 0) {
this._listeners[type].push(listener);
}
};
EventTarget.prototype.removeEventListener = function(type, listener) {
if (this._listeners[type]) {
var p = this._listeners[type].indexOf(listener);
if (p >= 0) {
this._listeners[type].splice(p, 1);
}
}
};
EventTarget.prototype.dispatchEvent = function(evt) {
if (this._listeners[evt.type] && this._listeners[evt.type].length) {
var listeners = this._listeners[evt.type].slice();
for (var i = 0, l = listeners.length; i < l; ++i) {
listeners[i].call(this, evt);
}
}
};
var isGenerator = function(func) {
return typeof func.constructor === "function" && func.constructor.name === "GeneratorFunction";
};
var functionToIterator = function(func) {
return {
next: function() {
var promise = func();
return promise ? { value: promise } : { done: true };
}
};
};
var promiseToIterator = function(promise) {
var called = false;
return {
next: function() {
if (called) {
return { done: true };
}
called = true;
return { value: promise };
}
};
};
var toIterator = function(obj, Promise2) {
var type = typeof obj;
if (type === "object") {
if (typeof obj.next === "function") {
return obj;
}
if (typeof obj.then === "function") {
return promiseToIterator(obj);
}
}
if (type === "function") {
return isGenerator(obj) ? obj() : functionToIterator(obj);
}
return promiseToIterator(Promise2.resolve(obj));
};
var PromisePoolEvent = function(target, type, data) {
this.target = target;
this.type = type;
this.data = data;
};
var PromisePool = function(source, concurrency, options) {
EventTarget.call(this);
if (typeof concurrency !== "number" || Math.floor(concurrency) !== concurrency || concurrency < 1) {
throw new Error("Invalid concurrency");
}
this._concurrency = concurrency;
this._options = options || {};
this._options.promise = this._options.promise || Promise;
this._iterator = toIterator(source, this._options.promise);
this._done = false;
this._size = 0;
this._promise = null;
this._callbacks = null;
};
PromisePool.prototype = new EventTarget();
PromisePool.prototype.constructor = PromisePool;
PromisePool.prototype.concurrency = function(value) {
if (typeof value !== "undefined") {
this._concurrency = value;
if (this.active()) {
this._proceed();
}
}
return this._concurrency;
};
PromisePool.prototype.size = function() {
return this._size;
};
PromisePool.prototype.active = function() {
return !!this._promise;
};
PromisePool.prototype.promise = function() {
return this._promise;
};
PromisePool.prototype.start = function() {
var that = this;
var Promise2 = this._options.promise;
this._promise = new Promise2(function(resolve, reject) {
that._callbacks = {
reject,
resolve
};
that._proceed();
});
return this._promise;
};
PromisePool.prototype._fireEvent = function(type, data) {
this.dispatchEvent(new PromisePoolEvent(this, type, data));
};
PromisePool.prototype._settle = function(error) {
if (error) {
this._callbacks.reject(error);
} else {
this._callbacks.resolve();
}
this._promise = null;
this._callbacks = null;
};
PromisePool.prototype._onPooledPromiseFulfilled = function(promise, result) {
this._size--;
if (this.active()) {
this._fireEvent("fulfilled", {
promise,
result
});
this._proceed();
}
};
PromisePool.prototype._onPooledPromiseRejected = function(promise, error) {
this._size--;
if (this.active()) {
this._fireEvent("rejected", {
promise,
error
});
this._settle(error || new Error("Unknown error"));
}
};
PromisePool.prototype._trackPromise = function(promise) {
var that = this;
promise.then(function(result) {
that._onPooledPromiseFulfilled(promise, result);
}, function(error) {
that._onPooledPromiseRejected(promise, error);
})["catch"](function(err) {
that._settle(new Error("Promise processing failed: " + err));
});
};
PromisePool.prototype._proceed = function() {
if (!this._done) {
var result = { done: false };
while (this._size < this._concurrency && !(result = this._iterator.next()).done) {
this._size++;
this._trackPromise(result.value);
}
this._done = result === null || !!result.done;
}
if (this._done && this._size === 0) {
this._settle();
}
};
PromisePool.PromisePoolEvent = PromisePoolEvent;
PromisePool.PromisePool = PromisePool;
return PromisePool;
});
}
});
// ../../node_modules/@braintree/sanitize-url/dist/index.js
var require_dist = __commonJS({
"../../node_modules/@braintree/sanitize-url/dist/index.js"(exports) {
"use strict";
init_define_import_meta_env();
Object.defineProperty(exports, "__esModule", { value: true });
exports.sanitizeUrl = void 0;
var invalidProtocolRegex = /^([^\w]*)(javascript|data|vbscript)/im;
var htmlEntitiesRegex = /&#(\w+)(^\w|;)?/g;
var htmlCtrlEntityRegex = /&(newline|tab);/gi;
var ctrlCharactersRegex = /[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim;
var urlSchemeRegex = /^.+(:|:)/gim;
var relativeFirstCharacters = [".", "/"];
function isRelativeUrlWithoutProtocol(url) {
return relativeFirstCharacters.indexOf(url[0]) > -1;
}
function decodeHtmlCharacters(str) {
return str.replace(htmlEntitiesRegex, function(match, dec) {
return String.fromCharCode(dec);
});
}
function sanitizeUrl2(url) {
var sanitizedUrl = decodeHtmlCharacters(url || "").replace(htmlCtrlEntityRegex, "").replace(ctrlCharactersRegex, "").trim();
if (!sanitizedUrl) {
return "about:blank";
}
if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {
return sanitizedUrl;
}
var urlSchemeParseResults = sanitizedUrl.match(urlSchemeRegex);
if (!urlSchemeParseResults) {
return sanitizedUrl;
}
var urlScheme = urlSchemeParseResults[0];
if (invalidProtocolRegex.test(urlScheme)) {
return "about:blank";
}
return sanitizedUrl;
}
exports.sanitizeUrl = sanitizeUrl2;
}
});
// src/index.ts
init_define_import_meta_env();
// src/angle.ts
init_define_import_meta_env();
// src/utils.ts
init_define_import_meta_env();
var PRECISION = 1e-4;
var clamp = (value, min, max) => {
return Math.min(Math.max(value, min), max);
};
var round = (value, precision, func = "round") => {
const multiplier = Math.pow(10, precision);
return Math[func]((value + Number.EPSILON) * multiplier) / multiplier;
};
var roundToStep = (value, step, func = "round") => {
const factor = 1 / step;
return Math[func](value * factor) / factor;
};
var average = (a, b) => (a + b) / 2;
var isFiniteNumber = (value) => {
return typeof value === "number" && Number.isFinite(value);
};
var isCloseTo = (a, b, precision = PRECISION) => Math.abs(a - b) < precision;
// src/angle.ts
var normalizeRadians = (angle) => angle < 0 ? angle % (2 * Math.PI) + 2 * Math.PI : angle % (2 * Math.PI);
var cartesian2Polar = ([
x,
y
]) => [
Math.hypot(x, y),
normalizeRadians(Math.atan2(y, x))
];
function degreesToRadians(degrees) {
return degrees * Math.PI / 180;
}
function radiansToDegrees(degrees) {
return degrees * 180 / Math.PI;
}
function isRightAngleRads(rads) {
return Math.abs(Math.sin(2 * rads)) < PRECISION;
}
function radiansBetweenAngles(a, min, max) {
a = normalizeRadians(a);
min = normalizeRadians(min);
max = normalizeRadians(max);
if (min < max) {
return a >= min && a <= max;
}
return a >= min || a <= max;
}
function radiansDifference(a, b) {
a = normalizeRadians(a);
b = normalizeRadians(b);
let diff = a - b;
if (diff < -Math.PI) {
diff = diff + 2 * Math.PI;
} else if (diff > Math.PI) {
diff = diff - 2 * Math.PI;
}
return Math.abs(diff);
}
// src/curve.ts
init_define_import_meta_env();
// src/point.ts
init_define_import_meta_env();
// src/vector.ts
init_define_import_meta_env();
function vector(x, y, originX = 0, originY = 0) {
return [x - originX, y - originY];
}
function vectorFromPoint(p, origin = [0, 0], threshold, defaultValue = [0, 1]) {
const vec = vector(p[0] - origin[0], p[1] - origin[1]);
if (threshold && vectorMagnitudeSq(vec) < threshold * threshold) {
return defaultValue;
}
return vec;
}
function vectorCross(a, b) {
return a[0] * b[1] - b[0] * a[1];
}
function vectorDot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
function isVector(v) {
return Array.isArray(v) && v.length === 2 && typeof v[0] === "number" && !isNaN(v[0]) && typeof v[1] === "number" && !isNaN(v[1]);
}
function vectorAdd(a, b) {
return [a[0] + b[0], a[1] + b[1]];
}
function vectorSubtract(start, end) {
return [start[0] - end[0], start[1] - end[1]];
}
function vectorScale(v, scalar) {
return vector(v[0] * scalar, v[1] * scalar);
}
function vectorMagnitudeSq(v) {
return v[0] * v[0] + v[1] * v[1];
}
function vectorMagnitude(v) {
return Math.sqrt(vectorMagnitudeSq(v));
}
var vectorNormalize = (v) => {
const m = vectorMagnitude(v);
if (m === 0) {
return vector(0, 0);
}
return vector(v[0] / m, v[1] / m);
};
var vectorNormal = (v) => vector(v[1], -v[0]);
// src/point.ts
function pointFrom(x, y) {
return [x, y];
}
function pointFromArray(numberArray) {
return numberArray.length === 2 ? pointFrom(numberArray[0], numberArray[1]) : void 0;
}
function pointFromPair(pair) {
return pair;
}
function pointFromVector(v, offset = pointFrom(0, 0)) {
return pointFrom(offset[0] + v[0], offset[1] + v[1]);
}
function isPoint(p) {
return Array.isArray(p) && p.length === 2 && typeof p[0] === "number" && !isNaN(p[0]) && typeof p[1] === "number" && !isNaN(p[1]);
}
function pointsEqual(a, b, tolerance = PRECISION) {
const abs = Math.abs;
return abs(a[0] - b[0]) < tolerance && abs(a[1] - b[1]) < tolerance;
}
function pointRotateRads([x, y], [cx, cy], angle) {
return pointFrom(
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy
);
}
function pointRotateDegs(point, center, angle) {
return pointRotateRads(point, center, degreesToRadians(angle));
}
function pointTranslate(p, v = [0, 0]) {
return pointFrom(p[0] + v[0], p[1] + v[1]);
}
function pointCenter(a, b) {
return pointFrom((a[0] + b[0]) / 2, (a[1] + b[1]) / 2);
}
function pointDistance(a, b) {
return Math.hypot(b[0] - a[0], b[1] - a[1]);
}
function pointDistanceSq(a, b) {
const xDiff = b[0] - a[0];
const yDiff = b[1] - a[1];
return xDiff * xDiff + yDiff * yDiff;
}
var pointScaleFromOrigin = (p, mid, multiplier) => pointTranslate(mid, vectorScale(vectorFromPoint(p, mid), multiplier));
var isPointWithinBounds = (p, q, r) => {
return q[0] <= Math.max(p[0], r[0]) && q[0] >= Math.min(p[0], r[0]) && q[1] <= Math.max(p[1], r[1]) && q[1] >= Math.min(p[1], r[1]);
};
// src/constants.ts
init_define_import_meta_env();
var LegendreGaussN24TValues = [
-0.06405689286260563,
0.06405689286260563,
-0.1911188674736163,
0.1911188674736163,
-0.3150426796961634,
0.3150426796961634,
-0.4337935076260451,
0.4337935076260451,
-0.5454214713888396,
0.5454214713888396,
-0.6480936519369755,
0.6480936519369755,
-0.7401241915785544,
0.7401241915785544,
-0.820001985973903,
0.820001985973903,
-0.8864155270044011,
0.8864155270044011,
-0.9382745520027328,
0.9382745520027328,
-0.9747285559713095,
0.9747285559713095,
-0.9951872199970213,
0.9951872199970213
];
var LegendreGaussN24CValues = [
0.12793819534675216,
0.12793819534675216,
0.1258374563468283,
0.1258374563468283,
0.12167047292780339,
0.12167047292780339,
0.1155056680537256,
0.1155056680537256,
0.10744427011596563,
0.10744427011596563,
0.09761865210411388,
0.09761865210411388,
0.08619016153195327,
0.08619016153195327,
0.0733464814110803,
0.0733464814110803,
0.05929858491543678,
0.05929858491543678,
0.04427743881741981,
0.04427743881741981,
0.028531388628933663,
0.028531388628933663,
0.0123412297999872,
0.0123412297999872
];
// src/curve.ts
function curve(a, b, c, d) {
return [a, b, c, d];
}
function gradient(f, t0, s0, delta = 1e-6) {
return [
(f(t0 + delta, s0) - f(t0 - delta, s0)) / (2 * delta),
(f(t0, s0 + delta) - f(t0, s0 - delta)) / (2 * delta)
];
}
function solve(f, t0, s0, tolerance = 1e-3, iterLimit = 10) {
let error = Infinity;
let iter = 0;
while (error >= tolerance) {
if (iter >= iterLimit) {
return null;
}
const y0 = f(t0, s0);
const jacobian = [
gradient((t, s) => f(t, s)[0], t0, s0),
gradient((t, s) => f(t, s)[1], t0, s0)
];
const b = [[-y0[0]], [-y0[1]]];
const det = jacobian[0][0] * jacobian[1][1] - jacobian[0][1] * jacobian[1][0];
if (det === 0) {
return null;
}
const iJ = [
[jacobian[1][1] / det, -jacobian[0][1] / det],
[-jacobian[1][0] / det, jacobian[0][0] / det]
];
const h = [
[iJ[0][0] * b[0][0] + iJ[0][1] * b[1][0]],
[iJ[1][0] * b[0][0] + iJ[1][1] * b[1][0]]
];
t0 = t0 + h[0][0];
s0 = s0 + h[1][0];
const [tErr, sErr] = f(t0, s0);
error = Math.max(Math.abs(tErr), Math.abs(sErr));
iter += 1;
}
return [t0, s0];
}
var bezierEquation = (c, t) => pointFrom(
(1 - t) ** 3 * c[0][0] + 3 * (1 - t) ** 2 * t * c[1][0] + 3 * (1 - t) * t ** 2 * c[2][0] + t ** 3 * c[3][0],
(1 - t) ** 3 * c[0][1] + 3 * (1 - t) ** 2 * t * c[1][1] + 3 * (1 - t) * t ** 2 * c[2][1] + t ** 3 * c[3][1]
);
function curveIntersectLineSegment(c, l) {
const line2 = (s) => pointFrom(
l[0][0] + s * (l[1][0] - l[0][0]),
l[0][1] + s * (l[1][1] - l[0][1])
);
const initial_guesses = [
[0.5, 0],
[0.2, 0],
[0.8, 0]
];
const calculate = ([t0, s0]) => {
const solution2 = solve(
(t2, s2) => {
const bezier_point = bezierEquation(c, t2);
const line_point = line2(s2);
return [
bezier_point[0] - line_point[0],
bezier_point[1] - line_point[1]
];
},
t0,
s0
);
if (!solution2) {
return null;
}
const [t, s] = solution2;
if (t < 0 || t > 1 || s < 0 || s > 1) {
return null;
}
return bezierEquation(c, t);
};
let solution = calculate(initial_guesses[0]);
if (solution) {
return [solution];
}
solution = calculate(initial_guesses[1]);
if (solution) {
return [solution];
}
solution = calculate(initial_guesses[2]);
if (solution) {
return [solution];
}
return [];
}
function curveClosestPoint(c, p, tolerance = 1e-3) {
const localMinimum = (min, max, f, e = tolerance) => {
let m = min;
let n = max;
let k;
while (n - m > e) {
k = (n + m) / 2;
if (f(k - e) < f(k + e)) {
n = k;
} else {
m = k;
}
}
return k;
};
const maxSteps = 30;
let closestStep = 0;
for (let min = Infinity, step = 0; step < maxSteps; step++) {
const d = pointDistance(p, bezierEquation(c, step / maxSteps));
if (d < min) {
min = d;
closestStep = step;
}
}
const t0 = Math.max((closestStep - 1) / maxSteps, 0);
const t1 = Math.min((closestStep + 1) / maxSteps, 1);
const solution = localMinimum(
t0,
t1,
(t) => pointDistance(p, bezierEquation(c, t))
);
if (!solution) {
return null;
}
return bezierEquation(c, solution);
}
function curvePointDistance(c, p) {
const closest = curveClosestPoint(c, p);
if (!closest) {
return 0;
}
return pointDistance(p, closest);
}
function isCurve(v) {
return Array.isArray(v) && v.length === 4 && isPoint(v[0]) && isPoint(v[1]) && isPoint(v[2]) && isPoint(v[3]);
}
function curveTangent([p0, p1, p2, p3], t) {
return vector(
-3 * (1 - t) * (1 - t) * p0[0] + 3 * (1 - t) * (1 - t) * p1[0] - 6 * t * (1 - t) * p1[0] - 3 * t * t * p2[0] + 6 * t * (1 - t) * p2[0] + 3 * t * t * p3[0],
-3 * (1 - t) * (1 - t) * p0[1] + 3 * (1 - t) * (1 - t) * p1[1] - 6 * t * (1 - t) * p1[1] - 3 * t * t * p2[1] + 6 * t * (1 - t) * p2[1] + 3 * t * t * p3[1]
);
}
function curveCatmullRomQuadraticApproxPoints(points, tension = 0.5) {
if (points.length < 2) {
return;
}
const pointSets = [];
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[i - 1 < 0 ? 0 : i - 1];
const p1 = points[i];
const p2 = points[i + 1 >= points.length ? points.length - 1 : i + 1];
const cpX = p1[0] + (p2[0] - p0[0]) * tension / 2;
const cpY = p1[1] + (p2[1] - p0[1]) * tension / 2;
pointSets.push([
pointFrom(cpX, cpY),
pointFrom(p2[0], p2[1])
]);
}
return pointSets;
}
function curveCatmullRomCubicApproxPoints(points, tension = 0.5) {
if (points.length < 2) {
return;
}
const pointSets = [];
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[i - 1 < 0 ? 0 : i - 1];
const p1 = points[i];
const p2 = points[i + 1 >= points.length ? points.length - 1 : i + 1];
const p3 = points[i + 2 >= points.length ? points.length - 1 : i + 2];
const tangent1 = [(p2[0] - p0[0]) * tension, (p2[1] - p0[1]) * tension];
const tangent2 = [(p3[0] - p1[0]) * tension, (p3[1] - p1[1]) * tension];
const cp1x = p1[0] + tangent1[0] / 3;
const cp1y = p1[1] + tangent1[1] / 3;
const cp2x = p2[0] - tangent2[0] / 3;
const cp2y = p2[1] - tangent2[1] / 3;
pointSets.push(
curve(
pointFrom(p1[0], p1[1]),
pointFrom(cp1x, cp1y),
pointFrom(cp2x, cp2y),
pointFrom(p2[0], p2[1])
)
);
}
return pointSets;
}
function curveOffsetPoints([p0, p1, p2, p3], offset, steps = 50) {
const offsetPoints = [];
for (let i = 0; i <= steps; i++) {
const t = i / steps;
const c = curve(p0, p1, p2, p3);
const point = bezierEquation(c, t);
const tangent = vectorNormalize(curveTangent(c, t));
const normal = vectorNormal(tangent);
offsetPoints.push(pointFromVector(vectorScale(normal, offset), point));
}
return offsetPoints;
}
function offsetPointsForQuadraticBezier(p0, p1, p2, offsetDist, steps = 50) {
const offsetPoints = [];
for (let i = 0; i <= steps; i++) {
const t = i / steps;
const t1 = 1 - t;
const point = pointFrom(
t1 * t1 * p0[0] + 2 * t1 * t * p1[0] + t * t * p2[0],
t1 * t1 * p0[1] + 2 * t1 * t * p1[1] + t * t * p2[1]
);
const tangentX = 2 * (1 - t) * (p1[0] - p0[0]) + 2 * t * (p2[0] - p1[0]);
const tangentY = 2 * (1 - t) * (p1[1] - p0[1]) + 2 * t * (p2[1] - p1[1]);
const tangent = vectorNormalize(vector(tangentX, tangentY));
const normal = vectorNormal(tangent);
offsetPoints.push(pointFromVector(vectorScale(normal, offsetDist), point));
}
return offsetPoints;
}
function curveLength(c) {
const z2 = 0.5;
let sum = 0;
for (let i = 0; i < 24; i++) {
const t = z2 * LegendreGaussN24TValues[i] + z2;
const derivativeVector = curveTangent(c, t);
const magnitude = Math.sqrt(
derivativeVector[0] * derivativeVector[0] + derivativeVector[1] * derivativeVector[1]
);
sum += LegendreGaussN24CValues[i] * magnitude;
}
return z2 * sum;
}
function curveLengthAtParameter(c, t) {
if (t <= 0) {
return 0;
}
if (t >= 1) {
return curveLength(c);
}
const z1 = t / 2;
const z2 = t / 2;
let sum = 0;
for (let i = 0; i < 24; i++) {
const parameter = z1 * LegendreGaussN24TValues[i] + z2;
const derivativeVector = curveTangent(c, parameter);
const magnitude = Math.sqrt(
derivativeVector[0] * derivativeVector[0] + derivativeVector[1] * derivativeVector[1]
);
sum += LegendreGaussN24CValues[i] * magnitude;
}
return z1 * sum;
}
function curvePointAtLength(c, percent) {
if (percent <= 0) {
return bezierEquation(c, 0);
}
if (percent >= 1) {
return bezierEquation(c, 1);
}
const totalLength = curveLength(c);
const targetLength = totalLength * percent;
let tMin = 0;
let tMax = 1;
let t = percent;
let currentLength = 0;
const tolerance = totalLength * 1e-4;
const maxIterations = 20;
for (let iteration = 0; iteration < maxIterations; iteration++) {
currentLength = curveLengthAtParameter(c, t);
const error = Math.abs(currentLength - targetLength);
if (error < tolerance) {
break;
}
if (currentLength < targetLength) {
tMin = t;
} else {
tMax = t;
}
t = (tMin + tMax) / 2;
}
return bezierEquation(c, t);
}
// src/ellipse.ts
init_define_import_meta_env();
function ellipse(center, halfWidth, halfHeight) {
return {
center,
halfWidth,
halfHeight
};
}
var ellipseIncludesPoint = (p, ellipse2) => {
const { center, halfWidth, halfHeight } = ellipse2;
const normalizedX = (p[0] - center[0]) / halfWidth;
const normalizedY = (p[1] - center[1]) / halfHeight;
return normalizedX * normalizedX + normalizedY * normalizedY <= 1;
};
var ellipseTouchesPoint = (point, ellipse2, threshold = PRECISION) => {
return ellipseDistanceFromPoint(point, ellipse2) <= threshold;
};
var ellipseDistanceFromPoint = (p, ellipse2) => {
const { halfWidth, halfHeight, center } = ellipse2;
const a = halfWidth;
const b = halfHeight;
const translatedPoint = vectorAdd(
vectorFromPoint(p),
vectorScale(vectorFromPoint(center), -1)
);
const px = Math.abs(translatedPoint[0]);
const py = Math.abs(translatedPoint[1]);
let tx = 0.707;
let ty = 0.707;
for (let i = 0; i < 3; i++) {
const x = a * tx;
const y = b * ty;
const ex = (a * a - b * b) * tx ** 3 / a;
const ey = (b * b - a * a) * ty ** 3 / b;
const rx = x - ex;
const ry = y - ey;
const qx = px - ex;
const qy = py - ey;
const r = Math.hypot(ry, rx);
const q = Math.hypot(qy, qx);
tx = Math.min(1, Math.max(0, (qx * r / q + ex) / a));
ty = Math.min(1, Math.max(0, (qy * r / q + ey) / b));
const t = Math.hypot(ty, tx);
tx /= t;
ty /= t;
}
const [minX, minY] = [
a * tx * Math.sign(translatedPoint[0]),
b * ty * Math.sign(translatedPoint[1])
];
return pointDistance(pointFromVector(translatedPoint), pointFrom(minX, minY));
};
function ellipseSegmentInterceptPoints(e, s) {
const rx = e.halfWidth;
const ry = e.halfHeight;
const dir = vectorFromPoint(s[1], s[0]);
const diff = vector(s[0][0] - e.center[0], s[0][1] - e.center[1]);
const mDir = vector(dir[0] / (rx * rx), dir[1] / (ry * ry));
const mDiff = vector(diff[0] / (rx * rx), diff[1] / (ry * ry));
const a = vectorDot(dir, mDir);
const b = vectorDot(dir, mDiff);
const c = vectorDot(diff, mDiff) - 1;
const d = b * b - a * c;
const intersections = [];
if (d > 0) {
const t_a = (-b - Math.sqrt(d)) / a;
const t_b = (-b + Math.sqrt(d)) / a;
if (0 <= t_a && t_a <= 1) {
intersections.push(
pointFrom(
s[0][0] + (s[1][0] - s[0][0]) * t_a,
s[0][1] + (s[1][1] - s[0][1]) * t_a
)
);
}
if (0 <= t_b && t_b <= 1) {
intersections.push(
pointFrom(
s[0][0] + (s[1][0] - s[0][0]) * t_b,
s[0][1] + (s[1][1] - s[0][1]) * t_b
)
);
}
} else if (d === 0) {
const t = -b / a;
if (0 <= t && t <= 1) {
intersections.push(
pointFrom(
s[0][0] + (s[1][0] - s[0][0]) * t,
s[0][1] + (s[1][1] - s[0][1]) * t
)
);
}
}
return intersections;
}
function ellipseLineIntersectionPoints({ center, halfWidth, halfHeight }, [g, h]) {
const [cx, cy] = center;
const x1 = g[0] - cx;
const y1 = g[1] - cy;
const x2 = h[0] - cx;
const y2 = h[1] - cy;
const a = Math.pow(x2 - x1, 2) / Math.pow(halfWidth, 2) + Math.pow(y2 - y1, 2) / Math.pow(halfHeight, 2);
const b = 2 * (x1 * (x2 - x1) / Math.pow(halfWidth, 2) + y1 * (y2 - y1) / Math.pow(halfHeight, 2));
const c = Math.pow(x1, 2) / Math.pow(halfWidth, 2) + Math.pow(y1, 2) / Math.pow(halfHeight, 2) - 1;
const t1 = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
const t2 = (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
const candidates = [
pointFrom(x1 + t1 * (x2 - x1) + cx, y1 + t1 * (y2 - y1) + cy),
pointFrom(x1 + t2 * (x2 - x1) + cx, y1 + t2 * (y2 - y1) + cy)
].filter((p) => !isNaN(p[0]) && !isNaN(p[1]));
if (candidates.length === 2 && pointsEqual(candidates[0], candidates[1])) {
return [candidates[0]];
}
return candidates;
}
// src/line.ts
init_define_import_meta_env();
function line(a, b) {
return [a, b];
}
function linesIntersectAt(a, b) {
const A1 = a[1][1] - a[0][1];
const B1 = a[0][0] - a[1][0];
const A2 = b[1][1] - b[0][1];
const B2 = b[0][0] - b[1][0];
const D = A1 * B2 - A2 * B1;
if (D !== 0) {
const C1 = A1 * a[0][0] + B1 * a[0][1];
const C2 = A2 * b[0][0] + B2 * b[0][1];
return pointFrom((C1 * B2 - C2 * B1) / D, (A1 * C2 - A2 * C1) / D);
}
return null;
}
// src/polygon.ts
init_define_import_meta_env();
// src/segment.ts
init_define_import_meta_env();
function lineSegment(a, b) {
return [a, b];
}
var isLineSegment = (segment) => Array.isArray(segment) && segment.length === 2 && isPoint(segment[0]) && isPoint(segment[0]);
var lineSegmentRotate = (l, angle, origin) => {
return lineSegment(
pointRotateRads(l[0], origin || pointCenter(l[0], l[1]), angle),
pointRotateRads(l[1], origin || pointCenter(l[0], l[1]), angle)
);
};
var segmentsIntersectAt = (a, b) => {
const a0 = vectorFromPoint(a[0]);
const a1 = vectorFromPoint(a[1]);
const b0 = vectorFromPoint(b[0]);
const b1 = vectorFromPoint(b[1]);
const r = vectorSubtract(a1, a0);
const s = vectorSubtract(b1, b0);
const denominator = vectorCross(r, s);
if (denominator === 0) {
return null;
}
const i = vectorSubtract(vectorFromPoint(b[0]), vectorFromPoint(a[0]));
const u = vectorCross(i, r) / denominator;
const t = vectorCross(i, s) / denominator;
if (u === 0) {
return null;
}
const p = vectorAdd(a0, vectorScale(r, t));
if (t >= 0 && t < 1 && u >= 0 && u < 1) {
return pointFromVector(p);
}
return null;
};
var pointOnLineSegment = (point, line2, threshold = PRECISION) => {
const distance = distanceToLineSegment(point, line2);
if (distance === 0) {
return true;
}
return distance < threshold;
};
var distanceToLineSegment = (point, line2) => {
const [x, y] = point;
const [[x1, y1], [x2, y2]] = line2;
const A = x - x1;
const B = y - y1;
const C = x2 - x1;
const D = y2 - y1;
const dot = A * C + B * D;
const len_sq = C * C + D * D;
let param = -1;
if (len_sq !== 0) {
param = dot / len_sq;
}
let xx;
let yy;
if (param < 0) {
xx = x1;
yy = y1;
} else if (param > 1) {
xx = x2;
yy = y2;
} else {
xx = x1 + param * C;
yy = y1 + param * D;
}
const dx = x - xx;
const dy = y - yy;
return Math.sqrt(dx * dx + dy * dy);
};
function lineSegmentIntersectionPoints(l, s, threshold) {
const candidate = linesIntersectAt(line(l[0], l[1]), line(s[0], s[1]));
if (!candidate || !pointOnLineSegment(candidate, s, threshold) || !pointOnLineSegment(candidate, l, threshold)) {
return null;
}
return candidate;
}
function lineSegmentsDistance(s1, s2) {
if (lineSegmentIntersectionPoints(s1, s2)) {
return 0;
}
return Math.min(
distanceToLineSegment(s1[0], s2),
distanceToLineSegment(s1[1], s2),
distanceToLineSegment(s2[0], s1),
distanceToLineSegment(s2[1], s1)
);
}
// src/polygon.ts
function polygon(...points) {
return polygonClose(points);
}
function polygonFromPoints(points) {
return polygonClose(points);
}
var polygonIncludesPoint = (point, polygon2) => {
const x = point[0];
const y = point[1];
let inside = false;
for (let i = 0, j = polygon2.length - 1; i < polygon2.length; j = i++) {
const xi = polygon2[i][0];
const yi = polygon2[i][1];
const xj = polygon2[j][0];
const yj = polygon2[j][1];
if ((yi > y && yj <= y || yi <= y && yj > y) && x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
inside = !inside;
}
}
return inside;
};
var polygonIncludesPointNonZero = (point, polygon2) => {
const [x, y] = point;
let windingNumber = 0;
for (let i = 0; i < polygon2.length; i++) {
const j = (i + 1) % polygon2.length;
const [xi, yi] = polygon2[i];
const [xj, yj] = polygon2[j];
if (yi <= y) {
if (yj > y) {
if ((xj - xi) * (y - yi) - (x - xi) * (yj - yi) > 0) {
windingNumber++;
}
}
} else if (yj <= y) {
if ((xj - xi) * (y - yi) - (x - xi) * (yj - yi) < 0) {
windingNumber--;
}
}
}
return windingNumber !== 0;
};
var pointOnPolygon = (p, poly, threshold = PRECISION) => {
let on = false;
for (let i = 0, l = poly.length - 1; i < l; i++) {
if (pointOnLineSegment(p, lineSegment(poly[i], poly[i + 1]), threshold)) {
on = true;
break;
}
}
return on;
};
function polygonClose(polygon2) {
return polygonIsClosed(polygon2) ? polygon2 : [...polygon2, polygon2[0]];
}
function polygonIsClosed(polygon2) {
return pointsEqual(polygon2[0], polygon2[polygon2.length - 1]);
}
// src/range.ts
init_define_import_meta_env();
// ../common/src/index.ts
init_define_import_meta_env();
// ../common/src/binary-heap.ts
init_define_import_meta_env();
// ../common/src/colors.ts
init_define_import_meta_env();
// ../../node_modules/open-color/open-color.json
var open_color_default = {
white: "#ffffff",
black: "#000000",
gray: [
"#f8f9fa",
"#f1f3f5",
"#e9ecef",
"#dee2e6",
"#ced4da",
"#adb5bd",
"#868e96",
"#495057",
"#343a40",
"#212529"
],
red: [
"#fff5f5",
"#ffe3e3",
"#ffc9c9",
"#ffa8a8",
"#ff8787",
"#ff6b6b",
"#fa5252",
"#f03e3e",
"#e03131",
"#c92a2a"
],
pink: [
"#fff0f6",
"#ffdeeb",
"#fcc2d7",
"#faa2c1",
"#f783ac",
"#f06595",
"#e64980",
"#d6336c",
"#c2255c",
"#a61e4d"
],
grape: [
"#f8f0fc",
"#f3d9fa",
"#eebefa",
"#e599f7",
"#da77f2",
"#cc5de8",
"#be4bdb",
"#ae3ec9",
"#9c36b5",
"#862e9c"
],
violet: [
"#f3f0ff",
"#e5dbff",
"#d0bfff",
"#b197fc",
"#9775fa",
"#845ef7",
"#7950f2",
"#7048e8",
"#6741d9",
"#5f3dc4"
],
indigo: [
"#edf2ff",
"#dbe4ff",
"#bac8ff",
"#91a7ff",
"#748ffc",
"#5c7cfa",
"#4c6ef5",
"#4263eb",
"#3b5bdb",
"#364fc7"
],
blue: [
"#e7f5ff",
"#d0ebff",
"#a5d8ff",
"#74c0fc",
"#4dabf7",
"#339af0",
"#228be6",
"#1c7ed6",
"#1971c2",
"#1864ab"
],
cyan: [
"#e3fafc",
"#c5f6fa",
"#99e9f2",
"#66d9e8",
"#3bc9db",
"#22b8cf",
"#15aabf",
"#1098ad",
"#0c8599",
"#0b7285"
],
teal: [
"#e6fcf5",
"#c3fae8",
"#96f2d7",
"#63e6be",
"#38d9a9",
"#20c997",
"#12b886",
"#0ca678",
"#099268",
"#087f5b"
],
green: [
"#ebfbee",
"#d3f9d8",
"#b2f2bb",
"#8ce99a",
"#69db7c",
"#51cf66",
"#40c057",
"#37b24d",
"#2f9e44",
"#2b8a3e"
],
lime: [
"#f4fce3",
"#e9fac8",
"#d8f5a2",
"#c0eb75",
"#a9e34b",
"#94d82d",
"#82c91e",
"#74b816",
"#66a80f",
"#5c940d"
],
yellow: [
"#fff9db",
"#fff3bf",
"#ffec99",
"#ffe066",
"#ffd43b",
"#fcc419",
"#fab005",
"#f59f00",
"#f08c00",
"#e67700"
],
orange: [
"#fff4e6",
"#ffe8cc",
"#ffd8a8",
"#ffc078",
"#ffa94d",
"#ff922b",
"#fd7e14",
"#f76707",
"#e8590c",
"#d9480f"
]
};
// ../common/src/colors.ts
var pick = (source, keys) => {
return keys.reduce((acc, key) => {
if (key in source) {
acc[key] = source[key];
}
return acc;
}, {});
};
var DEFAULT_ELEMENT_STROKE_COLOR_INDEX = 4;
var DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX = 1;
var ELEMENTS_PALETTE_SHADE_INDEXES = [0, 2, 4, 6, 8];
var getSpecificColorShades = (color, indexArr) => {
return indexArr.map((index) => open_color_default[color][index]);
};
var COLOR_PALETTE = {
transparent: "transparent",
black: "#1e1e1e",
white: "#ffffff",
// open-colors
gray: getSpecificColorShades("gray", ELEMENTS_PALETTE_SHADE_INDEXES),
red: getSpecificColorShades("red", ELEMENTS_PALETTE_SHADE_INDEXES),
pink: getSpecificColorShades("pink", ELEMENTS_PALETTE_SHADE_INDEXES),
grape: getSpecificColorShades("grape", ELEMENTS_PALETTE_SHADE_INDEXES),
violet: getSpecificColorShades("violet", ELEMENTS_PALETTE_SHADE_INDEXES),
blue: getSpecificColorShades("blue", ELEMENTS_PALETTE_SHADE_INDEXES),
cyan: getSpecificColorShades("cyan", ELEMENTS_PALETTE_SHADE_INDEXES),
teal: getSpecificColorShades("teal", ELEMENTS_PALETTE_SHADE_INDEXES),
green: getSpecificColorShades("green", ELEMENTS_PALETTE_SHADE_INDEXES),
yellow: getSpecificColorShades("yellow", ELEMENTS_PALETTE_SHADE_INDEXES),
orange: getSpecificColorShades("orange", ELEMENTS_PALETTE_SHADE_INDEXES),
// radix bronze shades 3,5,7,9,11
bronze: ["#f8f1ee", "#eaddd7", "#d2bab0", "#a18072", "#846358"]
};
var COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [
"cyan",
"blue",
"violet",
"grape",
"pink",
"green",
"teal",
"yellow",
"orange",
"red"
]);
var DEFAULT_ELEMENT_STROKE_PICKS = [
COLOR_PALETTE.black,
COLOR_PALETTE.red[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
COLOR_PALETTE.green[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
COLOR_PALETTE.blue[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
COLOR_PALETTE.yellow[DEFAULT_ELEMENT_STROKE_COLOR_INDEX]
];
var DEFAULT_ELEMENT_BACKGROUND_PICKS = [
COLOR_PALETTE.transparent,
COLOR_PALETTE.red[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
COLOR_PALETTE.green[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
COLOR_PALETTE.blue[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
COLOR_PALETTE.yellow[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX]
];
var DEFAULT_CANVAS_BACKGROUND_PICKS = [
COLOR_PALETTE.white,
// radix slate2
"#f8f9fa",
// radix blue2
"#f5faff",
// radix yellow2
"#fffce8",
// radix bronze2
"#fdf8f6"
];
var DEFAULT_ELEMENT_STROKE_COLOR_PALETTE = {
// 1st row
transparent: COLOR_PALETTE.transparent,
white: COLOR_PALETTE.white,
gray: COLOR_PALETTE.gray,
black: COLOR_PALETTE.black,
bronze: COLOR_PALETTE.bronze,
// rest
...COMMON_ELEMENT_SHADES
};
var DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = {
transparent: COLOR_PALETTE.transparent,
white: COLOR_PALETTE.white,
gray: COLOR_PALETTE.gray,
black: COLOR_PALETTE.black,
bronze: COLOR_PALETTE.bronze,
...COMMON_ELEMENT_SHADES
};
// ../common/src/constants.ts
init_define_import_meta_env();
var isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
var isWindows = /^Win/.test(navigator.platform);
var isAndroid = /\b(android)\b/i.test(navigator.userAgent);
var isFirefox = typeof window !== "undefined" && "netscape" in window && navigator.userAgent.indexOf("rv:") > 1 && navigator.userAgent.indexOf("Gecko") > 1;
var isChrome = navigator.userAgent.indexOf("Chrome") !== -1;
var isSafari = !isChrome && navigator.userAgent.indexOf("Safari") !== -1;
var isIOS = /iPad|iPhone/i.test(navigator.platform) || // iPadOS 13+
navigator.userAgent.includes("Mac") && "ontouchend" in document;
var isMobile = isIOS || /android|webos|ipod|blackberry|iemobile|opera mini/i.test(
navigator.userAgent
) || /android|ios|ipod|blackberry|windows phone/i.test(navigator.platform);
var supportsResizeObserver = typeof window !== "undefined" && "ResizeObserver" in window;
var SHIFT_LOCKING_ANGLE = Math.PI / 12;
var CJK_HAND_DRAWN_FALLBACK_FONT = "Xiaolai";
var WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
var FONT_FAMILY = {
Virgil: 1,
Helvetica: 2,
Cascadia: 3,
// leave 4 unused as it was historically used for Assistant (which we don't use anymore) or custom font (Obsidian)
Excalifont: 5,
Nunito: 6,
"Lilita One": 7,
"Comic Shanns": 8,
"Liberation Sans": 9,
Assistant: 10
};
var SANS_SERIF_GENERIC_FONT = "sans-serif";
var MONOSPACE_GENERIC_FONT = "monospace";
var FONT_FAMILY_GENERIC_FALLBACKS = {
[SANS_SERIF_GENERIC_FONT]: 998,
[MONOSPACE_GENERIC_FONT]: 999
};
var FONT_FAMILY_FALLBACKS = {
[CJK_HAND_DRAWN_FALLBACK_FONT]: 100,
...FONT_FAMILY_GENERIC_FALLBACKS,
[WINDOWS_EMOJI_FALLBACK_FONT]: 1e3
};
var DEFAULT_FONT_FAMILY = FONT_FAMILY.Excalifont;
var DEFAULT_TRANSFORM_HANDLE_SPACING = 2;
var SIDE_RESIZING_THRESHOLD = 2 * DEFAULT_TRANSFORM_HANDLE_SPACING;
var EPSILON = 1e-5;
var DEFAULT_COLLISION_THRESHOLD = 2 * SIDE_RESIZING_THRESHOLD - EPSILON;
var IMAGE_MIME_TYPES = {
svg: "image/svg+xml",
png: "image/png",
jpg: "image/jpeg",
gif: "image/gif",
webp: "image/webp",
bmp: "image/bmp",
ico: "image/x-icon",
avif: "image/avif",
jfif: "image/jfif"
};
var STRING_MIME_TYPES = {
text: "text/plain",
html: "text/html",
json: "application/json",
// excalidraw data
excalidraw: "application/vnd.excalidraw+json",
excalidrawlib: "application/vnd.excalidrawlib+json"
};
var MIME_TYPES = {
...STRING_MIME_TYPES,
// image-encoded excalidraw data
"excalidraw.svg": "image/svg+xml",
"excalidraw.png": "image/png",
// binary
binary: "application/octet-stream",
// image
...IMAGE_MIME_TYPES
};
var ALLOWED_PASTE_MIME_TYPES = [
MIME_TYPES.text,
MIME_TYPES.html,
...Object.values(IMAGE_MIME_TYPES)
];
var MQ_MAX_MOBILE = 599;
var MQ_MIN_TABLET = MQ_MAX_MOBILE + 1;
var MAX_ALLOWED_FILE_BYTES = 4 * 1024 * 1024;
var ROUGHNESS = {
architect: 0,
artist: 1,
cartoonist: 2
};
var DEFAULT_ELEMENT_PROPS = {
strokeColor: COLOR_PALETTE.black,
backgroundColor: COLOR_PALETTE.transparent,
fillStyle: "solid",
strokeWidth: 2,
strokeStyle: "solid",
roughness: ROUGHNESS.artist,
opacity: 100,
locked: false
};
var ORIG_ID = Symbol.for("__test__originalId__");
// ../common/src/font-metadata.ts
init_define_import_meta_env();
var FONT_METADATA = {
[FONT_FAMILY.Excalifont]: {
metrics: {
unitsPerEm: 1e3,
ascender: 886,
descender: -374,
lineHeight: 1.25
}
},
[FONT_FAMILY.Nunito]: {
metrics: {
unitsPerEm: 1e3,
ascender: 1011,
descender: -353,
lineHeight: 1.25
}
},
[FONT_FAMILY["Lilita One"]]: {
metrics: {
unitsPerEm: 1e3,
ascender: 923,
descender: -220,
lineHeight: 1.15
}
},
[FONT_FAMILY["Comic Shanns"]]: {
metrics: {
unitsPerEm: 1e3,
ascender: 750,
descender: -250,
lineHeight: 1.25
}
},
[FONT_FAMILY.Virgil]: {
metrics: {
unitsPerEm: 1e3,
ascender: 886,
descender: -374,
lineHeight: 1.25
},
deprecated: true
},
[FONT_FAMILY.Helvetica]: {
metrics: {
unitsPerEm: 2048,
ascender: 1577,
descender: -471,
lineHeight: 1.15
},
deprecated: true,
local: true
},
[FONT_FAMILY.Cascadia]: {
metrics: {
unitsPerEm: 2048,
ascender: 1900,
descender: -480,
lineHeight: 1.2
},
deprecated: true
},
[FONT_FAMILY["Liberation Sans"]]: {
metrics: {
unitsPerEm: 2048,
ascender: 1854,
descender: -434,
lineHeight: 1.15
},
private: true
},
[FONT_FAMILY.Assistant]: {
metrics: {
unitsPerEm: 2048,
ascender: 1021,
descender: -287,
lineHeight: 1.25
},
private: true
},
[FONT_FAMILY_FALLBACKS.Xiaolai]: {
metrics: {
unitsPerEm: 1e3,
ascender: 880,
descender: -144,
lineHeight: 1.25
},
fallback: true
},
[FONT_FAMILY_FALLBACKS["Segoe UI Emoji"]]: {
metrics: {
// reusing Excalifont metrics
unitsPerEm: 1e3,
ascender: 886,
descender: -374,
lineHeight: 1.25
},
local: true,
fallback: true
}
};
// ../common/src/queue.ts
init_define_import_meta_env();
// ../common/src/keys.ts
init_define_import_meta_env();
var CODES = {
EQUAL: "Equal",
MINUS: "Minus",
NUM_ADD: "NumpadAdd",
NUM_SUBTRACT: "NumpadSubtract",
NUM_ZERO: "Numpad0",
BRACKET_RIGHT: "BracketRight",
BRACKET_LEFT: "BracketLeft",
ONE: "Digit1",
TWO: "Digit2",
THREE: "Digit3",
NINE: "Digit9",
QUOTE: "Quote",
ZERO: "Digit0",
SLASH: "Slash",
C: "KeyC",
D: "KeyD",
H: "KeyH",
V: "KeyV",
Z: "KeyZ",
Y: "KeyY",
R: "KeyR",
S: "KeyS"
};
var KEYS = {
ARROW_DOWN: "ArrowDown",
ARROW_LEFT: "ArrowLeft",
ARROW_RIGHT: "ArrowRight",
ARROW_UP: "ArrowUp",
PAGE_UP: "PageUp",
PAGE_DOWN: "PageDown",
BACKSPACE: "Backspace",
ALT: "Alt",
CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey",
DELETE: "Delete",
ENTER: "Enter",
ESCAPE: "Escape",
QUESTION_MARK: "?",
SPACE: " ",
TAB: "Tab",
CHEVRON_LEFT: "<",
CHEVRON_RIGHT: ">",
PERIOD: ".",
COMMA: ",",
SUBTRACT: "-",
SLASH: "/",
A: "a",
C: "c",
D: "d",
E: "e",
F: "f",
G: "g",
H: "h",
I: "i",
L: "l",
O: "o",
P: "p",
Q: "q",
R: "r",
S: "s",
T: "t",
V: "v",
X: "x",
Y: "y",
Z: "z",
K: "k",
W: "w",
0: "0",
1: "1",
2: "2",
3: "3",
4: "4",
5: "5",
6: "6",
7: "7",
8: "8",
9: "9"
};
var KeyCodeMap = /* @__PURE__ */ new Map([
[KEYS.Z, CODES.Z],
[KEYS.Y, CODES.Y]
]);
// ../common/src/points.ts
init_define_import_meta_env();
// ../common/src/promise-pool.ts
init_define_import_meta_env();
var import_es6_promise_pool = __toESM(require_es6_promise_pool(), 1);
// ../common/src/random.ts
init_define_import_meta_env();
// ../../node_modules/roughjs/bin/math.js
init_define_import_meta_env();
var Random = class {
constructor(seed) {
this.seed = seed;
}
next() {
if (this.seed) {
return (2 ** 31 - 1 & (this.seed = Math.imul(48271, this.seed))) / 2 ** 31;
} else {
return Math.random();
}
}
};
// ../common/src/utils.ts
init_define_import_meta_env();
var RS_LTR_CHARS = "A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u0300-\u0590\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF";
var RS_RTL_CHARS = "\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC";
var RE_RTL_CHECK = new RegExp(`^[^${RS_LTR_CHARS}]*[${RS_RTL_CHARS}]`);
var toBrandedType = (value) => {
return value;
};
// ../common/src/random.ts
var random = new Random(Date.now());
// ../common/src/url.ts
init_define_import_meta_env();
var import_sanitize_url = __toESM(require_dist(), 1);
// ../common/src/emitter.ts
init_define_import_meta_env();
// src/range.ts
function rangeInclusive(start, end) {
return toBrandedType([start, end]);
}
function rangeInclusiveFromPair(pair) {
return toBrandedType(pair);
}
var rangesOverlap = ([a0, a1], [b0, b1]) => {
if (a0 <= b0) {
return a1 >= b0;
}
if (a0 >= b0) {
return b1 >= a0;
}
return false;
};
var rangeIntersection = ([a0, a1], [b0, b1]) => {
const rangeStart = Math.max(a0, b0);
const rangeEnd = Math.min(a1, b1);
if (rangeStart <= rangeEnd) {
return toBrandedType([rangeStart, rangeEnd]);
}
return null;
};
var rangeIncludesValue = (value, [min, max]) => {
return value >= min && value <= max;
};
// src/rectangle.ts
init_define_import_meta_env();
function rectangle(topLeft, bottomRight) {
return [topLeft, bottomRight];
}
function rectangleFromNumberSequence(minX, minY, maxX, maxY) {
return rectangle(pointFrom(minX, minY), pointFrom(maxX, maxY));
}
function rectangleIntersectLineSegment(r, l) {
return [
lineSegment(r[0], pointFrom(r[1][0], r[0][1])),
lineSegment(pointFrom(r[1][0], r[0][1]), r[1]),
lineSegment(r[1], pointFrom(r[0][0], r[1][1])),
lineSegment(pointFrom(r[0][0], r[1][1]), r[0])
].map((s) => lineSegmentIntersectionPoints(l, s)).filter((i) => !!i);
}
function rectangleIntersectRectangle(rectangle1, rectangle2) {
const [[minX1, minY1], [maxX1, maxY1]] = rectangle1;
const [[minX2, minY2], [maxX2, maxY2]] = rectangle2;
return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2;
}
// src/triangle.ts
init_define_import_meta_env();
function triangleIncludesPoint([a, b, c], p) {
const triangleSign = (p1, p2, p3) => (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
const d1 = triangleSign(p, a, b);
const d2 = triangleSign(p, b, c);
const d3 = triangleSign(p, c, a);
const has_neg = d1 < 0 || d2 < 0 || d3 < 0;
const has_pos = d1 > 0 || d2 > 0 || d3 > 0;
return !(has_neg && has_pos);
}
// src/types.ts
init_define_import_meta_env();
export {
PRECISION,
average,
bezierEquation,
cartesian2Polar,
clamp,
curve,
curveCatmullRomCubicApproxPoints,
curveCatmullRomQuadraticApproxPoints,
curveClosestPoint,
curveIntersectLineSegment,
curveLength,
curveLengthAtParameter,
curveOffsetPoints,
curvePointAtLength,
curvePointDistance,
curveTangent,
degreesToRadians,
distanceToLineSegment,
ellipse,
ellipseDistanceFromPoint,
ellipseIncludesPoint,
ellipseLineIntersectionPoints,
ellipseSegmentInterceptPoints,
ellipseTouchesPoint,
isCloseTo,
isCurve,
isFiniteNumber,
isLineSegment,
isPoint,
isPointWithinBounds,
isRightAngleRads,
isVector,
line,
lineSegment,
lineSegmentIntersectionPoints,
lineSegmentRotate,
lineSegmentsDistance,
linesIntersectAt,
normalizeRadians,
offsetPointsForQuadraticBezier,
pointCenter,
pointDistance,
pointDistanceSq,
pointFrom,
pointFromArray,
pointFromPair,
pointFromVector,
pointOnLineSegment,
pointOnPolygon,
pointRotateDegs,
pointRotateRads,
pointScaleFromOrigin,
pointTranslate,
pointsEqual,
polygon,
polygonFromPoints,
polygonIncludesPoint,
polygonIncludesPointNonZero,
radiansBetweenAngles,
radiansDifference,
radiansToDegrees,
rangeIncludesValue,
rangeInclusive,
rangeInclusiveFromPair,
rangeIntersection,
rangesOverlap,
rectangle,
rectangleFromNumberSequence,
rectangleIntersectLineSegment,
rectangleIntersectRectangle,
round,
roundToStep,
segmentsIntersectAt,
triangleIncludesPoint,
vector,
vectorAdd,
vectorCross,
vectorDot,
vectorFromPoint,
vectorMagnitude,
vectorMagnitudeSq,
vectorNormal,
vectorNormalize,
vectorScale,
vectorSubtract
};
//# sourceMappingURL=index.js.map