@sketch-ruler/core 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/AGENTS.md +145 -0
  2. package/README.md +230 -0
  3. package/lib/engine/coordinate.d.ts +38 -0
  4. package/lib/engine/coordinate.d.ts.map +1 -0
  5. package/lib/engine/index.d.ts +7 -0
  6. package/lib/engine/index.d.ts.map +1 -0
  7. package/lib/engine/matrix.d.ts +45 -0
  8. package/lib/engine/matrix.d.ts.map +1 -0
  9. package/lib/engine/minimap-engine.d.ts +64 -0
  10. package/lib/engine/minimap-engine.d.ts.map +1 -0
  11. package/lib/engine/transform-engine.d.ts +78 -0
  12. package/lib/engine/transform-engine.d.ts.map +1 -0
  13. package/lib/index.cjs +1 -0
  14. package/lib/index.d.ts +23 -0
  15. package/lib/index.d.ts.map +1 -0
  16. package/lib/index.iife.js +1 -0
  17. package/lib/index.js +950 -0
  18. package/lib/index.umd.cjs +1 -0
  19. package/lib/managers/canvas-manager.d.ts +61 -0
  20. package/lib/managers/canvas-manager.d.ts.map +1 -0
  21. package/lib/plugins/index.d.ts +2 -0
  22. package/lib/plugins/index.d.ts.map +1 -0
  23. package/lib/plugins/plugin-manager.d.ts +33 -0
  24. package/lib/plugins/plugin-manager.d.ts.map +1 -0
  25. package/lib/scale/index.d.ts +18 -0
  26. package/lib/scale/index.d.ts.map +1 -0
  27. package/lib/scale/tick-config.d.ts +15 -0
  28. package/lib/scale/tick-config.d.ts.map +1 -0
  29. package/lib/snap/snap-engine.d.ts +50 -0
  30. package/lib/snap/snap-engine.d.ts.map +1 -0
  31. package/lib/state/index.d.ts +3 -0
  32. package/lib/state/index.d.ts.map +1 -0
  33. package/lib/state/line-manager.d.ts +20 -0
  34. package/lib/state/line-manager.d.ts.map +1 -0
  35. package/lib/state/ruler-state.d.ts +49 -0
  36. package/lib/state/ruler-state.d.ts.map +1 -0
  37. package/lib/types/index.d.ts +164 -0
  38. package/lib/types/index.d.ts.map +1 -0
  39. package/lib/utils/id-utils.d.ts +3 -0
  40. package/lib/utils/id-utils.d.ts.map +1 -0
  41. package/lib/utils/line-utils.d.ts +40 -0
  42. package/lib/utils/line-utils.d.ts.map +1 -0
  43. package/package.json +66 -0
package/lib/index.js ADDED
@@ -0,0 +1,950 @@
1
+ /*!@sketch-ruler/core v3.0.0-beta.0 2026-5-21*/
2
+ //#region src/engine/matrix.ts
3
+ function e() {
4
+ return new Float64Array([
5
+ 1,
6
+ 0,
7
+ 0,
8
+ 1,
9
+ 0,
10
+ 0
11
+ ]);
12
+ }
13
+ function t(e, t, n) {
14
+ return new Float64Array([
15
+ e,
16
+ 0,
17
+ 0,
18
+ e,
19
+ t,
20
+ n
21
+ ]);
22
+ }
23
+ function n(e, t) {
24
+ let n = new Float64Array(6);
25
+ return n[0] = e[0] * t[0] + e[2] * t[1], n[1] = e[1] * t[0] + e[3] * t[1], n[2] = e[0] * t[2] + e[2] * t[3], n[3] = e[1] * t[2] + e[3] * t[3], n[4] = e[0] * t[4] + e[2] * t[5] + e[4], n[5] = e[1] * t[4] + e[3] * t[5] + e[5], n;
26
+ }
27
+ function r(e) {
28
+ let t = e[0] * e[3] - e[1] * e[2];
29
+ if (Math.abs(t) < 1e-10) return null;
30
+ let n = 1 / t, r = new Float64Array(6);
31
+ return r[0] = e[3] * n, r[1] = -e[1] * n, r[2] = -e[2] * n, r[3] = e[0] * n, r[4] = (e[2] * e[5] - e[3] * e[4]) * n, r[5] = (e[1] * e[4] - e[0] * e[5]) * n, r;
32
+ }
33
+ function i(e) {
34
+ return {
35
+ scale: e[0],
36
+ translateX: e[4],
37
+ translateY: e[5]
38
+ };
39
+ }
40
+ function a(e) {
41
+ return `matrix(${e[0]}, ${e[1]}, ${e[2]}, ${e[3]}, ${e[4]}, ${e[5]})`;
42
+ }
43
+ function o(e, t, n = 1e-6) {
44
+ for (let r = 0; r < 6; r++) if (Math.abs(e[r] - t[r]) > n) return !1;
45
+ return !0;
46
+ }
47
+ //#endregion
48
+ //#region src/engine/coordinate.ts
49
+ function s(e, t, n) {
50
+ let r = e[0] * e[3] - e[1] * e[2];
51
+ if (Math.abs(r) < 1e-10) return {
52
+ x: 0,
53
+ y: 0
54
+ };
55
+ let i = 1 / r, a = t - e[4], o = n - e[5];
56
+ return {
57
+ x: (e[3] * a - e[2] * o) * i,
58
+ y: (-e[1] * a + e[0] * o) * i
59
+ };
60
+ }
61
+ function c(e, t, n) {
62
+ return {
63
+ x: e[0] * t + e[2] * n + e[4],
64
+ y: e[1] * t + e[3] * n + e[5]
65
+ };
66
+ }
67
+ function l(e, t) {
68
+ return t.map((t) => s(e, t.x, t.y));
69
+ }
70
+ function u(e, t) {
71
+ return t.map((t) => c(e, t.x, t.y));
72
+ }
73
+ function d(e, t, n = "contain", r = 0) {
74
+ if (e.width <= 0 || e.height <= 0) return {
75
+ scale: 1,
76
+ x: t.x,
77
+ y: t.y
78
+ };
79
+ let i = {
80
+ x: t.x + t.width * r / 2,
81
+ y: t.y + t.height * r / 2,
82
+ width: t.width * (1 - r),
83
+ height: t.height * (1 - r)
84
+ }, a = i.width / e.width, o = i.height / e.height, s;
85
+ s = n === "contain" ? Math.min(a, o) : n === "cover" ? Math.max(a, o) : 1;
86
+ let c = i.x + (i.width - e.width * s) / 2, l = i.y + (i.height - e.height * s) / 2;
87
+ return {
88
+ scale: s,
89
+ x: c,
90
+ y: l
91
+ };
92
+ }
93
+ //#endregion
94
+ //#region src/engine/transform-engine.ts
95
+ var f = class {
96
+ matrix;
97
+ targetState;
98
+ currentState;
99
+ minZoom;
100
+ maxZoom;
101
+ enableAnimation;
102
+ animationDuration;
103
+ animationMode;
104
+ dampingRatio;
105
+ naturalFrequency;
106
+ timeConstant;
107
+ pendingTransform = !1;
108
+ rafId = null;
109
+ callbacks = /* @__PURE__ */ new Set();
110
+ lastFrameTime = 0;
111
+ velocity = {
112
+ x: 0,
113
+ y: 0,
114
+ scale: 0
115
+ };
116
+ constructor(e = {
117
+ x: 0,
118
+ y: 0,
119
+ scale: 1
120
+ }, n = {}) {
121
+ this.minZoom = n.minZoom ?? .1, this.maxZoom = n.maxZoom ?? 10, this.enableAnimation = n.enableAnimation ?? !1, this.animationDuration = n.animationDuration ?? 200, this.animationMode = n.animationMode ?? "ease-out", this.dampingRatio = n.dampingRatio ?? .8, this.naturalFrequency = n.naturalFrequency ?? 20, this.timeConstant = n.timeConstant ?? 80;
122
+ let r = this.clampScale(e.scale);
123
+ this.currentState = {
124
+ ...e,
125
+ scale: r
126
+ }, this.targetState = { ...this.currentState }, this.matrix = t(r, e.x, e.y);
127
+ }
128
+ onUpdate(e) {
129
+ return this.callbacks.add(e), e({ ...this.currentState }), () => {
130
+ this.callbacks.delete(e);
131
+ };
132
+ }
133
+ setTransform(e) {
134
+ e.scale !== void 0 && (this.targetState.scale = this.clampScale(e.scale)), e.x !== void 0 && (this.targetState.x = e.x), e.y !== void 0 && (this.targetState.y = e.y), this.enableAnimation ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify());
135
+ }
136
+ panBy(e, t) {
137
+ this.targetState.x += e, this.targetState.y += t, this.enableAnimation ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify());
138
+ }
139
+ zoomBy(e, t, n) {
140
+ let r = this.targetState.scale, i = this.clampScale(r + e), a = i / r;
141
+ Math.abs(a - 1) < 1e-6 || (this.targetState.x = t - (t - this.targetState.x) * a, this.targetState.y = n - (n - this.targetState.y) * a, this.targetState.scale = i, this.enableAnimation ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify()));
142
+ }
143
+ zoomTo(e, t, n) {
144
+ let r = this.clampScale(e) - this.targetState.scale;
145
+ this.zoomBy(r, t, n);
146
+ }
147
+ toWorldPoint(e, t) {
148
+ return s(this.matrix, e, t);
149
+ }
150
+ toScreenPoint(e, t) {
151
+ return c(this.matrix, e, t);
152
+ }
153
+ getState() {
154
+ return { ...this.currentState };
155
+ }
156
+ getMatrix() {
157
+ return new Float64Array(this.matrix);
158
+ }
159
+ destroy() {
160
+ this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.callbacks.clear();
161
+ }
162
+ clampScale(e) {
163
+ return Math.max(this.minZoom, Math.min(this.maxZoom, e));
164
+ }
165
+ updateMatrix() {
166
+ this.matrix = t(this.currentState.scale, this.currentState.x, this.currentState.y);
167
+ }
168
+ scheduleUpdate() {
169
+ this.pendingTransform = !0, this.rafId === null && (this.rafId = requestAnimationFrame((e) => this.onFrame(e)));
170
+ }
171
+ onFrame(e) {
172
+ if (this.rafId = null, !this.pendingTransform) return;
173
+ if (this.pendingTransform = !1, !this.enableAnimation) {
174
+ this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify();
175
+ return;
176
+ }
177
+ let t = this.lastFrameTime === 0 ? 16 : e - this.lastFrameTime;
178
+ this.lastFrameTime = e;
179
+ let n = t / 1e3;
180
+ switch (this.animationMode) {
181
+ case "direct":
182
+ this.currentState = { ...this.targetState };
183
+ break;
184
+ case "ease-out": {
185
+ let e = 1 - (1 - Math.min(1, t / this.animationDuration)) ** 3;
186
+ this.currentState.x = this.lerp(this.currentState.x, this.targetState.x, e), this.currentState.y = this.lerp(this.currentState.y, this.targetState.y, e), this.currentState.scale = this.lerp(this.currentState.scale, this.targetState.scale, e);
187
+ break;
188
+ }
189
+ case "exponential": {
190
+ let e = this.timeConstant / 1e3, t = 1 - Math.exp(-n / e);
191
+ this.currentState.x = this.lerp(this.currentState.x, this.targetState.x, t), this.currentState.y = this.lerp(this.currentState.y, this.targetState.y, t), this.currentState.scale = this.lerp(this.currentState.scale, this.targetState.scale, t);
192
+ break;
193
+ }
194
+ case "damped": {
195
+ let e = this.dampingRatio, t = this.naturalFrequency, r = t * t, i = r * (this.targetState.x - this.currentState.x) - 2 * e * t * this.velocity.x;
196
+ this.velocity.x += i * n, this.currentState.x += this.velocity.x * n;
197
+ let a = r * (this.targetState.y - this.currentState.y) - 2 * e * t * this.velocity.y;
198
+ this.velocity.y += a * n, this.currentState.y += this.velocity.y * n;
199
+ let o = r * (this.targetState.scale - this.currentState.scale) - 2 * e * t * this.velocity.scale;
200
+ this.velocity.scale += o * n, this.currentState.scale += this.velocity.scale * n;
201
+ break;
202
+ }
203
+ }
204
+ this.currentState.scale = this.clampScale(this.currentState.scale);
205
+ let r = this.animationMode === "damped" ? .01 : 1e-4, i = Math.abs(this.currentState.x - this.targetState.x) > r || Math.abs(this.currentState.y - this.targetState.y) > r || Math.abs(this.currentState.scale - this.targetState.scale) > r || this.animationMode === "damped" && (Math.abs(this.velocity.x) > r || Math.abs(this.velocity.y) > r || Math.abs(this.velocity.scale) > r);
206
+ this.updateMatrix(), this.notify(), i ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.velocity = {
207
+ x: 0,
208
+ y: 0,
209
+ scale: 0
210
+ }, this.lastFrameTime = 0);
211
+ }
212
+ lerp(e, t, n) {
213
+ return e + (t - e) * n;
214
+ }
215
+ notify() {
216
+ let e = { ...this.currentState };
217
+ this.callbacks.forEach((t) => t(e));
218
+ }
219
+ };
220
+ //#endregion
221
+ //#region src/state/ruler-state.ts
222
+ function p() {
223
+ return {
224
+ lines: [],
225
+ palette: {
226
+ bgColor: "#f6f7f9",
227
+ tickColor: "#BABBBC",
228
+ labelColor: "#7D8694",
229
+ guideLineColor: "#51d6a9",
230
+ guideLineLockedColor: "#d4d7dc",
231
+ hoverBg: "#000",
232
+ hoverColor: "#fff",
233
+ borderColor: "#eeeeef",
234
+ shadowColor: "#e9f7fe",
235
+ guideLineStyle: "dashed",
236
+ guideLineWidth: 1,
237
+ labelEnabled: !0,
238
+ labelPosition: "end"
239
+ },
240
+ snapConfig: {
241
+ enabled: !0,
242
+ threshold: 5,
243
+ strength: .5
244
+ },
245
+ showReferLine: !0
246
+ };
247
+ }
248
+ function m(e, t) {
249
+ switch (t.type) {
250
+ case "addLine": return {
251
+ ...e,
252
+ lines: [...e.lines, t.line]
253
+ };
254
+ case "removeLine": {
255
+ let n = e.lines.filter((e) => e.id !== t.id);
256
+ return n.length === e.lines.length ? e : {
257
+ ...e,
258
+ lines: n
259
+ };
260
+ }
261
+ case "moveLine": {
262
+ let n = e.lines.findIndex((e) => e.id === t.id);
263
+ if (n === -1) return e;
264
+ let r = [...e.lines];
265
+ return r[n] = {
266
+ ...r[n],
267
+ position: t.position
268
+ }, {
269
+ ...e,
270
+ lines: r
271
+ };
272
+ }
273
+ case "updateLine": {
274
+ let n = e.lines.findIndex((e) => e.id === t.id);
275
+ if (n === -1) return e;
276
+ let r = [...e.lines];
277
+ return r[n] = {
278
+ ...r[n],
279
+ ...t.updates
280
+ }, {
281
+ ...e,
282
+ lines: r
283
+ };
284
+ }
285
+ case "setLines": return t.lines === e.lines ? e : {
286
+ ...e,
287
+ lines: t.lines
288
+ };
289
+ case "setPalette": return {
290
+ ...e,
291
+ palette: {
292
+ ...e.palette,
293
+ ...t.palette
294
+ }
295
+ };
296
+ case "setSnapConfig": return {
297
+ ...e,
298
+ snapConfig: {
299
+ ...e.snapConfig,
300
+ ...t.config
301
+ }
302
+ };
303
+ case "toggleReferLine": return {
304
+ ...e,
305
+ showReferLine: t.value === void 0 ? !e.showReferLine : t.value
306
+ };
307
+ default: return e;
308
+ }
309
+ }
310
+ //#endregion
311
+ //#region src/plugins/plugin-manager.ts
312
+ var h = class {
313
+ plugins = [];
314
+ renderers = /* @__PURE__ */ new Map();
315
+ rendererOwners = /* @__PURE__ */ new WeakMap();
316
+ activeRenderer = null;
317
+ api = null;
318
+ setApi(e) {
319
+ this.api = e;
320
+ }
321
+ register(e) {
322
+ if (this.plugins.push(e), this.sortPlugins(), e.registerRenderer) {
323
+ let t = e.registerRenderer();
324
+ this.renderers.set(t.name, t.renderer), this.rendererOwners.set(e, t), this.activeRenderer === null && (this.activeRenderer = t.name);
325
+ }
326
+ return () => this.unregister(e);
327
+ }
328
+ unregister(e) {
329
+ let t = this.plugins.indexOf(e);
330
+ t !== -1 && this.plugins.splice(t, 1);
331
+ let n = this.rendererOwners.get(e);
332
+ n && (this.renderers.delete(n.name), this.rendererOwners.delete(e), this.activeRenderer === n.name && (this.activeRenderer = this.renderers.keys().next().value ?? null));
333
+ }
334
+ sortPlugins() {
335
+ this.plugins.sort((e, t) => (t.priority ?? 0) - (e.priority ?? 0));
336
+ }
337
+ getContext(e) {
338
+ if (!this.api) throw Error("[PluginManager] api not set. Call setApi() before dispatching hooks.");
339
+ return {
340
+ ...e,
341
+ api: this.api
342
+ };
343
+ }
344
+ safeCall(e, t, n) {
345
+ try {
346
+ e();
347
+ } catch (e) {
348
+ console.error(`[PluginManager] Plugin "${t}" ${n} threw:`, e);
349
+ }
350
+ }
351
+ async safeCallAsync(e, t, n) {
352
+ try {
353
+ await e();
354
+ } catch (e) {
355
+ console.error(`[PluginManager] Plugin "${t}" ${n} threw:`, e);
356
+ }
357
+ }
358
+ async beforeZoom(e) {
359
+ let t = !1, n = () => {
360
+ t = !0;
361
+ }, r = this.getContext({
362
+ ...e,
363
+ cancel: n
364
+ });
365
+ for (let e of this.plugins) if (e.beforeZoom && (await this.safeCallAsync(() => e.beforeZoom(r), e.name, "beforeZoom"), t)) return !1;
366
+ return !0;
367
+ }
368
+ afterZoom(e) {
369
+ let t = this.getContext(e);
370
+ for (let e of this.plugins) e.afterZoom && this.safeCall(() => e.afterZoom(t), e.name, "afterZoom");
371
+ }
372
+ async beforePan(e) {
373
+ let t = !1, n = () => {
374
+ t = !0;
375
+ }, r = this.getContext({
376
+ ...e,
377
+ cancel: n
378
+ });
379
+ for (let e of this.plugins) if (e.beforePan && (await this.safeCallAsync(() => e.beforePan(r), e.name, "beforePan"), t)) return !1;
380
+ return !0;
381
+ }
382
+ afterPan(e) {
383
+ let t = this.getContext(e);
384
+ for (let e of this.plugins) e.afterPan && this.safeCall(() => e.afterPan(t), e.name, "afterPan");
385
+ }
386
+ onSnap(e) {
387
+ let t = this.getContext(e);
388
+ for (let e of this.plugins) e.onSnap && this.safeCall(() => e.onSnap(t), e.name, "onSnap");
389
+ }
390
+ onLineCreate(e) {
391
+ let t = this.getContext(e);
392
+ for (let e of this.plugins) e.onLineCreate && this.safeCall(() => e.onLineCreate(t), e.name, "onLineCreate");
393
+ }
394
+ onLineDelete(e) {
395
+ let t = this.getContext(e);
396
+ for (let e of this.plugins) e.onLineDelete && this.safeCall(() => e.onLineDelete(t), e.name, "onLineDelete");
397
+ }
398
+ onLineMove(e) {
399
+ let t = this.getContext(e);
400
+ for (let e of this.plugins) e.onLineMove && this.safeCall(() => e.onLineMove(t), e.name, "onLineMove");
401
+ }
402
+ setActiveRenderer(e) {
403
+ return this.renderers.has(e) ? (this.activeRenderer = e, !0) : !1;
404
+ }
405
+ getActiveRenderer() {
406
+ return this.activeRenderer ? this.renderers.get(this.activeRenderer) ?? null : null;
407
+ }
408
+ getRendererNames() {
409
+ return Array.from(this.renderers.keys());
410
+ }
411
+ hasRenderer(e) {
412
+ return this.renderers.has(e);
413
+ }
414
+ clear() {
415
+ this.plugins = [], this.renderers.clear(), this.rendererOwners = /* @__PURE__ */ new WeakMap(), this.activeRenderer = null;
416
+ }
417
+ }, g = [
418
+ {
419
+ maxScale: .2,
420
+ interval: 500,
421
+ subdivisions: 5,
422
+ showLabel: !0,
423
+ formatLabel: (e) => `${Math.round(e / 1e3)}k`
424
+ },
425
+ {
426
+ maxScale: .5,
427
+ interval: 200,
428
+ subdivisions: 4,
429
+ showLabel: !0
430
+ },
431
+ {
432
+ maxScale: 1,
433
+ interval: 100,
434
+ subdivisions: 5,
435
+ showLabel: !0
436
+ },
437
+ {
438
+ maxScale: 2,
439
+ interval: 50,
440
+ subdivisions: 5,
441
+ showLabel: !0
442
+ },
443
+ {
444
+ maxScale: 5,
445
+ interval: 20,
446
+ subdivisions: 4,
447
+ showLabel: !0
448
+ },
449
+ {
450
+ maxScale: 10,
451
+ interval: 10,
452
+ subdivisions: 5,
453
+ showLabel: !0
454
+ },
455
+ {
456
+ maxScale: Infinity,
457
+ interval: 5,
458
+ subdivisions: 5,
459
+ showLabel: !0
460
+ }
461
+ ], _ = 1.1, v = .9;
462
+ function y(e) {
463
+ let t = g.findIndex((t) => e < t.maxScale);
464
+ return g[t === -1 ? g.length - 1 : t];
465
+ }
466
+ function b(e, t) {
467
+ let n = e;
468
+ for (; n < g.length - 1 && t >= g[n].maxScale * _;) n++;
469
+ for (; n > 0 && t < g[n - 1].maxScale * v;) n--;
470
+ return n;
471
+ }
472
+ //#endregion
473
+ //#region src/scale/index.ts
474
+ function x(e) {
475
+ let { scale: t, offset: n, viewportSize: r, thick: i, canvasSize: a, showMinorTicks: o } = e;
476
+ if (r <= 0 || t <= 0) return [];
477
+ let s = y(t), c = s.interval, l = s.subdivisions, u = c / l, d = -n / t, f = (r - n) / t, p = r / t, m = d - p * .5, h = f + p * .5, g = Math.floor(m / c) * c, _ = [], v = a ?? Infinity;
478
+ for (let e = g; e <= h; e += c) {
479
+ let a = e * t + n;
480
+ if (a >= -i && a <= r + i) {
481
+ let t = e >= 0 && e <= v && (v === Infinity || e === v || v - e >= c);
482
+ _.push({
483
+ position: a,
484
+ length: i * .6,
485
+ isMajor: !0,
486
+ label: t ? s.formatLabel ? s.formatLabel(e) : `${Math.round(e)}` : void 0,
487
+ value: e
488
+ });
489
+ }
490
+ if (o) for (let a = 1; a < l; a++) {
491
+ let o = e + a * u, s = o * t + n;
492
+ s >= -i && s <= r + i && _.push({
493
+ position: s,
494
+ length: i * .3,
495
+ isMajor: !1,
496
+ value: o
497
+ });
498
+ }
499
+ }
500
+ if (v !== Infinity && v > 0 && !_.some((e) => e.isMajor && e.value === v)) {
501
+ let e = v * t + n;
502
+ e >= -i && e <= r + i * 2 && (_.push({
503
+ position: e,
504
+ length: i * .6,
505
+ isMajor: !0,
506
+ label: `${Math.round(v)}`,
507
+ value: v
508
+ }), _.sort((e, t) => e.position - t.position));
509
+ }
510
+ return _;
511
+ }
512
+ //#endregion
513
+ //#region src/utils/id-utils.ts
514
+ var S = 0, C = 0;
515
+ function w() {
516
+ return `line-${++S}-${Date.now()}`;
517
+ }
518
+ function T() {
519
+ return `canvas-${++C}-${Date.now()}`;
520
+ }
521
+ //#endregion
522
+ //#region src/utils/line-utils.ts
523
+ function E(e) {
524
+ if (!e) return [];
525
+ let t = [], n = 0;
526
+ for (let r of e.h) t.push({
527
+ id: `h-${n++}-${Date.now()}`,
528
+ orientation: "h",
529
+ position: r,
530
+ visible: !0,
531
+ locked: !1
532
+ });
533
+ for (let r of e.v) t.push({
534
+ id: `v-${n++}-${Date.now()}`,
535
+ orientation: "v",
536
+ position: r,
537
+ visible: !0,
538
+ locked: !1
539
+ });
540
+ return t;
541
+ }
542
+ function D(e) {
543
+ return {
544
+ h: e.filter((e) => e.orientation === "h").map((e) => e.position),
545
+ v: e.filter((e) => e.orientation === "v").map((e) => e.position)
546
+ };
547
+ }
548
+ function O(e, t) {
549
+ return `${e ? "X" : "Y"}: ${Math.round(t)}`;
550
+ }
551
+ function k(e, t, n, r, i) {
552
+ let a = e.position * t + n, o = e.locked ? "default" : r ? "ns-resize" : "ew-resize";
553
+ return r ? {
554
+ left: `${a}px`,
555
+ top: "0",
556
+ height: "100vh",
557
+ width: "1px",
558
+ borderLeft: `1px dashed ${i}`,
559
+ cursor: o
560
+ } : {
561
+ top: `${a}px`,
562
+ left: "0",
563
+ width: "100vw",
564
+ height: "1px",
565
+ borderBottom: `1px dashed ${i}`,
566
+ cursor: o
567
+ };
568
+ }
569
+ function A(e, t, n) {
570
+ return (e - t) / n;
571
+ }
572
+ function j(e, t, n) {
573
+ return e * n + t;
574
+ }
575
+ function M(e) {
576
+ let { worldPos: t, majorTicks: n, thresholdWorld: r } = e;
577
+ if (n.length === 0) return null;
578
+ let i = null, a = Infinity;
579
+ for (let e of n) {
580
+ let n = Math.abs(t - e.value);
581
+ n < r && n < a && (a = n, i = e.value);
582
+ }
583
+ return i;
584
+ }
585
+ function N(e) {
586
+ let { startMouse: t, startPos: n, currentMouse: r, scale: i, majorTicks: a, snapThresholdWorld: o } = e, s = n + (r - t) / i, c = M({
587
+ worldPos: s,
588
+ majorTicks: a,
589
+ thresholdWorld: o
590
+ });
591
+ return c !== null && (s = c), Math.round(s);
592
+ }
593
+ //#endregion
594
+ //#region src/state/line-manager.ts
595
+ var P = class {
596
+ state;
597
+ listeners = /* @__PURE__ */ new Set();
598
+ constructor(e = []) {
599
+ this.state = p(), e.length > 0 && (this.state = m(this.state, {
600
+ type: "setLines",
601
+ lines: e
602
+ }));
603
+ }
604
+ dispatch(e) {
605
+ this.state = m(this.state, e), this.listeners.forEach((e) => e(this.state));
606
+ }
607
+ onUpdate(e) {
608
+ return this.listeners.add(e), () => this.listeners.delete(e);
609
+ }
610
+ getState() {
611
+ return this.state;
612
+ }
613
+ getLines() {
614
+ return this.state.lines;
615
+ }
616
+ addLine(e) {
617
+ let t = {
618
+ ...e,
619
+ id: w()
620
+ };
621
+ return this.dispatch({
622
+ type: "addLine",
623
+ line: t
624
+ }), t;
625
+ }
626
+ removeLine(e) {
627
+ return this.state.lines.some((t) => t.id === e) ? (this.dispatch({
628
+ type: "removeLine",
629
+ id: e
630
+ }), !0) : !1;
631
+ }
632
+ updateLine(e, t) {
633
+ return this.state.lines.some((t) => t.id === e) ? (this.dispatch({
634
+ type: "updateLine",
635
+ id: e,
636
+ updates: t
637
+ }), !0) : !1;
638
+ }
639
+ moveLine(e, t) {
640
+ return this.updateLine(e, { position: t });
641
+ }
642
+ toggleLock(e) {
643
+ let t = this.state.lines.find((t) => t.id === e);
644
+ return t ? this.updateLine(e, { locked: !t.locked }) : !1;
645
+ }
646
+ toggleVisible(e) {
647
+ let t = this.state.lines.find((t) => t.id === e);
648
+ return t ? this.updateLine(e, { visible: !t.visible }) : !1;
649
+ }
650
+ clear() {
651
+ this.dispatch({
652
+ type: "setLines",
653
+ lines: []
654
+ });
655
+ }
656
+ setLines(e) {
657
+ this.dispatch({
658
+ type: "setLines",
659
+ lines: [...e]
660
+ });
661
+ }
662
+ }, F = {
663
+ "A4 Portrait": {
664
+ name: "A4 纵向",
665
+ width: 794,
666
+ height: 1123
667
+ },
668
+ "A4 Landscape": {
669
+ name: "A4 横向",
670
+ width: 1123,
671
+ height: 794
672
+ },
673
+ "Web 1920": {
674
+ name: "Web 1920",
675
+ width: 1920,
676
+ height: 1080
677
+ },
678
+ "Web 1440": {
679
+ name: "Web 1440",
680
+ width: 1440,
681
+ height: 900
682
+ },
683
+ "Mobile 375": {
684
+ name: "Mobile 375",
685
+ width: 375,
686
+ height: 812
687
+ },
688
+ "Mobile 414": {
689
+ name: "Mobile 414",
690
+ width: 414,
691
+ height: 896
692
+ }
693
+ }, I = class {
694
+ canvases = [];
695
+ activeId = "";
696
+ templates = /* @__PURE__ */ new Map();
697
+ globalLines = [];
698
+ listeners = /* @__PURE__ */ new Set();
699
+ constructor(e = []) {
700
+ for (let [e, t] of Object.entries(F)) this.templates.set(e, t);
701
+ for (let t of e) this.addCanvas(t);
702
+ }
703
+ notify() {
704
+ let e = {
705
+ canvases: [...this.canvases],
706
+ activeId: this.activeId
707
+ };
708
+ this.listeners.forEach((t) => t(e));
709
+ }
710
+ onUpdate(e) {
711
+ return this.listeners.add(e), () => this.listeners.delete(e);
712
+ }
713
+ getState() {
714
+ return {
715
+ canvases: [...this.canvases],
716
+ activeId: this.activeId
717
+ };
718
+ }
719
+ get activeCanvas() {
720
+ return this.canvases.find((e) => e.id === this.activeId) ?? null;
721
+ }
722
+ addCanvas(e) {
723
+ let t = e?.id ?? T(), n = {
724
+ id: t,
725
+ name: e?.name ?? `画布 ${this.canvases.length + 1}`,
726
+ width: e?.width ?? 1920,
727
+ height: e?.height ?? 1080,
728
+ scale: e?.scale ?? 1,
729
+ offsetX: e?.offsetX ?? 0,
730
+ offsetY: e?.offsetY ?? 0,
731
+ lines: E(e?.lines),
732
+ thumbnail: null
733
+ };
734
+ return this.canvases = [...this.canvases, n], this.activeId ||= t, this.notify(), t;
735
+ }
736
+ removeCanvas(e) {
737
+ let t = this.canvases.findIndex((t) => t.id === e);
738
+ if (t === -1) return;
739
+ let n = [...this.canvases];
740
+ n.splice(t, 1), this.canvases = n, this.activeId === e && n.length > 0 && (this.activeId = n[0].id), this.notify();
741
+ }
742
+ switchCanvas(e) {
743
+ if (!this.canvases.some((t) => t.id === e)) return;
744
+ let t = this.activeCanvas;
745
+ t && t.id !== e && this.captureThumbnail(t.id), this.activeId = e;
746
+ let n = this.canvases.find((t) => t.id === e);
747
+ n && (n.thumbnail = null), this.notify();
748
+ }
749
+ updateCanvasState(e, t) {
750
+ this.canvases = this.canvases.map((n) => n.id === e ? {
751
+ ...n,
752
+ ...t
753
+ } : n), this.notify();
754
+ }
755
+ updateCanvasLines(e, t) {
756
+ this.canvases = this.canvases.map((n) => n.id === e ? {
757
+ ...n,
758
+ lines: [...t]
759
+ } : n), this.notify();
760
+ }
761
+ registerTemplate(e, t) {
762
+ this.templates.set(e, t);
763
+ }
764
+ getTemplateNames() {
765
+ return Array.from(this.templates.keys());
766
+ }
767
+ applyTemplate(e) {
768
+ let t = this.templates.get(e);
769
+ return t ? this.addCanvas(t) : null;
770
+ }
771
+ setGlobalLines(e) {
772
+ this.globalLines = E(e);
773
+ }
774
+ getGlobalLines() {
775
+ return [...this.globalLines];
776
+ }
777
+ getMergedLines(e) {
778
+ let t = this.canvases.find((t) => t.id === e);
779
+ return t ? [...this.globalLines, ...t.lines] : [];
780
+ }
781
+ exportCanvas(e) {
782
+ let t = this.canvases.find((t) => t.id === e);
783
+ return t ? { ...t } : null;
784
+ }
785
+ importCanvas(e) {
786
+ this.canvases.some((t) => t.id === e.id) ? this.canvases = this.canvases.map((t) => t.id === e.id ? { ...e } : t) : this.canvases = [...this.canvases, { ...e }], this.notify();
787
+ }
788
+ captureThumbnail(e) {
789
+ let t = this.canvases.find((t) => t.id === e);
790
+ t && (t.thumbnail = "data:image/png;base64,placeholder");
791
+ }
792
+ }, L = class {
793
+ options;
794
+ constructor(e) {
795
+ this.options = e;
796
+ }
797
+ snap(e, t) {
798
+ let n = this.options.scale;
799
+ if (n <= 0) return null;
800
+ let r = this.collectCandidates(e, t);
801
+ if (r.length === 0) return null;
802
+ let i = e * n, a = this.options.threshold, o = null, s = Infinity;
803
+ for (let e of r) {
804
+ let t = e.position * n, r = Math.abs(i - t);
805
+ r <= a && r < s && (s = r, o = e);
806
+ }
807
+ if (!o) return null;
808
+ let c = this.options.strength ?? .5;
809
+ return {
810
+ position: e * (1 - c) + o.position * c,
811
+ target: o,
812
+ original: e
813
+ };
814
+ }
815
+ collectCandidates(e, t) {
816
+ let n = [];
817
+ if (this.options.tickTargets) for (let e of this.options.tickTargets) n.push({
818
+ type: "tick",
819
+ position: e,
820
+ priority: 1
821
+ });
822
+ if (this.options.guideLineTargets) for (let e of this.options.guideLineTargets) n.push({
823
+ type: "guide-line",
824
+ position: e,
825
+ priority: 2
826
+ });
827
+ if (this.options.customTargets) for (let e of this.options.customTargets) n.push({
828
+ type: "custom",
829
+ position: e,
830
+ priority: 3
831
+ });
832
+ if (this.options.gridSize && this.options.gridSize > 0) {
833
+ let t = Math.round(e / this.options.gridSize) * this.options.gridSize;
834
+ n.push({
835
+ type: "grid",
836
+ position: t,
837
+ priority: 4
838
+ });
839
+ }
840
+ if (this.options.enableEquidistant && this.options.lines) {
841
+ let e = R(this.options.lines.filter((e) => e.orientation === t && e.visible !== !1).map((e) => e.position).sort((e, t) => e - t));
842
+ for (let t of e) n.push({
843
+ type: "equidistant",
844
+ position: t,
845
+ priority: 5
846
+ });
847
+ }
848
+ if (this.options.customRules && this.options.lines && this.options.viewportSize) {
849
+ let r = {
850
+ direction: t,
851
+ position: e,
852
+ scale: this.options.scale,
853
+ lines: this.options.lines,
854
+ viewportSize: this.options.viewportSize
855
+ };
856
+ for (let e of this.options.customRules) {
857
+ let t = e.getTargets(r);
858
+ for (let r of t) n.push({
859
+ ...r,
860
+ priority: e.priority
861
+ });
862
+ }
863
+ }
864
+ return n;
865
+ }
866
+ };
867
+ function R(e) {
868
+ if (e.length < 2) return [];
869
+ let t = [];
870
+ for (let n = 1; n < e.length; n++) {
871
+ let r = e[n] - e[n - 1], i = e[n] + r;
872
+ e.includes(i) || t.push(i);
873
+ let a = e[n - 1] - r;
874
+ e.includes(a) || t.push(a);
875
+ }
876
+ return t;
877
+ }
878
+ //#endregion
879
+ //#region src/engine/minimap-engine.ts
880
+ var z = class {
881
+ options;
882
+ constructor(e) {
883
+ this.options = e;
884
+ }
885
+ getState() {
886
+ let e = Math.min(this.options.width / this.options.contentWidth, this.options.height / this.options.contentHeight), t = this.options.contentWidth * e, n = this.options.contentHeight * e, r = (this.options.width - t) / 2, i = (this.options.height - n) / 2, a = r + -this.options.viewportX / this.options.scale * e, o = i + -this.options.viewportY / this.options.scale * e, s = this.options.viewportWidth / this.options.scale * e, c = this.options.viewportHeight / this.options.scale * e;
887
+ return {
888
+ miniScale: e,
889
+ contentOffset: {
890
+ x: r,
891
+ y: i
892
+ },
893
+ viewportRect: {
894
+ left: a,
895
+ top: o,
896
+ width: s,
897
+ height: c
898
+ }
899
+ };
900
+ }
901
+ clampTransform(e, t) {
902
+ let n = this.options.contentWidth * this.options.scale, r = this.options.contentHeight * this.options.scale, i = e, a = t;
903
+ return i = n <= this.options.viewportWidth ? (this.options.viewportWidth - n) / 2 : Math.min(0, Math.max(this.options.viewportWidth - n, e)), a = r <= this.options.viewportHeight ? (this.options.viewportHeight - r) / 2 : Math.min(0, Math.max(this.options.viewportHeight - r, t)), {
904
+ x: i,
905
+ y: a
906
+ };
907
+ }
908
+ canPan() {
909
+ return this.options.contentWidth * this.options.scale > this.options.viewportWidth || this.options.contentHeight * this.options.scale > this.options.viewportHeight;
910
+ }
911
+ clickAt(e, t, n, r) {
912
+ let i = this.getState(), a = (e - n - i.contentOffset.x) / i.miniScale, o = (t - r - i.contentOffset.y) / i.miniScale, s = this.options.viewportWidth / 2 - a * this.options.scale, c = this.options.viewportHeight / 2 - o * this.options.scale;
913
+ return this.clampTransform(s, c);
914
+ }
915
+ startDrag(e, t, n, r) {
916
+ return new B(this, e, t, n, r);
917
+ }
918
+ }, B = class {
919
+ engine;
920
+ startViewportX;
921
+ startViewportY;
922
+ startMinimapLeft;
923
+ startMinimapTop;
924
+ ratio;
925
+ constructor(e, t, n, r, i) {
926
+ this.engine = e, this.startViewportX = t, this.startViewportY = n, this.startMinimapLeft = r, this.startMinimapTop = i, this.ratio = e.options.scale / e.getState().miniScale;
927
+ }
928
+ move(e, t) {
929
+ let n = this.startViewportX - e * this.ratio, r = this.startViewportY - t * this.ratio, i = this.engine.clampTransform(n, r), a = (this.startViewportX - i.x) / this.ratio, o = (this.startViewportY - i.y) / this.ratio, s = this.engine.getState();
930
+ return {
931
+ targetX: i.x,
932
+ targetY: i.y,
933
+ dragRect: {
934
+ left: this.startMinimapLeft + a,
935
+ top: this.startMinimapTop + o,
936
+ width: s.viewportRect.width,
937
+ height: s.viewportRect.height
938
+ }
939
+ };
940
+ }
941
+ end(e, t) {
942
+ let n = this.startViewportX - e * this.ratio, r = this.startViewportY - t * this.ratio, i = this.engine.clampTransform(n, r);
943
+ return {
944
+ x: i.x,
945
+ y: i.y
946
+ };
947
+ }
948
+ };
949
+ //#endregion
950
+ export { F as BUILTIN_TEMPLATES, I as CanvasManager, P as LineManager, B as MinimapDragSession, z as MinimapEngine, h as PluginManager, L as SnapEngine, g as TICK_CONFIGS, f as TransformEngine, b as applyHysteresis, u as batchToScreen, l as batchToWorld, N as computeDraggedLinePosition, R as computeEquidistantTargets, k as computeLineStyle, x as computeScaleMarks, p as createDefaultState, e as createMatrix, i as decompose, o as equals, D as exportLines, d as fitRect, O as formatLineLabel, t as fromTransform, T as generateCanvasId, w as generateLineId, y as getTickConfig, E as importLines, r as invert, n as multiply, m as produceState, A as screenToWorld, M as snapToNearestTick, a as toCSSString, c as toScreenPoint, s as toWorldPoint, j as worldToScreen };