@xom11/whiteboard 0.24.0 → 0.24.1
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.
- package/dist/{ExcalidrawWithMenus-KBLDWPM2.mjs → ExcalidrawWithMenus-WENZRYYE.mjs} +2 -2
- package/dist/{ExcalidrawWithMenus-KBLDWPM2.mjs.map → ExcalidrawWithMenus-WENZRYYE.mjs.map} +1 -1
- package/dist/catalog.json +4 -4
- package/dist/{chunk-TOOHCAWP.mjs → chunk-4D5CSIJO.mjs} +4 -4
- package/dist/{chunk-TOOHCAWP.mjs.map → chunk-4D5CSIJO.mjs.map} +1 -1
- package/dist/chunk-6V4SH4JJ.mjs +1801 -0
- package/dist/chunk-6V4SH4JJ.mjs.map +1 -0
- package/dist/{chunk-VBJLUHCY.mjs → chunk-AZIARTGX.mjs} +3 -3
- package/dist/{chunk-VBJLUHCY.mjs.map → chunk-AZIARTGX.mjs.map} +1 -1
- package/dist/{chunk-6XUPIGVD.mjs → chunk-BKSXPNPQ.mjs} +4 -123
- package/dist/chunk-BKSXPNPQ.mjs.map +1 -0
- package/dist/{chunk-O6QTYAKE.mjs → chunk-CRAPWQKJ.mjs} +4 -4
- package/dist/{chunk-O6QTYAKE.mjs.map → chunk-CRAPWQKJ.mjs.map} +1 -1
- package/dist/{chunk-RBUILBX3.mjs → chunk-CSCF3YFZ.mjs} +5 -5
- package/dist/{chunk-RBUILBX3.mjs.map → chunk-CSCF3YFZ.mjs.map} +1 -1
- package/dist/{chunk-7WG2KDRF.mjs → chunk-IBTRMWD6.mjs} +3 -3
- package/dist/{chunk-7WG2KDRF.mjs.map → chunk-IBTRMWD6.mjs.map} +1 -1
- package/dist/{chunk-RD34F5PM.mjs → chunk-ICR4CVOE.mjs} +2 -2
- package/dist/chunk-ICR4CVOE.mjs.map +1 -0
- package/dist/{chunk-33PEN2WC.mjs → chunk-LVNCYP4J.mjs} +6 -6
- package/dist/{chunk-33PEN2WC.mjs.map → chunk-LVNCYP4J.mjs.map} +1 -1
- package/dist/{chunk-FZY33J6Z.mjs → chunk-MFOGFFIL.mjs} +6 -6
- package/dist/{chunk-FZY33J6Z.mjs.map → chunk-MFOGFFIL.mjs.map} +1 -1
- package/dist/{chunk-TQYQVXNW.mjs → chunk-QGNU34T7.mjs} +2 -2
- package/dist/chunk-QGNU34T7.mjs.map +1 -0
- package/dist/{chunk-RXOFO64U.mjs → chunk-SGFJLHHG.mjs} +3 -3
- package/dist/{chunk-RXOFO64U.mjs.map → chunk-SGFJLHHG.mjs.map} +1 -1
- package/dist/{chunk-2SKXRBGS.mjs → chunk-WWMQ2VHZ.mjs} +4 -4
- package/dist/{chunk-2SKXRBGS.mjs.map → chunk-WWMQ2VHZ.mjs.map} +1 -1
- package/dist/{chunk-XVSO7FBM.mjs → chunk-YIPI3WUL.mjs} +5 -5
- package/dist/{chunk-XVSO7FBM.mjs.map → chunk-YIPI3WUL.mjs.map} +1 -1
- package/dist/{chunk-VRWZILTG.mjs → chunk-ZBJBQKJ2.mjs} +128 -3
- package/dist/chunk-ZBJBQKJ2.mjs.map +1 -0
- package/dist/geometry-2d.js +2056 -100
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +6 -6
- package/dist/geometry-3d.js +2051 -15
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +5 -5
- package/dist/graph-2d.js +1938 -8
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +8 -8
- package/dist/{host-EVJT3LIF.mjs → host-DOAYVL35.mjs} +29 -28
- package/dist/host-DOAYVL35.mjs.map +1 -0
- package/dist/{host-3N4E4KJH.mjs → host-GKNQBBUE.mjs} +11 -11
- package/dist/{host-3N4E4KJH.mjs.map → host-GKNQBBUE.mjs.map} +1 -1
- package/dist/{host-6SNSZ332.mjs → host-QS2EOTRJ.mjs} +3 -3
- package/dist/{host-6SNSZ332.mjs.map → host-QS2EOTRJ.mjs.map} +1 -1
- package/dist/{host-HN4X3TBC.mjs → host-TLIXN4CF.mjs} +8 -8
- package/dist/{host-HN4X3TBC.mjs.map → host-TLIXN4CF.mjs.map} +1 -1
- package/dist/index.js +2044 -120
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +22 -30
- package/dist/index.mjs.map +1 -1
- package/dist/latex.js.map +1 -1
- package/dist/latex.mjs +1 -1
- package/dist/render-SA4JTOW3.mjs +8 -0
- package/dist/{render-OCVGDKK6.mjs.map → render-SA4JTOW3.mjs.map} +1 -1
- package/dist/serialize-3NZS6A6Q.mjs +6 -0
- package/dist/{serialize-GKN6OVPM.mjs.map → serialize-3NZS6A6Q.mjs.map} +1 -1
- package/package.json +11 -2
- package/dist/chunk-3KBL77M6.mjs +0 -127
- package/dist/chunk-3KBL77M6.mjs.map +0 -1
- package/dist/chunk-6XUPIGVD.mjs.map +0 -1
- package/dist/chunk-RD34F5PM.mjs.map +0 -1
- package/dist/chunk-TQYQVXNW.mjs.map +0 -1
- package/dist/chunk-VRWZILTG.mjs.map +0 -1
- package/dist/host-EVJT3LIF.mjs.map +0 -1
- package/dist/render-OCVGDKK6.mjs +0 -8
- package/dist/serialize-GKN6OVPM.mjs +0 -6
package/dist/index.js
CHANGED
|
@@ -82,10 +82,16 @@ var init_types = __esm({
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
// src/core/scene/registry.ts
|
|
85
|
+
function registerKind(def22) {
|
|
86
|
+
if (registry.has(def22.type)) {
|
|
87
|
+
console.warn(`[scene] kind "${def22.type}" \u0111\xE3 \u0111\u01B0\u1EE3c \u0111\u0103ng k\xFD \u2014 ghi \u0111\xE8 \u0111\u1ECBnh ngh\u0129a c\u0169`);
|
|
88
|
+
}
|
|
89
|
+
registry.set(def22.type, def22);
|
|
90
|
+
}
|
|
85
91
|
function getKind(type) {
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
return
|
|
92
|
+
const def22 = registry.get(type);
|
|
93
|
+
if (!def22) throw new Error(`[scene] unknown kind: ${type}`);
|
|
94
|
+
return def22;
|
|
89
95
|
}
|
|
90
96
|
var registry;
|
|
91
97
|
var init_registry = __esm({
|
|
@@ -310,67 +316,1621 @@ function nextLabel(state, kind) {
|
|
|
310
316
|
}
|
|
311
317
|
idx += 1;
|
|
312
318
|
}
|
|
313
|
-
}
|
|
314
|
-
var ALPHABET, LABEL_GROUPS;
|
|
315
|
-
var init_selectors = __esm({
|
|
316
|
-
"src/core/scene/selectors.ts"() {
|
|
317
|
-
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
318
|
-
LABEL_GROUPS = {
|
|
319
|
-
point: ["point", "intersection"],
|
|
320
|
-
intersection: ["point", "intersection"]
|
|
319
|
+
}
|
|
320
|
+
var ALPHABET, LABEL_GROUPS;
|
|
321
|
+
var init_selectors = __esm({
|
|
322
|
+
"src/core/scene/selectors.ts"() {
|
|
323
|
+
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
324
|
+
LABEL_GROUPS = {
|
|
325
|
+
point: ["point", "intersection"],
|
|
326
|
+
intersection: ["point", "intersection"]
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
function useEditorState(opts) {
|
|
331
|
+
const { store, initialState, onHistoryChange, bindKeyboardShortcuts = true } = opts;
|
|
332
|
+
const onHistoryChangeRef = React18__namespace.useRef(onHistoryChange);
|
|
333
|
+
onHistoryChangeRef.current = onHistoryChange;
|
|
334
|
+
React18__namespace.useEffect(() => {
|
|
335
|
+
if (initialState?.state) {
|
|
336
|
+
const loaded = initialState.state;
|
|
337
|
+
store.withoutHistory(() => {
|
|
338
|
+
store.dispatch({ type: "LOAD", payload: { state: loaded } });
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}, []);
|
|
342
|
+
React18__namespace.useEffect(() => {
|
|
343
|
+
onHistoryChangeRef.current?.(store.canUndo(), store.canRedo());
|
|
344
|
+
const unsub = store.subscribe(() => {
|
|
345
|
+
onHistoryChangeRef.current?.(store.canUndo(), store.canRedo());
|
|
346
|
+
});
|
|
347
|
+
return unsub;
|
|
348
|
+
}, [store]);
|
|
349
|
+
React18__namespace.useEffect(() => {
|
|
350
|
+
if (!bindKeyboardShortcuts) return;
|
|
351
|
+
const onKey = (e) => {
|
|
352
|
+
const ae = document.activeElement;
|
|
353
|
+
const inField = !!(ae && (ae.tagName === "INPUT" || ae.tagName === "TEXTAREA" || ae.isContentEditable));
|
|
354
|
+
if (inField) return;
|
|
355
|
+
if (!(e.metaKey || e.ctrlKey)) return;
|
|
356
|
+
const key = e.key.toLowerCase();
|
|
357
|
+
if (key === "z" && !e.shiftKey) {
|
|
358
|
+
e.preventDefault();
|
|
359
|
+
e.stopPropagation();
|
|
360
|
+
store.undo();
|
|
361
|
+
} else if (key === "z" && e.shiftKey || key === "y" && !e.shiftKey) {
|
|
362
|
+
e.preventDefault();
|
|
363
|
+
e.stopPropagation();
|
|
364
|
+
store.redo();
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
window.addEventListener("keydown", onKey, { capture: true });
|
|
368
|
+
return () => window.removeEventListener("keydown", onKey, { capture: true });
|
|
369
|
+
}, [store, bindKeyboardShortcuts]);
|
|
370
|
+
}
|
|
371
|
+
var init_useEditorState = __esm({
|
|
372
|
+
"src/core/scene/hooks/useEditorState.ts"() {
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// src/core/scene/hooks/index.ts
|
|
377
|
+
var init_hooks = __esm({
|
|
378
|
+
"src/core/scene/hooks/index.ts"() {
|
|
379
|
+
init_useEditorState();
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// src/core/scene/kinds/3d-constraint.ts
|
|
384
|
+
function constraintRefs(c) {
|
|
385
|
+
switch (c.kind) {
|
|
386
|
+
case "onPlane":
|
|
387
|
+
return [c.planeId];
|
|
388
|
+
case "onLine":
|
|
389
|
+
return [c.lineId];
|
|
390
|
+
case "onPolygon":
|
|
391
|
+
return [c.polygonId];
|
|
392
|
+
case "onSphere":
|
|
393
|
+
return [c.sphereId];
|
|
394
|
+
default:
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
var init_d_constraint = __esm({
|
|
399
|
+
"src/core/scene/kinds/3d-constraint.ts"() {
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// src/core/scene/kinds/point3d.ts
|
|
404
|
+
var def;
|
|
405
|
+
var init_point3d = __esm({
|
|
406
|
+
"src/core/scene/kinds/point3d.ts"() {
|
|
407
|
+
init_registry();
|
|
408
|
+
init_d_constraint();
|
|
409
|
+
def = {
|
|
410
|
+
type: "point3d",
|
|
411
|
+
schemaVersion: 1,
|
|
412
|
+
migrate: {},
|
|
413
|
+
validate: (a) => {
|
|
414
|
+
if (!a || !a.constraint || !a.constraint.kind) {
|
|
415
|
+
throw new Error("point3d: constraint required");
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
dependsOn: (a) => constraintRefs(a.constraint),
|
|
419
|
+
measure: (obj) => {
|
|
420
|
+
const c = obj.attrs.constraint;
|
|
421
|
+
if (c.kind === "free") {
|
|
422
|
+
return [
|
|
423
|
+
{ label: "x", value: c.x },
|
|
424
|
+
{ label: "y", value: c.y },
|
|
425
|
+
{ label: "z", value: c.z }
|
|
426
|
+
];
|
|
427
|
+
}
|
|
428
|
+
if (c.kind === "onGround") {
|
|
429
|
+
return [
|
|
430
|
+
{ label: "x", value: c.x },
|
|
431
|
+
{ label: "y", value: c.y },
|
|
432
|
+
{ label: "z", value: 0 }
|
|
433
|
+
];
|
|
434
|
+
}
|
|
435
|
+
return null;
|
|
436
|
+
},
|
|
437
|
+
describe: (obj) => {
|
|
438
|
+
const c = obj.attrs.constraint;
|
|
439
|
+
if (c.kind === "free") return `${obj.label} = (${c.x.toFixed(2)}, ${c.y.toFixed(2)}, ${c.z.toFixed(2)})`;
|
|
440
|
+
if (c.kind === "onGround") return `${obj.label} = (${c.x.toFixed(2)}, ${c.y.toFixed(2)}, 0)`;
|
|
441
|
+
if (c.kind === "onAxis") return `${obj.label} tr\xEAn tr\u1EE5c ${c.axis} (t=${c.t.toFixed(2)})`;
|
|
442
|
+
if (c.kind === "onPlane") return `${obj.label} tr\xEAn m\u1EB7t ${c.planeId}`;
|
|
443
|
+
if (c.kind === "onLine") return `${obj.label} tr\xEAn \u0111\u01B0\u1EDDng ${c.lineId}`;
|
|
444
|
+
if (c.kind === "onPolygon") return `${obj.label} tr\xEAn \u0111a gi\xE1c ${c.polygonId}`;
|
|
445
|
+
if (c.kind === "onSphere") return `${obj.label} tr\xEAn m\u1EB7t c\u1EA7u ${c.sphereId}`;
|
|
446
|
+
return obj.label;
|
|
447
|
+
},
|
|
448
|
+
render: (obj, ctx) => {
|
|
449
|
+
const view = ctx.jxg;
|
|
450
|
+
const c = obj.attrs.constraint;
|
|
451
|
+
const opts = {
|
|
452
|
+
name: obj.label,
|
|
453
|
+
visible: obj.visible,
|
|
454
|
+
fixed: obj.locked,
|
|
455
|
+
strokeColor: obj.attrs.color ?? "#1e40af",
|
|
456
|
+
fillColor: obj.attrs.color ?? "#1e40af",
|
|
457
|
+
size: 4
|
|
458
|
+
};
|
|
459
|
+
if (c.kind === "free") {
|
|
460
|
+
return view.create("point3d", [c.x, c.y, c.z], opts);
|
|
461
|
+
} else if (c.kind === "onGround") {
|
|
462
|
+
return view.create("point3d", [c.x, c.y, 0], opts);
|
|
463
|
+
} else if (c.kind === "onAxis") {
|
|
464
|
+
const coords = c.axis === "x" ? [c.t, 0, 0] : c.axis === "y" ? [0, c.t, 0] : [0, 0, c.t];
|
|
465
|
+
return view.create("point3d", coords, opts);
|
|
466
|
+
} else if (c.kind === "onPlane") {
|
|
467
|
+
const plane = ctx.resolveRef(c.planeId);
|
|
468
|
+
return view.create("point3d", [
|
|
469
|
+
() => plane.F(c.u, c.v)[0],
|
|
470
|
+
() => plane.F(c.u, c.v)[1],
|
|
471
|
+
() => plane.F(c.u, c.v)[2]
|
|
472
|
+
], opts);
|
|
473
|
+
} else if (c.kind === "onLine") {
|
|
474
|
+
const line = ctx.resolveRef(c.lineId);
|
|
475
|
+
return view.create("point3d", [
|
|
476
|
+
() => line.F(c.t)[0],
|
|
477
|
+
() => line.F(c.t)[1],
|
|
478
|
+
() => line.F(c.t)[2]
|
|
479
|
+
], opts);
|
|
480
|
+
} else if (c.kind === "onPolygon") {
|
|
481
|
+
const poly = ctx.resolveRef(c.polygonId);
|
|
482
|
+
return view.create("point3d", [
|
|
483
|
+
() => poly.F(c.u, c.v)[0],
|
|
484
|
+
() => poly.F(c.u, c.v)[1],
|
|
485
|
+
() => poly.F(c.u, c.v)[2]
|
|
486
|
+
], opts);
|
|
487
|
+
} else if (c.kind === "onSphere") {
|
|
488
|
+
const sph = ctx.resolveRef(c.sphereId);
|
|
489
|
+
return view.create("point3d", [
|
|
490
|
+
() => sph.F(c.theta, c.phi)[0],
|
|
491
|
+
() => sph.F(c.theta, c.phi)[1],
|
|
492
|
+
() => sph.F(c.theta, c.phi)[2]
|
|
493
|
+
], opts);
|
|
494
|
+
}
|
|
495
|
+
return view.create("point3d", [0, 0, 0], opts);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
registerKind(def);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// src/core/scene/kinds/labelOf.ts
|
|
503
|
+
function labelOf(id, state) {
|
|
504
|
+
return state?.objects[id]?.label ?? id;
|
|
505
|
+
}
|
|
506
|
+
var init_labelOf = __esm({
|
|
507
|
+
"src/core/scene/kinds/labelOf.ts"() {
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
// src/core/scene/kinds/segment3d.ts
|
|
512
|
+
var def2;
|
|
513
|
+
var init_segment3d = __esm({
|
|
514
|
+
"src/core/scene/kinds/segment3d.ts"() {
|
|
515
|
+
init_registry();
|
|
516
|
+
init_labelOf();
|
|
517
|
+
def2 = {
|
|
518
|
+
type: "segment3d",
|
|
519
|
+
schemaVersion: 1,
|
|
520
|
+
migrate: {},
|
|
521
|
+
validate: (a) => {
|
|
522
|
+
if (!a?.p1 || !a?.p2) throw new Error("segment3d: p1 v\xE0 p2 b\u1EAFt bu\u1ED9c");
|
|
523
|
+
},
|
|
524
|
+
dependsOn: (a) => [a.p1, a.p2],
|
|
525
|
+
measure: (obj, state) => {
|
|
526
|
+
const p1 = state.objects[obj.attrs.p1];
|
|
527
|
+
const p2 = state.objects[obj.attrs.p2];
|
|
528
|
+
if (!p1 || !p2) return null;
|
|
529
|
+
const c1 = p1.attrs.constraint;
|
|
530
|
+
const c2 = p2.attrs.constraint;
|
|
531
|
+
if (c1?.kind !== "free" || c2?.kind !== "free") return null;
|
|
532
|
+
const dx = (c2.x ?? 0) - (c1.x ?? 0);
|
|
533
|
+
const dy = (c2.y ?? 0) - (c1.y ?? 0);
|
|
534
|
+
const dz = (c2.z ?? 0) - (c1.z ?? 0);
|
|
535
|
+
return [{ label: "length", value: Math.hypot(dx, dy, dz) }];
|
|
536
|
+
},
|
|
537
|
+
describe: (obj, state) => `\u0110o\u1EA1n th\u1EB3ng ${labelOf(obj.attrs.p1, state)}${labelOf(obj.attrs.p2, state)}`,
|
|
538
|
+
render: (obj, ctx) => {
|
|
539
|
+
const view = ctx.jxg;
|
|
540
|
+
const pA = ctx.resolveRef(obj.attrs.p1);
|
|
541
|
+
const pB = ctx.resolveRef(obj.attrs.p2);
|
|
542
|
+
return view.create("line3d", [pA, pB], {
|
|
543
|
+
straightFirst: false,
|
|
544
|
+
straightLast: false,
|
|
545
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
546
|
+
strokeWidth: 2,
|
|
547
|
+
visible: obj.visible
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
registerKind(def2);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// src/core/scene/kinds/line3d.ts
|
|
556
|
+
var init_line3d = __esm({
|
|
557
|
+
"src/core/scene/kinds/line3d.ts"() {
|
|
558
|
+
init_registry();
|
|
559
|
+
init_labelOf();
|
|
560
|
+
registerKind({
|
|
561
|
+
type: "line3d",
|
|
562
|
+
schemaVersion: 1,
|
|
563
|
+
migrate: {},
|
|
564
|
+
validate: (a) => {
|
|
565
|
+
if (!a?.p1 || !a?.p2) throw new Error("line3d: p1/p2 required");
|
|
566
|
+
},
|
|
567
|
+
dependsOn: (a) => [a.p1, a.p2],
|
|
568
|
+
describe: (obj, state) => `\u0110\u01B0\u1EDDng ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}`,
|
|
569
|
+
render: (obj, ctx) => {
|
|
570
|
+
const view = ctx.jxg;
|
|
571
|
+
const pA = ctx.resolveRef(obj.attrs.p1);
|
|
572
|
+
const pB = ctx.resolveRef(obj.attrs.p2);
|
|
573
|
+
return view.create("line3d", [pA, pB], {
|
|
574
|
+
straightFirst: true,
|
|
575
|
+
straightLast: true,
|
|
576
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
577
|
+
strokeWidth: 2,
|
|
578
|
+
visible: obj.visible
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
// src/core/scene/kinds/ray3d.ts
|
|
586
|
+
var init_ray3d = __esm({
|
|
587
|
+
"src/core/scene/kinds/ray3d.ts"() {
|
|
588
|
+
init_registry();
|
|
589
|
+
init_labelOf();
|
|
590
|
+
registerKind({
|
|
591
|
+
type: "ray3d",
|
|
592
|
+
schemaVersion: 1,
|
|
593
|
+
migrate: {},
|
|
594
|
+
validate: (a) => {
|
|
595
|
+
if (!a?.origin || !a?.through) throw new Error("ray3d: origin/through required");
|
|
596
|
+
},
|
|
597
|
+
dependsOn: (a) => [a.origin, a.through],
|
|
598
|
+
describe: (obj, state) => `Tia ${obj.label} t\u1EEB ${labelOf(obj.attrs.origin, state)} qua ${labelOf(obj.attrs.through, state)}`,
|
|
599
|
+
render: (obj, ctx) => {
|
|
600
|
+
const view = ctx.jxg;
|
|
601
|
+
const pOrigin = ctx.resolveRef(obj.attrs.origin);
|
|
602
|
+
const pThrough = ctx.resolveRef(obj.attrs.through);
|
|
603
|
+
return view.create("line3d", [pOrigin, pThrough], {
|
|
604
|
+
straightFirst: false,
|
|
605
|
+
straightLast: true,
|
|
606
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
607
|
+
strokeWidth: 2,
|
|
608
|
+
visible: obj.visible
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// src/core/scene/kinds/vector3d.ts
|
|
616
|
+
var init_vector3d = __esm({
|
|
617
|
+
"src/core/scene/kinds/vector3d.ts"() {
|
|
618
|
+
init_registry();
|
|
619
|
+
init_labelOf();
|
|
620
|
+
registerKind({
|
|
621
|
+
type: "vector3d",
|
|
622
|
+
schemaVersion: 1,
|
|
623
|
+
migrate: {},
|
|
624
|
+
validate: (a) => {
|
|
625
|
+
if (!a?.from || !a?.to) throw new Error("vector3d: from/to required");
|
|
626
|
+
},
|
|
627
|
+
dependsOn: (a) => [a.from, a.to],
|
|
628
|
+
describe: (obj, state) => `V\xE9c-t\u01A1 ${obj.label}: ${labelOf(obj.attrs.from, state)} \u2192 ${labelOf(obj.attrs.to, state)}`,
|
|
629
|
+
render: (obj, ctx) => {
|
|
630
|
+
const view = ctx.jxg;
|
|
631
|
+
const pFrom = ctx.resolveRef(obj.attrs.from);
|
|
632
|
+
const pTo = ctx.resolveRef(obj.attrs.to);
|
|
633
|
+
return view.create("line3d", [pFrom, pTo], {
|
|
634
|
+
straightFirst: false,
|
|
635
|
+
straightLast: false,
|
|
636
|
+
lastArrow: { type: 1 },
|
|
637
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
638
|
+
strokeWidth: 2,
|
|
639
|
+
visible: obj.visible
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
// src/core/scene/kinds/plane3d.ts
|
|
647
|
+
var init_plane3d = __esm({
|
|
648
|
+
"src/core/scene/kinds/plane3d.ts"() {
|
|
649
|
+
init_registry();
|
|
650
|
+
init_labelOf();
|
|
651
|
+
registerKind({
|
|
652
|
+
type: "plane3d",
|
|
653
|
+
schemaVersion: 1,
|
|
654
|
+
migrate: {},
|
|
655
|
+
validate: (a) => {
|
|
656
|
+
if (!a?.p1 || !a?.p2 || !a?.p3) throw new Error("plane3d: c\u1EA7n 3 \u0111i\u1EC3m");
|
|
657
|
+
},
|
|
658
|
+
dependsOn: (a) => [a.p1, a.p2, a.p3],
|
|
659
|
+
describe: (obj, state) => `M\u1EB7t ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}, ${labelOf(obj.attrs.p3, state)}`,
|
|
660
|
+
render: (obj, ctx) => {
|
|
661
|
+
const view = ctx.jxg;
|
|
662
|
+
return view.create("plane3d", [
|
|
663
|
+
ctx.resolveRef(obj.attrs.p1),
|
|
664
|
+
ctx.resolveRef(obj.attrs.p2),
|
|
665
|
+
ctx.resolveRef(obj.attrs.p3)
|
|
666
|
+
], {
|
|
667
|
+
fillOpacity: 0.15,
|
|
668
|
+
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
669
|
+
strokeColor: obj.attrs.color ?? "#60a5fa",
|
|
670
|
+
visible: obj.visible
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
// src/core/scene/kinds/polygon3d.ts
|
|
678
|
+
var init_polygon3d = __esm({
|
|
679
|
+
"src/core/scene/kinds/polygon3d.ts"() {
|
|
680
|
+
init_registry();
|
|
681
|
+
registerKind({
|
|
682
|
+
type: "polygon3d",
|
|
683
|
+
schemaVersion: 1,
|
|
684
|
+
migrate: {},
|
|
685
|
+
validate: (a) => {
|
|
686
|
+
if (!a?.vertices || a.vertices.length < 3) throw new Error("polygon3d: c\u1EA7n \u22653 vertices");
|
|
687
|
+
},
|
|
688
|
+
dependsOn: (a) => [...a.vertices],
|
|
689
|
+
describe: (obj) => `\u0110a gi\xE1c ${obj.label} (${obj.attrs.vertices.length} \u0111\u1EC9nh)`,
|
|
690
|
+
render: (obj, ctx) => {
|
|
691
|
+
const view = ctx.jxg;
|
|
692
|
+
const refs = obj.attrs.vertices.map((id) => ctx.resolveRef(id));
|
|
693
|
+
return view.create("polygon3d", [refs], {
|
|
694
|
+
fillOpacity: 0.3,
|
|
695
|
+
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
696
|
+
visible: obj.visible
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// src/core/scene/kinds/sphere3d.ts
|
|
704
|
+
var init_sphere3d = __esm({
|
|
705
|
+
"src/core/scene/kinds/sphere3d.ts"() {
|
|
706
|
+
init_registry();
|
|
707
|
+
init_labelOf();
|
|
708
|
+
registerKind({
|
|
709
|
+
type: "sphere3d",
|
|
710
|
+
schemaVersion: 1,
|
|
711
|
+
migrate: {},
|
|
712
|
+
validate: (a) => {
|
|
713
|
+
if (!a?.center || !a?.surfacePoint) throw new Error("sphere3d: center/surfacePoint required");
|
|
714
|
+
},
|
|
715
|
+
dependsOn: (a) => [a.center, a.surfacePoint],
|
|
716
|
+
describe: (obj, state) => `M\u1EB7t c\u1EA7u ${obj.label} t\xE2m ${labelOf(obj.attrs.center, state)}`,
|
|
717
|
+
render: (obj, ctx) => {
|
|
718
|
+
const view = ctx.jxg;
|
|
719
|
+
return view.create("sphere3d", [
|
|
720
|
+
ctx.resolveRef(obj.attrs.center),
|
|
721
|
+
ctx.resolveRef(obj.attrs.surfacePoint)
|
|
722
|
+
], {
|
|
723
|
+
fillOpacity: 0.25,
|
|
724
|
+
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
725
|
+
visible: obj.visible
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
// src/core/scene/kinds/polyhedron3d.ts
|
|
733
|
+
var FLAVOR_LABEL;
|
|
734
|
+
var init_polyhedron3d = __esm({
|
|
735
|
+
"src/core/scene/kinds/polyhedron3d.ts"() {
|
|
736
|
+
init_registry();
|
|
737
|
+
FLAVOR_LABEL = {
|
|
738
|
+
pyramid: "ch\xF3p",
|
|
739
|
+
prism: "l\u0103ng tr\u1EE5",
|
|
740
|
+
tetrahedron: "t\u1EE9 di\u1EC7n",
|
|
741
|
+
cube: "l\u1EADp ph\u01B0\u01A1ng"
|
|
742
|
+
};
|
|
743
|
+
registerKind({
|
|
744
|
+
type: "polyhedron3d",
|
|
745
|
+
schemaVersion: 1,
|
|
746
|
+
migrate: {},
|
|
747
|
+
validate: (a) => {
|
|
748
|
+
if (!a?.vertices || a.vertices.length < 4) throw new Error("polyhedron3d: c\u1EA7n \u22654 vertices");
|
|
749
|
+
if (!a?.faces || a.faces.length < 4) throw new Error("polyhedron3d: c\u1EA7n \u22654 faces");
|
|
750
|
+
},
|
|
751
|
+
dependsOn: (a) => [...a.vertices],
|
|
752
|
+
describe: (obj) => `Kh\u1ED1i ${FLAVOR_LABEL[obj.attrs.flavor]} ${obj.label}`,
|
|
753
|
+
render: (obj, ctx) => {
|
|
754
|
+
const view = ctx.jxg;
|
|
755
|
+
const verts = obj.attrs.vertices.map((id) => ctx.resolveRef(id));
|
|
756
|
+
const faces = obj.attrs.faces.map(
|
|
757
|
+
(faceIndices, fi) => view.create("polygon3d", [faceIndices.map((i) => verts[i])], {
|
|
758
|
+
id: `${obj.id}.face${faceIndices.join("-")}.${fi}`,
|
|
759
|
+
fillOpacity: 0.25,
|
|
760
|
+
fillColor: obj.attrs.color ?? "#fbbf24",
|
|
761
|
+
strokeColor: "#0066cc",
|
|
762
|
+
strokeWidth: 1.5,
|
|
763
|
+
visible: obj.visible
|
|
764
|
+
})
|
|
765
|
+
);
|
|
766
|
+
return { faces };
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// src/core/scene/kinds/cylinder3d.ts
|
|
773
|
+
var CURVED_SEGMENTS;
|
|
774
|
+
var init_cylinder3d = __esm({
|
|
775
|
+
"src/core/scene/kinds/cylinder3d.ts"() {
|
|
776
|
+
init_registry();
|
|
777
|
+
CURVED_SEGMENTS = 16;
|
|
778
|
+
registerKind({
|
|
779
|
+
type: "cylinder3d",
|
|
780
|
+
schemaVersion: 1,
|
|
781
|
+
migrate: {},
|
|
782
|
+
validate: (a) => {
|
|
783
|
+
if (!a?.baseCenter || !a?.topCenter) throw new Error("cylinder3d: baseCenter/topCenter required");
|
|
784
|
+
if (!(a.radius > 0)) throw new Error("cylinder3d: radius > 0");
|
|
785
|
+
},
|
|
786
|
+
dependsOn: (a) => [a.baseCenter, a.topCenter],
|
|
787
|
+
describe: (obj) => `Tr\u1EE5 ${obj.label} R=${obj.attrs.radius.toFixed(2)}`,
|
|
788
|
+
render: (obj, ctx) => {
|
|
789
|
+
const view = ctx.jxg;
|
|
790
|
+
const a = ctx.resolveRef(obj.attrs.baseCenter);
|
|
791
|
+
const b = ctx.resolveRef(obj.attrs.topCenter);
|
|
792
|
+
const r2 = obj.attrs.radius;
|
|
793
|
+
const ax = a.X?.() ?? 0, ay = a.Y?.() ?? 0, az = a.Z?.() ?? 0;
|
|
794
|
+
const bx = b.X?.() ?? 0, by = b.Y?.() ?? 0, bz = b.Z?.() ?? 0;
|
|
795
|
+
const baseRing = [];
|
|
796
|
+
const topRing = [];
|
|
797
|
+
for (let i = 0; i < CURVED_SEGMENTS; i++) {
|
|
798
|
+
const theta = i / CURVED_SEGMENTS * Math.PI * 2;
|
|
799
|
+
const dx = r2 * Math.cos(theta);
|
|
800
|
+
const dy = r2 * Math.sin(theta);
|
|
801
|
+
baseRing.push([ax + dx, ay + dy, az]);
|
|
802
|
+
topRing.push([bx + dx, by + dy, bz]);
|
|
803
|
+
}
|
|
804
|
+
const vertices = [...baseRing, ...topRing];
|
|
805
|
+
const faces = [];
|
|
806
|
+
faces.push(baseRing.map((_, i) => i));
|
|
807
|
+
faces.push(topRing.map((_, i) => CURVED_SEGMENTS + i));
|
|
808
|
+
for (let i = 0; i < CURVED_SEGMENTS; i++) {
|
|
809
|
+
const next = (i + 1) % CURVED_SEGMENTS;
|
|
810
|
+
faces.push([i, next, CURVED_SEGMENTS + next, CURVED_SEGMENTS + i]);
|
|
811
|
+
}
|
|
812
|
+
const vertJxgs = vertices.map(
|
|
813
|
+
(v, i) => view.create("point3d", v, {
|
|
814
|
+
id: `${obj.id}.v${i}`,
|
|
815
|
+
visible: false,
|
|
816
|
+
fixed: true,
|
|
817
|
+
withLabel: false
|
|
818
|
+
})
|
|
819
|
+
);
|
|
820
|
+
const faceJxgs = faces.map(
|
|
821
|
+
(face, fi) => view.create("polygon3d", [face.map((idx) => vertJxgs[idx])], {
|
|
822
|
+
id: `${obj.id}.face${fi}`,
|
|
823
|
+
fillOpacity: 0.25,
|
|
824
|
+
fillColor: obj.attrs.color ?? "#f97316",
|
|
825
|
+
strokeColor: "#0066cc",
|
|
826
|
+
strokeWidth: 1.5,
|
|
827
|
+
visible: obj.visible
|
|
828
|
+
})
|
|
829
|
+
);
|
|
830
|
+
return { _verts: vertJxgs, faces: faceJxgs };
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
// src/core/scene/kinds/cone3d.ts
|
|
837
|
+
var CURVED_SEGMENTS2;
|
|
838
|
+
var init_cone3d = __esm({
|
|
839
|
+
"src/core/scene/kinds/cone3d.ts"() {
|
|
840
|
+
init_registry();
|
|
841
|
+
CURVED_SEGMENTS2 = 16;
|
|
842
|
+
registerKind({
|
|
843
|
+
type: "cone3d",
|
|
844
|
+
schemaVersion: 1,
|
|
845
|
+
migrate: {},
|
|
846
|
+
validate: (a) => {
|
|
847
|
+
if (!a?.baseCenter || !a?.apex) throw new Error("cone3d: baseCenter/apex required");
|
|
848
|
+
if (!(a.radius > 0)) throw new Error("cone3d: radius > 0");
|
|
849
|
+
},
|
|
850
|
+
dependsOn: (a) => [a.baseCenter, a.apex],
|
|
851
|
+
describe: (obj) => `N\xF3n ${obj.label} R=${obj.attrs.radius.toFixed(2)}`,
|
|
852
|
+
render: (obj, ctx) => {
|
|
853
|
+
const view = ctx.jxg;
|
|
854
|
+
const base = ctx.resolveRef(obj.attrs.baseCenter);
|
|
855
|
+
const apexPt = ctx.resolveRef(obj.attrs.apex);
|
|
856
|
+
const r2 = obj.attrs.radius;
|
|
857
|
+
const bx = base.X?.() ?? 0, by = base.Y?.() ?? 0, bz = base.Z?.() ?? 0;
|
|
858
|
+
const apexCoords = [
|
|
859
|
+
apexPt.X?.() ?? 0,
|
|
860
|
+
apexPt.Y?.() ?? 0,
|
|
861
|
+
apexPt.Z?.() ?? 0
|
|
862
|
+
];
|
|
863
|
+
const baseRing = [];
|
|
864
|
+
for (let i = 0; i < CURVED_SEGMENTS2; i++) {
|
|
865
|
+
const theta = i / CURVED_SEGMENTS2 * Math.PI * 2;
|
|
866
|
+
baseRing.push([bx + r2 * Math.cos(theta), by + r2 * Math.sin(theta), bz]);
|
|
867
|
+
}
|
|
868
|
+
const apexIdx = baseRing.length;
|
|
869
|
+
const vertices = [...baseRing, apexCoords];
|
|
870
|
+
const faces = [baseRing.map((_, i) => i)];
|
|
871
|
+
for (let i = 0; i < CURVED_SEGMENTS2; i++) {
|
|
872
|
+
faces.push([i, (i + 1) % CURVED_SEGMENTS2, apexIdx]);
|
|
873
|
+
}
|
|
874
|
+
const vertJxgs = vertices.map(
|
|
875
|
+
(v, i) => view.create("point3d", v, {
|
|
876
|
+
id: `${obj.id}.v${i}`,
|
|
877
|
+
visible: false,
|
|
878
|
+
fixed: true,
|
|
879
|
+
withLabel: false
|
|
880
|
+
})
|
|
881
|
+
);
|
|
882
|
+
const faceJxgs = faces.map(
|
|
883
|
+
(face, fi) => view.create("polygon3d", [face.map((idx) => vertJxgs[idx])], {
|
|
884
|
+
id: `${obj.id}.face${fi}`,
|
|
885
|
+
fillOpacity: 0.25,
|
|
886
|
+
fillColor: obj.attrs.color ?? "#f59e0b",
|
|
887
|
+
strokeColor: "#0066cc",
|
|
888
|
+
strokeWidth: 1.5,
|
|
889
|
+
visible: obj.visible
|
|
890
|
+
})
|
|
891
|
+
);
|
|
892
|
+
return { _verts: vertJxgs, faces: faceJxgs };
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
// src/core/scene/kinds/2d-constraint.ts
|
|
899
|
+
function transformRefs(t) {
|
|
900
|
+
switch (t.kind) {
|
|
901
|
+
case "translate":
|
|
902
|
+
return [];
|
|
903
|
+
case "rotate":
|
|
904
|
+
case "reflectPoint":
|
|
905
|
+
case "dilate":
|
|
906
|
+
return [t.center];
|
|
907
|
+
case "reflectLine":
|
|
908
|
+
return [t.line];
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
function constraintRefs2D(c) {
|
|
912
|
+
switch (c.kind) {
|
|
913
|
+
case "onLine":
|
|
914
|
+
return [c.lineId];
|
|
915
|
+
case "onSegment":
|
|
916
|
+
return [c.segmentId];
|
|
917
|
+
case "onCircle":
|
|
918
|
+
return [c.circleId];
|
|
919
|
+
case "onPolygon":
|
|
920
|
+
return [c.polygonId];
|
|
921
|
+
case "midpoint":
|
|
922
|
+
return [c.p1, c.p2];
|
|
923
|
+
case "transformed":
|
|
924
|
+
return [c.source, ...transformRefs(c.transform)];
|
|
925
|
+
case "perpFoot":
|
|
926
|
+
return [c.from, c.onLine];
|
|
927
|
+
case "circumcenter":
|
|
928
|
+
return [c.vertices[0], c.vertices[1], c.vertices[2]];
|
|
929
|
+
case "incenter":
|
|
930
|
+
return [c.vertices[0], c.vertices[1], c.vertices[2]];
|
|
931
|
+
case "centroid":
|
|
932
|
+
return [c.vertices[0], c.vertices[1], c.vertices[2]];
|
|
933
|
+
case "orthocenter":
|
|
934
|
+
return [c.vertices[0], c.vertices[1], c.vertices[2]];
|
|
935
|
+
default:
|
|
936
|
+
return [];
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
var init_d_constraint2 = __esm({
|
|
940
|
+
"src/core/scene/kinds/2d-constraint.ts"() {
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
// src/core/scene/kinds/point.ts
|
|
945
|
+
function buildJxgTransforms(board, ctx, t) {
|
|
946
|
+
switch (t.kind) {
|
|
947
|
+
case "translate":
|
|
948
|
+
return [board.create("transform", [t.dx, t.dy], { type: "translate" })];
|
|
949
|
+
case "rotate": {
|
|
950
|
+
const c = ctx.resolveRef(t.center);
|
|
951
|
+
return [board.create("transform", [t.angleRad, c], { type: "rotate" })];
|
|
952
|
+
}
|
|
953
|
+
case "reflectPoint": {
|
|
954
|
+
const c = ctx.resolveRef(t.center);
|
|
955
|
+
return [board.create("transform", [Math.PI, c], { type: "rotate" })];
|
|
956
|
+
}
|
|
957
|
+
case "reflectLine": {
|
|
958
|
+
const l = ctx.resolveRef(t.line);
|
|
959
|
+
return [board.create("transform", [l], { type: "reflect" })];
|
|
960
|
+
}
|
|
961
|
+
case "dilate": {
|
|
962
|
+
const c = ctx.resolveRef(t.center);
|
|
963
|
+
return [
|
|
964
|
+
board.create("transform", [() => -c.X(), () => -c.Y()], { type: "translate" }),
|
|
965
|
+
board.create("transform", [t.k, t.k], { type: "scale" }),
|
|
966
|
+
board.create("transform", [() => c.X(), () => c.Y()], { type: "translate" })
|
|
967
|
+
];
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
var def3;
|
|
972
|
+
var init_point = __esm({
|
|
973
|
+
"src/core/scene/kinds/point.ts"() {
|
|
974
|
+
init_registry();
|
|
975
|
+
init_d_constraint2();
|
|
976
|
+
def3 = {
|
|
977
|
+
type: "point",
|
|
978
|
+
schemaVersion: 1,
|
|
979
|
+
migrate: {},
|
|
980
|
+
validate: (a) => {
|
|
981
|
+
if (!a || !a.constraint || !a.constraint.kind) {
|
|
982
|
+
throw new Error("point: constraint required");
|
|
983
|
+
}
|
|
984
|
+
const c = a.constraint;
|
|
985
|
+
if (c.kind === "perpFoot") {
|
|
986
|
+
if (!c.from || !c.onLine) {
|
|
987
|
+
throw new Error("point.perpFoot: from v\xE0 onLine b\u1EAFt bu\u1ED9c");
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (c.kind === "circumcenter") {
|
|
991
|
+
if (!Array.isArray(c.vertices) || c.vertices.length !== 3) {
|
|
992
|
+
throw new Error("point.circumcenter: vertices ph\u1EA3i l\xE0 tuple 3 id");
|
|
993
|
+
}
|
|
994
|
+
if (!c.vertices[0] || !c.vertices[1] || !c.vertices[2]) {
|
|
995
|
+
throw new Error("point.circumcenter: 3 vertex id ph\u1EA3i non-empty");
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (c.kind === "incenter") {
|
|
999
|
+
if (!Array.isArray(c.vertices) || c.vertices.length !== 3) {
|
|
1000
|
+
throw new Error("point.incenter: vertices ph\u1EA3i l\xE0 tuple 3 id");
|
|
1001
|
+
}
|
|
1002
|
+
if (!c.vertices[0] || !c.vertices[1] || !c.vertices[2]) {
|
|
1003
|
+
throw new Error("point.incenter: 3 vertex id ph\u1EA3i non-empty");
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (c.kind === "centroid") {
|
|
1007
|
+
if (!Array.isArray(c.vertices) || c.vertices.length !== 3) {
|
|
1008
|
+
throw new Error("point.centroid: vertices ph\u1EA3i l\xE0 tuple 3 id");
|
|
1009
|
+
}
|
|
1010
|
+
if (!c.vertices[0] || !c.vertices[1] || !c.vertices[2]) {
|
|
1011
|
+
throw new Error("point.centroid: 3 vertex id ph\u1EA3i non-empty");
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (c.kind === "orthocenter") {
|
|
1015
|
+
if (!Array.isArray(c.vertices) || c.vertices.length !== 3) {
|
|
1016
|
+
throw new Error("point.orthocenter: vertices ph\u1EA3i l\xE0 tuple 3 id");
|
|
1017
|
+
}
|
|
1018
|
+
if (!c.vertices[0] || !c.vertices[1] || !c.vertices[2]) {
|
|
1019
|
+
throw new Error("point.orthocenter: 3 vertex id ph\u1EA3i non-empty");
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
},
|
|
1023
|
+
dependsOn: (a) => constraintRefs2D(a.constraint),
|
|
1024
|
+
measure: (obj) => {
|
|
1025
|
+
const c = obj.attrs.constraint;
|
|
1026
|
+
if (c.kind === "free") {
|
|
1027
|
+
return [
|
|
1028
|
+
{ label: "x", value: c.x },
|
|
1029
|
+
{ label: "y", value: c.y }
|
|
1030
|
+
];
|
|
1031
|
+
}
|
|
1032
|
+
return null;
|
|
1033
|
+
},
|
|
1034
|
+
describe: (obj, state) => {
|
|
1035
|
+
const c = obj.attrs.constraint;
|
|
1036
|
+
if (c.kind === "free") return `\u0110i\u1EC3m ${obj.label}`;
|
|
1037
|
+
if (c.kind === "onAxis") return `${obj.label} tr\xEAn tr\u1EE5c ${c.axis}`;
|
|
1038
|
+
if (c.kind === "onLine") return `${obj.label} tr\xEAn \u0111\u01B0\u1EDDng ${state?.objects[c.lineId]?.label ?? c.lineId}`;
|
|
1039
|
+
if (c.kind === "onSegment") return `${obj.label} tr\xEAn \u0111o\u1EA1n ${state?.objects[c.segmentId]?.label ?? c.segmentId}`;
|
|
1040
|
+
if (c.kind === "onCircle") return `${obj.label} tr\xEAn \u0111\u01B0\u1EDDng tr\xF2n ${state?.objects[c.circleId]?.label ?? c.circleId}`;
|
|
1041
|
+
if (c.kind === "onPolygon") return `${obj.label} tr\xEAn \u0111a gi\xE1c ${state?.objects[c.polygonId]?.label ?? c.polygonId}`;
|
|
1042
|
+
if (c.kind === "midpoint") {
|
|
1043
|
+
const l1 = state?.objects[c.p1]?.label ?? c.p1;
|
|
1044
|
+
const l2 = state?.objects[c.p2]?.label ?? c.p2;
|
|
1045
|
+
return `${obj.label} = trung \u0111i\u1EC3m ${l1}${l2}`;
|
|
1046
|
+
}
|
|
1047
|
+
if (c.kind === "transformed") {
|
|
1048
|
+
const t = c.transform;
|
|
1049
|
+
const labelRef = (id) => state?.objects[id]?.label ?? id;
|
|
1050
|
+
const op = t.kind === "translate" ? `t\u1ECBnh ti\u1EBFn (${t.dx.toFixed(2)}, ${t.dy.toFixed(2)})` : t.kind === "rotate" ? `quay ${(t.angleRad * 180 / Math.PI).toFixed(0)}\xB0 quanh ${labelRef(t.center)}` : t.kind === "reflectLine" ? `\u0111\u1ED1i x\u1EE9ng qua ${labelRef(t.line)}` : t.kind === "reflectPoint" ? `\u0111\u1ED1i x\u1EE9ng qua \u0111i\u1EC3m ${labelRef(t.center)}` : t.kind === "dilate" ? `v\u1ECB t\u1EF1 k=${t.k} quanh ${labelRef(t.center)}` : "";
|
|
1051
|
+
return `${obj.label} = \u1EA3nh c\u1EE7a ${labelRef(c.source)} (${op})`;
|
|
1052
|
+
}
|
|
1053
|
+
if (c.kind === "perpFoot") {
|
|
1054
|
+
const fromLabel = state?.objects[c.from]?.label ?? c.from;
|
|
1055
|
+
const lineLabel = state?.objects[c.onLine]?.label ?? c.onLine;
|
|
1056
|
+
return `${obj.label} = ch\xE2n \u27C2 t\u1EEB ${fromLabel} xu\u1ED1ng ${lineLabel}`;
|
|
1057
|
+
}
|
|
1058
|
+
if (c.kind === "circumcenter") {
|
|
1059
|
+
const labels = c.vertices.map((id) => state?.objects[id]?.label ?? id).join("");
|
|
1060
|
+
return `${obj.label} = t\xE2m ngo\u1EA1i ti\u1EBFp \u0394${labels}`;
|
|
1061
|
+
}
|
|
1062
|
+
if (c.kind === "incenter") {
|
|
1063
|
+
const labels = c.vertices.map((id) => state?.objects[id]?.label ?? id).join("");
|
|
1064
|
+
return `${obj.label} = t\xE2m n\u1ED9i ti\u1EBFp \u0394${labels}`;
|
|
1065
|
+
}
|
|
1066
|
+
if (c.kind === "centroid") {
|
|
1067
|
+
const labels = c.vertices.map((id) => state?.objects[id]?.label ?? id).join("");
|
|
1068
|
+
return `${obj.label} = tr\u1ECDng t\xE2m \u0394${labels}`;
|
|
1069
|
+
}
|
|
1070
|
+
if (c.kind === "orthocenter") {
|
|
1071
|
+
const labels = c.vertices.map((id) => state?.objects[id]?.label ?? id).join("");
|
|
1072
|
+
return `${obj.label} = tr\u1EF1c t\xE2m \u0394${labels}`;
|
|
1073
|
+
}
|
|
1074
|
+
return `\u0110i\u1EC3m ${obj.label}`;
|
|
1075
|
+
},
|
|
1076
|
+
render: (obj, ctx) => {
|
|
1077
|
+
const board = ctx.jxg;
|
|
1078
|
+
const c = obj.attrs.constraint;
|
|
1079
|
+
const opts = {
|
|
1080
|
+
name: obj.label,
|
|
1081
|
+
withLabel: obj.attrs.showLabel ?? true,
|
|
1082
|
+
visible: obj.visible,
|
|
1083
|
+
fixed: obj.locked,
|
|
1084
|
+
strokeColor: obj.attrs.color ?? "#1e40af",
|
|
1085
|
+
fillColor: obj.attrs.color ?? "#1e40af",
|
|
1086
|
+
face: obj.attrs.face ?? "o",
|
|
1087
|
+
size: obj.attrs.size ?? 4
|
|
1088
|
+
};
|
|
1089
|
+
if (c.kind === "free") return board.create("point", [c.x, c.y], opts);
|
|
1090
|
+
if (c.kind === "onAxis") {
|
|
1091
|
+
const coords = c.axis === "x" ? [c.t, 0] : [0, c.t];
|
|
1092
|
+
return board.create("point", coords, opts);
|
|
1093
|
+
}
|
|
1094
|
+
if (c.kind === "onLine") {
|
|
1095
|
+
const line = ctx.resolveRef(c.lineId);
|
|
1096
|
+
return board.create("glider", [c.t, c.t, line], opts);
|
|
1097
|
+
}
|
|
1098
|
+
if (c.kind === "onSegment") {
|
|
1099
|
+
const seg = ctx.resolveRef(c.segmentId);
|
|
1100
|
+
return board.create("glider", [c.t, c.t, seg], opts);
|
|
1101
|
+
}
|
|
1102
|
+
if (c.kind === "onCircle") {
|
|
1103
|
+
const circle = ctx.resolveRef(c.circleId);
|
|
1104
|
+
return board.create("glider", [Math.cos(c.theta), Math.sin(c.theta), circle], opts);
|
|
1105
|
+
}
|
|
1106
|
+
if (c.kind === "onPolygon") {
|
|
1107
|
+
const poly = ctx.resolveRef(c.polygonId);
|
|
1108
|
+
return board.create("glider", [c.u, c.v, poly], opts);
|
|
1109
|
+
}
|
|
1110
|
+
if (c.kind === "midpoint") {
|
|
1111
|
+
const p1 = ctx.resolveRef(c.p1);
|
|
1112
|
+
const p2 = ctx.resolveRef(c.p2);
|
|
1113
|
+
return board.create("midpoint", [p1, p2], opts);
|
|
1114
|
+
}
|
|
1115
|
+
if (c.kind === "transformed") {
|
|
1116
|
+
const src = ctx.resolveRef(c.source);
|
|
1117
|
+
const transforms = buildJxgTransforms(board, ctx, c.transform);
|
|
1118
|
+
const parent = transforms.length === 1 ? transforms[0] : transforms;
|
|
1119
|
+
const pt = board.create("point", [src, parent], opts);
|
|
1120
|
+
pt._helpers = transforms;
|
|
1121
|
+
return pt;
|
|
1122
|
+
}
|
|
1123
|
+
if (c.kind === "perpFoot") {
|
|
1124
|
+
const from = ctx.resolveRef(c.from);
|
|
1125
|
+
const onLine = ctx.resolveRef(c.onLine);
|
|
1126
|
+
return board.create("perpendicularpoint", [onLine, from], opts);
|
|
1127
|
+
}
|
|
1128
|
+
if (c.kind === "circumcenter") {
|
|
1129
|
+
const a = ctx.resolveRef(c.vertices[0]);
|
|
1130
|
+
const b = ctx.resolveRef(c.vertices[1]);
|
|
1131
|
+
const c3 = ctx.resolveRef(c.vertices[2]);
|
|
1132
|
+
return board.create("circumcenter", [a, b, c3], opts);
|
|
1133
|
+
}
|
|
1134
|
+
if (c.kind === "incenter") {
|
|
1135
|
+
const a = ctx.resolveRef(c.vertices[0]);
|
|
1136
|
+
const b = ctx.resolveRef(c.vertices[1]);
|
|
1137
|
+
const c3 = ctx.resolveRef(c.vertices[2]);
|
|
1138
|
+
return board.create("incenter", [a, b, c3], opts);
|
|
1139
|
+
}
|
|
1140
|
+
if (c.kind === "centroid") {
|
|
1141
|
+
const a = ctx.resolveRef(c.vertices[0]);
|
|
1142
|
+
const b = ctx.resolveRef(c.vertices[1]);
|
|
1143
|
+
const c3 = ctx.resolveRef(c.vertices[2]);
|
|
1144
|
+
return board.create("point", [
|
|
1145
|
+
() => (a.X() + b.X() + c3.X()) / 3,
|
|
1146
|
+
() => (a.Y() + b.Y() + c3.Y()) / 3
|
|
1147
|
+
], opts);
|
|
1148
|
+
}
|
|
1149
|
+
if (c.kind === "orthocenter") {
|
|
1150
|
+
const a = ctx.resolveRef(c.vertices[0]);
|
|
1151
|
+
const b = ctx.resolveRef(c.vertices[1]);
|
|
1152
|
+
const c3 = ctx.resolveRef(c.vertices[2]);
|
|
1153
|
+
const hide = { visible: false, withLabel: false, fixed: true, name: "" };
|
|
1154
|
+
const lineBC = board.create("line", [b, c3], hide);
|
|
1155
|
+
const altA = board.create("perpendicular", [lineBC, a], hide);
|
|
1156
|
+
const lineAC = board.create("line", [a, c3], hide);
|
|
1157
|
+
const altB = board.create("perpendicular", [lineAC, b], hide);
|
|
1158
|
+
const ortho = board.create("intersection", [altA, altB, 0], opts);
|
|
1159
|
+
ortho._helpers = [lineBC, altA, lineAC, altB];
|
|
1160
|
+
return ortho;
|
|
1161
|
+
}
|
|
1162
|
+
return board.create("point", [0, 0], opts);
|
|
1163
|
+
},
|
|
1164
|
+
/**
|
|
1165
|
+
* Free → Free update giữ nguyên JxgObj identity (gọi setPositionDirectly +
|
|
1166
|
+
* setAttribute) để các object phụ thuộc (line/segment/...) không bị stale
|
|
1167
|
+
* parent ref. Đổi constraint kind → throw để renderer fallback recreate.
|
|
1168
|
+
*
|
|
1169
|
+
* Đây cũng là endpoint cho drag-sync dispatch trong JxgRenderer: khi user
|
|
1170
|
+
* kéo điểm, listener dispatch UPDATE_ATTRS → update hook chạy, vị trí đã
|
|
1171
|
+
* đúng sẵn nên setPositionDirectly là no-op nhưng vẫn cần để sync các attrs
|
|
1172
|
+
* khác (label/color/...).
|
|
1173
|
+
*/
|
|
1174
|
+
update: (obj, prev, ctx, existing) => {
|
|
1175
|
+
const c = obj.attrs.constraint;
|
|
1176
|
+
const oldC = prev.attrs.constraint;
|
|
1177
|
+
if (c.kind === "free" && oldC.kind === "free") {
|
|
1178
|
+
const el = existing;
|
|
1179
|
+
if (typeof el.setPositionDirectly === "function") {
|
|
1180
|
+
try {
|
|
1181
|
+
el.setPositionDirectly(1, [c.x, c.y]);
|
|
1182
|
+
} catch {
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
if (typeof el.setAttribute === "function") {
|
|
1186
|
+
try {
|
|
1187
|
+
el.setAttribute({
|
|
1188
|
+
name: obj.label,
|
|
1189
|
+
withLabel: obj.attrs.showLabel ?? true,
|
|
1190
|
+
visible: obj.visible,
|
|
1191
|
+
fixed: obj.locked,
|
|
1192
|
+
strokeColor: obj.attrs.color ?? "#1e40af",
|
|
1193
|
+
fillColor: obj.attrs.color ?? "#1e40af",
|
|
1194
|
+
face: obj.attrs.face ?? "o",
|
|
1195
|
+
size: obj.attrs.size ?? 4
|
|
1196
|
+
});
|
|
1197
|
+
} catch {
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
throw new Error("point: constraint kind changed \u2014 recreate");
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
registerKind(def3);
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
// src/core/scene/kinds/segment.ts
|
|
1210
|
+
var def4;
|
|
1211
|
+
var init_segment = __esm({
|
|
1212
|
+
"src/core/scene/kinds/segment.ts"() {
|
|
1213
|
+
init_registry();
|
|
1214
|
+
init_labelOf();
|
|
1215
|
+
def4 = {
|
|
1216
|
+
type: "segment",
|
|
1217
|
+
schemaVersion: 1,
|
|
1218
|
+
migrate: {},
|
|
1219
|
+
validate: (a) => {
|
|
1220
|
+
if (!a?.p1 || !a?.p2) throw new Error("segment: p1 v\xE0 p2 b\u1EAFt bu\u1ED9c");
|
|
1221
|
+
},
|
|
1222
|
+
dependsOn: (a) => [a.p1, a.p2],
|
|
1223
|
+
measure: (obj, state) => {
|
|
1224
|
+
const p1 = state.objects[obj.attrs.p1];
|
|
1225
|
+
const p2 = state.objects[obj.attrs.p2];
|
|
1226
|
+
if (!p1 || !p2) return null;
|
|
1227
|
+
const c1 = p1.attrs.constraint;
|
|
1228
|
+
const c2 = p2.attrs.constraint;
|
|
1229
|
+
if (c1?.kind !== "free" || c2?.kind !== "free") return null;
|
|
1230
|
+
const dx = (c2.x ?? 0) - (c1.x ?? 0);
|
|
1231
|
+
const dy = (c2.y ?? 0) - (c1.y ?? 0);
|
|
1232
|
+
return [{ label: "length", value: Math.hypot(dx, dy) }];
|
|
1233
|
+
},
|
|
1234
|
+
describe: (obj, state) => `\u0110o\u1EA1n th\u1EB3ng ${labelOf(obj.attrs.p1, state)}${labelOf(obj.attrs.p2, state)}`,
|
|
1235
|
+
render: (obj, ctx) => {
|
|
1236
|
+
const board = ctx.jxg;
|
|
1237
|
+
const p1 = ctx.resolveRef(obj.attrs.p1);
|
|
1238
|
+
const p2 = ctx.resolveRef(obj.attrs.p2);
|
|
1239
|
+
return board.create("segment", [p1, p2], {
|
|
1240
|
+
name: obj.label,
|
|
1241
|
+
withLabel: obj.attrs.showLabel ?? false,
|
|
1242
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1243
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1244
|
+
dash: obj.attrs.dash ?? 0,
|
|
1245
|
+
visible: obj.visible,
|
|
1246
|
+
fixed: obj.locked
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
registerKind(def4);
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
// src/core/scene/kinds/line.ts
|
|
1255
|
+
function stripBorderSuffix(id) {
|
|
1256
|
+
const m = /^(.+):border:\d+$/.exec(id);
|
|
1257
|
+
return m ? m[1] : id;
|
|
1258
|
+
}
|
|
1259
|
+
function constructionRefs(c) {
|
|
1260
|
+
switch (c.kind) {
|
|
1261
|
+
case "perpendicular":
|
|
1262
|
+
case "parallel":
|
|
1263
|
+
return [c.throughPoint, stripBorderSuffix(c.toLine)];
|
|
1264
|
+
case "perpBisector":
|
|
1265
|
+
return [c.p1, c.p2];
|
|
1266
|
+
case "angleBisector":
|
|
1267
|
+
return [c.p1, c.vertex, c.p2];
|
|
1268
|
+
case "angleBisectorLines":
|
|
1269
|
+
return [stripBorderSuffix(c.line1), stripBorderSuffix(c.line2)];
|
|
1270
|
+
case "tangent":
|
|
1271
|
+
return [c.throughPoint, c.toCircle];
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
var def5;
|
|
1275
|
+
var init_line = __esm({
|
|
1276
|
+
"src/core/scene/kinds/line.ts"() {
|
|
1277
|
+
init_registry();
|
|
1278
|
+
init_labelOf();
|
|
1279
|
+
def5 = {
|
|
1280
|
+
type: "line",
|
|
1281
|
+
schemaVersion: 1,
|
|
1282
|
+
migrate: {},
|
|
1283
|
+
validate: (a) => {
|
|
1284
|
+
if (a?.construction) return;
|
|
1285
|
+
if (!a?.p1 || !a?.p2) throw new Error("line: p1 v\xE0 p2 b\u1EAFt bu\u1ED9c (ho\u1EB7c construction)");
|
|
1286
|
+
},
|
|
1287
|
+
dependsOn: (a) => a.construction ? constructionRefs(a.construction) : [a.p1, a.p2],
|
|
1288
|
+
describe: (obj, state) => {
|
|
1289
|
+
const L = (id) => labelOf(id, state);
|
|
1290
|
+
const c = obj.attrs.construction;
|
|
1291
|
+
if (!c) return `\u0110\u01B0\u1EDDng th\u1EB3ng ${L(obj.attrs.p1)}${L(obj.attrs.p2)}`;
|
|
1292
|
+
switch (c.kind) {
|
|
1293
|
+
case "perpendicular":
|
|
1294
|
+
return `${obj.label} \u27C2 ${L(c.toLine)} qua ${L(c.throughPoint)}`;
|
|
1295
|
+
case "parallel":
|
|
1296
|
+
return `${obj.label} \u2225 ${L(c.toLine)} qua ${L(c.throughPoint)}`;
|
|
1297
|
+
case "perpBisector":
|
|
1298
|
+
return `${obj.label}: trung tr\u1EF1c ${L(c.p1)}${L(c.p2)}`;
|
|
1299
|
+
case "angleBisector":
|
|
1300
|
+
return `${obj.label}: ph\xE2n gi\xE1c g\xF3c ${L(c.p1)}${L(c.vertex)}${L(c.p2)}`;
|
|
1301
|
+
case "angleBisectorLines":
|
|
1302
|
+
return `${obj.label}: ph\xE2n gi\xE1c ${L(c.line1)} & ${L(c.line2)} (${c.branch === 0 ? "1" : "2"})`;
|
|
1303
|
+
case "tangent":
|
|
1304
|
+
return `${obj.label}: ti\u1EBFp tuy\u1EBFn ${L(c.toCircle)} qua ${L(c.throughPoint)}`;
|
|
1305
|
+
}
|
|
1306
|
+
},
|
|
1307
|
+
render: (obj, ctx) => {
|
|
1308
|
+
const board = ctx.jxg;
|
|
1309
|
+
const baseOpts = {
|
|
1310
|
+
name: obj.label,
|
|
1311
|
+
withLabel: obj.attrs.showLabel ?? false,
|
|
1312
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1313
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1314
|
+
dash: obj.attrs.dash ?? 0,
|
|
1315
|
+
visible: obj.visible,
|
|
1316
|
+
fixed: obj.locked
|
|
1317
|
+
};
|
|
1318
|
+
const c = obj.attrs.construction;
|
|
1319
|
+
if (!c) {
|
|
1320
|
+
const p1 = ctx.resolveRef(obj.attrs.p1);
|
|
1321
|
+
const p2 = ctx.resolveRef(obj.attrs.p2);
|
|
1322
|
+
return board.create("line", [p1, p2], {
|
|
1323
|
+
...baseOpts,
|
|
1324
|
+
straightFirst: true,
|
|
1325
|
+
straightLast: true
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
switch (c.kind) {
|
|
1329
|
+
case "perpendicular": {
|
|
1330
|
+
const through = ctx.resolveRef(c.throughPoint);
|
|
1331
|
+
const toLine = ctx.resolveRef(c.toLine);
|
|
1332
|
+
return board.create("perpendicular", [toLine, through], baseOpts);
|
|
1333
|
+
}
|
|
1334
|
+
case "parallel": {
|
|
1335
|
+
const through = ctx.resolveRef(c.throughPoint);
|
|
1336
|
+
const toLine = ctx.resolveRef(c.toLine);
|
|
1337
|
+
return board.create("parallel", [toLine, through], baseOpts);
|
|
1338
|
+
}
|
|
1339
|
+
case "perpBisector": {
|
|
1340
|
+
const p1 = ctx.resolveRef(c.p1);
|
|
1341
|
+
const p2 = ctx.resolveRef(c.p2);
|
|
1342
|
+
const mid = board.create("midpoint", [p1, p2], {
|
|
1343
|
+
visible: false,
|
|
1344
|
+
withLabel: false,
|
|
1345
|
+
fixed: true,
|
|
1346
|
+
name: ""
|
|
1347
|
+
});
|
|
1348
|
+
const helperLine = board.create("line", [p1, p2], {
|
|
1349
|
+
visible: false,
|
|
1350
|
+
withLabel: false,
|
|
1351
|
+
fixed: true,
|
|
1352
|
+
name: "",
|
|
1353
|
+
straightFirst: true,
|
|
1354
|
+
straightLast: true
|
|
1355
|
+
});
|
|
1356
|
+
const bisector = board.create("perpendicular", [helperLine, mid], baseOpts);
|
|
1357
|
+
bisector._helpers = [mid, helperLine];
|
|
1358
|
+
return bisector;
|
|
1359
|
+
}
|
|
1360
|
+
case "angleBisector": {
|
|
1361
|
+
const p1 = ctx.resolveRef(c.p1);
|
|
1362
|
+
const vertex = ctx.resolveRef(c.vertex);
|
|
1363
|
+
const p2 = ctx.resolveRef(c.p2);
|
|
1364
|
+
return board.create("bisector", [p1, vertex, p2], baseOpts);
|
|
1365
|
+
}
|
|
1366
|
+
case "angleBisectorLines": {
|
|
1367
|
+
const line1Jxg = ctx.resolveRef(c.line1);
|
|
1368
|
+
const line2Jxg = ctx.resolveRef(c.line2);
|
|
1369
|
+
const comp = board.create("bisectorlines", [line1Jxg, line2Jxg], {
|
|
1370
|
+
line1: { visible: false, withLabel: false, fixed: true, name: "" },
|
|
1371
|
+
line2: { visible: false, withLabel: false, fixed: true, name: "" }
|
|
1372
|
+
});
|
|
1373
|
+
const selected = c.branch === 0 ? comp.line1 : comp.line2;
|
|
1374
|
+
const other = c.branch === 0 ? comp.line2 : comp.line1;
|
|
1375
|
+
selected.setAttribute({
|
|
1376
|
+
...baseOpts,
|
|
1377
|
+
visible: obj.visible,
|
|
1378
|
+
fixed: obj.locked
|
|
1379
|
+
});
|
|
1380
|
+
selected._helpers = [other];
|
|
1381
|
+
return selected;
|
|
1382
|
+
}
|
|
1383
|
+
case "tangent": {
|
|
1384
|
+
const through = ctx.resolveRef(c.throughPoint);
|
|
1385
|
+
const toCircle = ctx.resolveRef(c.toCircle);
|
|
1386
|
+
const branch = c.branch ?? "on";
|
|
1387
|
+
if (branch === "on") {
|
|
1388
|
+
const glider = board.create("glider", [through.X(), through.Y(), toCircle], {
|
|
1389
|
+
visible: false,
|
|
1390
|
+
withLabel: false,
|
|
1391
|
+
fixed: true,
|
|
1392
|
+
name: ""
|
|
1393
|
+
});
|
|
1394
|
+
const tangent2 = board.create("tangent", [glider], baseOpts);
|
|
1395
|
+
tangent2._helpers = [glider];
|
|
1396
|
+
return tangent2;
|
|
1397
|
+
}
|
|
1398
|
+
const center = toCircle.center;
|
|
1399
|
+
const mid = board.create("midpoint", [center, through], {
|
|
1400
|
+
visible: false,
|
|
1401
|
+
withLabel: false,
|
|
1402
|
+
fixed: true,
|
|
1403
|
+
name: ""
|
|
1404
|
+
});
|
|
1405
|
+
const thales = board.create("circle", [mid, through], {
|
|
1406
|
+
visible: false,
|
|
1407
|
+
withLabel: false,
|
|
1408
|
+
fixed: true,
|
|
1409
|
+
strokeOpacity: 0,
|
|
1410
|
+
fillOpacity: 0
|
|
1411
|
+
});
|
|
1412
|
+
const touch = board.create("intersection", [thales, toCircle, branch], {
|
|
1413
|
+
visible: false,
|
|
1414
|
+
withLabel: false,
|
|
1415
|
+
fixed: true,
|
|
1416
|
+
name: ""
|
|
1417
|
+
});
|
|
1418
|
+
const tangent = board.create("line", [through, touch], {
|
|
1419
|
+
...baseOpts,
|
|
1420
|
+
straightFirst: true,
|
|
1421
|
+
straightLast: true
|
|
1422
|
+
});
|
|
1423
|
+
tangent._helpers = [mid, thales, touch];
|
|
1424
|
+
return tangent;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
registerKind(def5);
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
// src/core/scene/kinds/ray.ts
|
|
1434
|
+
var def6;
|
|
1435
|
+
var init_ray = __esm({
|
|
1436
|
+
"src/core/scene/kinds/ray.ts"() {
|
|
1437
|
+
init_registry();
|
|
1438
|
+
init_labelOf();
|
|
1439
|
+
def6 = {
|
|
1440
|
+
type: "ray",
|
|
1441
|
+
schemaVersion: 1,
|
|
1442
|
+
migrate: {},
|
|
1443
|
+
validate: (a) => {
|
|
1444
|
+
if (!a?.origin || !a?.through) throw new Error("ray: origin v\xE0 through b\u1EAFt bu\u1ED9c");
|
|
1445
|
+
},
|
|
1446
|
+
dependsOn: (a) => [a.origin, a.through],
|
|
1447
|
+
describe: (obj, state) => `Tia ${labelOf(obj.attrs.origin, state)}${labelOf(obj.attrs.through, state)}`,
|
|
1448
|
+
render: (obj, ctx) => {
|
|
1449
|
+
const board = ctx.jxg;
|
|
1450
|
+
const o = ctx.resolveRef(obj.attrs.origin);
|
|
1451
|
+
const t = ctx.resolveRef(obj.attrs.through);
|
|
1452
|
+
return board.create("line", [o, t], {
|
|
1453
|
+
name: obj.label,
|
|
1454
|
+
straightFirst: false,
|
|
1455
|
+
straightLast: true,
|
|
1456
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1457
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1458
|
+
dash: obj.attrs.dash ?? 0,
|
|
1459
|
+
visible: obj.visible,
|
|
1460
|
+
fixed: obj.locked
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
registerKind(def6);
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
|
|
1468
|
+
// src/core/scene/kinds/vector.ts
|
|
1469
|
+
var def7;
|
|
1470
|
+
var init_vector = __esm({
|
|
1471
|
+
"src/core/scene/kinds/vector.ts"() {
|
|
1472
|
+
init_registry();
|
|
1473
|
+
init_labelOf();
|
|
1474
|
+
def7 = {
|
|
1475
|
+
type: "vector",
|
|
1476
|
+
schemaVersion: 1,
|
|
1477
|
+
migrate: {},
|
|
1478
|
+
validate: (a) => {
|
|
1479
|
+
if (!a?.from || !a?.to) throw new Error("vector: from v\xE0 to b\u1EAFt bu\u1ED9c");
|
|
1480
|
+
},
|
|
1481
|
+
dependsOn: (a) => [a.from, a.to],
|
|
1482
|
+
describe: (obj, state) => `Vector ${labelOf(obj.attrs.from, state)}${labelOf(obj.attrs.to, state)}`,
|
|
1483
|
+
render: (obj, ctx) => {
|
|
1484
|
+
const board = ctx.jxg;
|
|
1485
|
+
const f = ctx.resolveRef(obj.attrs.from);
|
|
1486
|
+
const t = ctx.resolveRef(obj.attrs.to);
|
|
1487
|
+
return board.create("arrow", [f, t], {
|
|
1488
|
+
name: obj.label,
|
|
1489
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1490
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1491
|
+
visible: obj.visible,
|
|
1492
|
+
fixed: obj.locked
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1496
|
+
registerKind(def7);
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1500
|
+
// src/core/scene/kinds/circle.ts
|
|
1501
|
+
function constructionRefs2(c) {
|
|
1502
|
+
switch (c.kind) {
|
|
1503
|
+
case "circumscribed":
|
|
1504
|
+
return [c.p1, c.p2, c.p3];
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
var def8;
|
|
1508
|
+
var init_circle = __esm({
|
|
1509
|
+
"src/core/scene/kinds/circle.ts"() {
|
|
1510
|
+
init_registry();
|
|
1511
|
+
init_labelOf();
|
|
1512
|
+
def8 = {
|
|
1513
|
+
type: "circle",
|
|
1514
|
+
schemaVersion: 1,
|
|
1515
|
+
migrate: {},
|
|
1516
|
+
validate: (a) => {
|
|
1517
|
+
if (a?.construction) return;
|
|
1518
|
+
if (!a?.center || !a?.surfacePoint) {
|
|
1519
|
+
throw new Error("circle: center v\xE0 surfacePoint b\u1EAFt bu\u1ED9c (ho\u1EB7c construction)");
|
|
1520
|
+
}
|
|
1521
|
+
},
|
|
1522
|
+
dependsOn: (a) => a.construction ? constructionRefs2(a.construction) : [a.center, a.surfacePoint],
|
|
1523
|
+
measure: (obj, state) => {
|
|
1524
|
+
if (obj.attrs.construction) return null;
|
|
1525
|
+
const center = obj.attrs.center ? state.objects[obj.attrs.center] : void 0;
|
|
1526
|
+
const surface = obj.attrs.surfacePoint ? state.objects[obj.attrs.surfacePoint] : void 0;
|
|
1527
|
+
if (!center || !surface) return null;
|
|
1528
|
+
const c1 = center.attrs.constraint;
|
|
1529
|
+
const c2 = surface.attrs.constraint;
|
|
1530
|
+
if (c1?.kind !== "free" || c2?.kind !== "free") return null;
|
|
1531
|
+
const dx = (c2.x ?? 0) - (c1.x ?? 0);
|
|
1532
|
+
const dy = (c2.y ?? 0) - (c1.y ?? 0);
|
|
1533
|
+
return [{ label: "r", value: Math.hypot(dx, dy) }];
|
|
1534
|
+
},
|
|
1535
|
+
describe: (obj, state) => {
|
|
1536
|
+
const L = (id) => labelOf(id, state);
|
|
1537
|
+
const c = obj.attrs.construction;
|
|
1538
|
+
if (c?.kind === "circumscribed") {
|
|
1539
|
+
return `\u0110\u01B0\u1EDDng tr\xF2n \u0111i qua ${L(c.p1)}${L(c.p2)}${L(c.p3)}`;
|
|
1540
|
+
}
|
|
1541
|
+
return `\u0110\u01B0\u1EDDng tr\xF2n t\xE2m ${L(obj.attrs.center)} b\xE1n k\xEDnh ${L(obj.attrs.center)}${L(obj.attrs.surfacePoint)}`;
|
|
1542
|
+
},
|
|
1543
|
+
render: (obj, ctx) => {
|
|
1544
|
+
const board = ctx.jxg;
|
|
1545
|
+
const baseOpts = {
|
|
1546
|
+
name: obj.label,
|
|
1547
|
+
withLabel: obj.attrs.showLabel ?? false,
|
|
1548
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1549
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1550
|
+
dash: obj.attrs.dash ?? 0,
|
|
1551
|
+
fillColor: "none",
|
|
1552
|
+
visible: obj.visible,
|
|
1553
|
+
fixed: obj.locked
|
|
1554
|
+
};
|
|
1555
|
+
const c = obj.attrs.construction;
|
|
1556
|
+
if (c?.kind === "circumscribed") {
|
|
1557
|
+
const p1 = ctx.resolveRef(c.p1);
|
|
1558
|
+
const p2 = ctx.resolveRef(c.p2);
|
|
1559
|
+
const p3 = ctx.resolveRef(c.p3);
|
|
1560
|
+
return board.create("circumcircle", [p1, p2, p3], baseOpts);
|
|
1561
|
+
}
|
|
1562
|
+
const center = ctx.resolveRef(obj.attrs.center);
|
|
1563
|
+
const surface = ctx.resolveRef(obj.attrs.surfacePoint);
|
|
1564
|
+
return board.create("circle", [center, surface], baseOpts);
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
registerKind(def8);
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
// src/core/scene/kinds/arc.ts
|
|
1572
|
+
function constructionRefs3(c) {
|
|
1573
|
+
switch (c.kind) {
|
|
1574
|
+
case "semicircle":
|
|
1575
|
+
return [c.p1, c.p2];
|
|
1576
|
+
case "byCenter":
|
|
1577
|
+
return [c.center, c.p1, c.p2];
|
|
1578
|
+
case "by3Points":
|
|
1579
|
+
return [c.p1, c.p2, c.p3];
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
var def9;
|
|
1583
|
+
var init_arc = __esm({
|
|
1584
|
+
"src/core/scene/kinds/arc.ts"() {
|
|
1585
|
+
init_registry();
|
|
1586
|
+
init_labelOf();
|
|
1587
|
+
def9 = {
|
|
1588
|
+
type: "arc",
|
|
1589
|
+
schemaVersion: 1,
|
|
1590
|
+
migrate: {},
|
|
1591
|
+
validate: (a) => {
|
|
1592
|
+
const c = a?.construction;
|
|
1593
|
+
if (!c) throw new Error("arc: construction b\u1EAFt bu\u1ED9c");
|
|
1594
|
+
if (c.kind === "semicircle") {
|
|
1595
|
+
if (!c.p1 || !c.p2) throw new Error("arc.semicircle: p1, p2 b\u1EAFt bu\u1ED9c");
|
|
1596
|
+
} else if (c.kind === "byCenter") {
|
|
1597
|
+
if (!c.center || !c.p1 || !c.p2) throw new Error("arc.byCenter: center, p1, p2 b\u1EAFt bu\u1ED9c");
|
|
1598
|
+
} else if (c.kind === "by3Points") {
|
|
1599
|
+
if (!c.p1 || !c.p2 || !c.p3) throw new Error("arc.by3Points: p1, p2, p3 b\u1EAFt bu\u1ED9c");
|
|
1600
|
+
}
|
|
1601
|
+
},
|
|
1602
|
+
dependsOn: (a) => constructionRefs3(a.construction),
|
|
1603
|
+
describe: (obj, state) => {
|
|
1604
|
+
const L = (id) => labelOf(id, state);
|
|
1605
|
+
const c = obj.attrs.construction;
|
|
1606
|
+
switch (c.kind) {
|
|
1607
|
+
case "semicircle":
|
|
1608
|
+
return `N\u1EEDa \u0111\u01B0\u1EDDng tr\xF2n \u0111\u01B0\u1EDDng k\xEDnh ${L(c.p1)}${L(c.p2)}`;
|
|
1609
|
+
case "byCenter":
|
|
1610
|
+
return `Cung tr\xF2n t\xE2m ${L(c.center)} t\u1EEB ${L(c.p1)} \u0111\u1EBFn ${L(c.p2)}`;
|
|
1611
|
+
case "by3Points":
|
|
1612
|
+
return `Cung tr\xF2n qua ${L(c.p1)}${L(c.p2)}${L(c.p3)}`;
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
render: (obj, ctx) => {
|
|
1616
|
+
const board = ctx.jxg;
|
|
1617
|
+
const baseOpts = {
|
|
1618
|
+
name: obj.label,
|
|
1619
|
+
withLabel: obj.attrs.showLabel ?? false,
|
|
1620
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1621
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1622
|
+
dash: obj.attrs.dash ?? 0,
|
|
1623
|
+
fillColor: "none",
|
|
1624
|
+
visible: obj.visible,
|
|
1625
|
+
fixed: obj.locked
|
|
1626
|
+
};
|
|
1627
|
+
const c = obj.attrs.construction;
|
|
1628
|
+
if (c.kind === "semicircle") {
|
|
1629
|
+
const p1 = ctx.resolveRef(c.p1);
|
|
1630
|
+
const p2 = ctx.resolveRef(c.p2);
|
|
1631
|
+
return board.create("semicircle", [p1, p2], baseOpts);
|
|
1632
|
+
}
|
|
1633
|
+
if (c.kind === "byCenter") {
|
|
1634
|
+
const O = ctx.resolveRef(c.center);
|
|
1635
|
+
const A2 = ctx.resolveRef(c.p1);
|
|
1636
|
+
const B2 = ctx.resolveRef(c.p2);
|
|
1637
|
+
return board.create("arc", [O, A2, B2], baseOpts);
|
|
1638
|
+
}
|
|
1639
|
+
const A = ctx.resolveRef(c.p1);
|
|
1640
|
+
const B = ctx.resolveRef(c.p2);
|
|
1641
|
+
const C = ctx.resolveRef(c.p3);
|
|
1642
|
+
return board.create("circumcirclearc", [A, B, C], baseOpts);
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
registerKind(def9);
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
// src/core/scene/kinds/sector.ts
|
|
1650
|
+
var def10;
|
|
1651
|
+
var init_sector = __esm({
|
|
1652
|
+
"src/core/scene/kinds/sector.ts"() {
|
|
1653
|
+
init_registry();
|
|
1654
|
+
init_labelOf();
|
|
1655
|
+
def10 = {
|
|
1656
|
+
type: "sector",
|
|
1657
|
+
schemaVersion: 1,
|
|
1658
|
+
migrate: {},
|
|
1659
|
+
validate: (a) => {
|
|
1660
|
+
const c = a?.construction;
|
|
1661
|
+
if (!c) throw new Error("sector: construction b\u1EAFt bu\u1ED9c");
|
|
1662
|
+
if (c.kind === "byCenter") {
|
|
1663
|
+
if (!c.center || !c.p1 || !c.p2) {
|
|
1664
|
+
throw new Error("sector.byCenter: center, p1, p2 b\u1EAFt bu\u1ED9c");
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
},
|
|
1668
|
+
dependsOn: (a) => {
|
|
1669
|
+
const c = a.construction;
|
|
1670
|
+
return [c.center, c.p1, c.p2];
|
|
1671
|
+
},
|
|
1672
|
+
describe: (obj, state) => {
|
|
1673
|
+
const L = (id) => labelOf(id, state);
|
|
1674
|
+
const c = obj.attrs.construction;
|
|
1675
|
+
return `H\xECnh qu\u1EA1t t\xE2m ${L(c.center)} t\u1EEB ${L(c.p1)} \u0111\u1EBFn ${L(c.p2)}`;
|
|
1676
|
+
},
|
|
1677
|
+
render: (obj, ctx) => {
|
|
1678
|
+
const board = ctx.jxg;
|
|
1679
|
+
const c = obj.attrs.construction;
|
|
1680
|
+
const O = ctx.resolveRef(c.center);
|
|
1681
|
+
const A = ctx.resolveRef(c.p1);
|
|
1682
|
+
const B = ctx.resolveRef(c.p2);
|
|
1683
|
+
return board.create("sector", [O, A, B], {
|
|
1684
|
+
name: obj.label,
|
|
1685
|
+
withLabel: obj.attrs.showLabel ?? false,
|
|
1686
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1687
|
+
strokeWidth: obj.attrs.width ?? 2,
|
|
1688
|
+
fillColor: obj.attrs.fillColor ?? "#f59e0b",
|
|
1689
|
+
fillOpacity: obj.attrs.fillOpacity ?? 0.18,
|
|
1690
|
+
visible: obj.visible,
|
|
1691
|
+
fixed: obj.locked
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
registerKind(def10);
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
// src/core/scene/kinds/polygon.ts
|
|
1700
|
+
function regularPolygonName(n) {
|
|
1701
|
+
if (n === 3) return "Tam gi\xE1c \u0111\u1EC1u";
|
|
1702
|
+
if (n === 4) return "H\xECnh vu\xF4ng";
|
|
1703
|
+
if (n === 5) return "Ng\u0169 gi\xE1c \u0111\u1EC1u";
|
|
1704
|
+
if (n === 6) return "L\u1EE5c gi\xE1c \u0111\u1EC1u";
|
|
1705
|
+
return `${n}-gi\xE1c \u0111\u1EC1u`;
|
|
1706
|
+
}
|
|
1707
|
+
function regularVertexLabels(p1Label, p2Label, n) {
|
|
1708
|
+
const A = "A".charCodeAt(0);
|
|
1709
|
+
const Z = "Z".charCodeAt(0);
|
|
1710
|
+
if (p1Label.length === 1 && p2Label.length === 1) {
|
|
1711
|
+
const c1 = p1Label.charCodeAt(0);
|
|
1712
|
+
const c2 = p2Label.charCodeAt(0);
|
|
1713
|
+
if (c1 >= A && c1 <= Z && c2 === c1 + 1 && c1 + n - 1 <= Z) {
|
|
1714
|
+
let out = "";
|
|
1715
|
+
for (let i = 0; i < n; i++) out += String.fromCharCode(c1 + i);
|
|
1716
|
+
return out;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
return `${p1Label}${p2Label}\u2026`;
|
|
1720
|
+
}
|
|
1721
|
+
var def11;
|
|
1722
|
+
var init_polygon = __esm({
|
|
1723
|
+
"src/core/scene/kinds/polygon.ts"() {
|
|
1724
|
+
init_registry();
|
|
1725
|
+
init_labelOf();
|
|
1726
|
+
def11 = {
|
|
1727
|
+
type: "polygon",
|
|
1728
|
+
schemaVersion: 1,
|
|
1729
|
+
migrate: {},
|
|
1730
|
+
validate: (a) => {
|
|
1731
|
+
if (a?.construction) {
|
|
1732
|
+
if (a.construction.kind === "regular") {
|
|
1733
|
+
if (!a.construction.p1 || !a.construction.p2) {
|
|
1734
|
+
throw new Error("polygon (regular): p1 v\xE0 p2 b\u1EAFt bu\u1ED9c");
|
|
1735
|
+
}
|
|
1736
|
+
if (!Number.isFinite(a.construction.n) || a.construction.n < 3) {
|
|
1737
|
+
throw new Error("polygon (regular): n \u2265 3");
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
if (!Array.isArray(a?.vertices) || a.vertices.length < 3) {
|
|
1743
|
+
throw new Error("polygon: c\u1EA7n \xEDt nh\u1EA5t 3 \u0111\u1EC9nh");
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1746
|
+
dependsOn: (a) => {
|
|
1747
|
+
if (a.construction?.kind === "regular") return [a.construction.p1, a.construction.p2];
|
|
1748
|
+
return [...a.vertices ?? []];
|
|
1749
|
+
},
|
|
1750
|
+
describe: (obj, state) => {
|
|
1751
|
+
if (obj.attrs.construction?.kind === "regular") {
|
|
1752
|
+
const c = obj.attrs.construction;
|
|
1753
|
+
const labels = regularVertexLabels(labelOf(c.p1, state), labelOf(c.p2, state), c.n);
|
|
1754
|
+
return `${regularPolygonName(c.n)} ${labels}`;
|
|
1755
|
+
}
|
|
1756
|
+
return `\u0110a gi\xE1c ${(obj.attrs.vertices ?? []).map((id) => labelOf(id, state)).join("")}`;
|
|
1757
|
+
},
|
|
1758
|
+
render: (obj, ctx) => {
|
|
1759
|
+
const board = ctx.jxg;
|
|
1760
|
+
const label = obj.label;
|
|
1761
|
+
const showValue = obj.attrs.showValue ?? false;
|
|
1762
|
+
if (obj.attrs.construction?.kind === "regular") {
|
|
1763
|
+
const c = obj.attrs.construction;
|
|
1764
|
+
const p1 = ctx.resolveRef(c.p1);
|
|
1765
|
+
const p2 = ctx.resolveRef(c.p2);
|
|
1766
|
+
return board.create("regularpolygon", [p1, p2, c.n], {
|
|
1767
|
+
name: label,
|
|
1768
|
+
withLabel: obj.attrs.showLabel ?? false,
|
|
1769
|
+
borders: {
|
|
1770
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1771
|
+
strokeWidth: obj.attrs.width ?? 2
|
|
1772
|
+
},
|
|
1773
|
+
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
1774
|
+
fillOpacity: obj.attrs.fillOpacity ?? 0.15,
|
|
1775
|
+
visible: obj.visible,
|
|
1776
|
+
fixed: obj.locked
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
const verts = (obj.attrs.vertices ?? []).map((id) => ctx.resolveRef(id));
|
|
1780
|
+
const poly = board.create("polygon", verts, {
|
|
1781
|
+
name: showValue ? function() {
|
|
1782
|
+
const a = typeof this.Area === "function" ? this.Area() : 0;
|
|
1783
|
+
const prefix = obj.attrs.showLabel ?? true ? `${label}: ` : "";
|
|
1784
|
+
return `${prefix}S = ${Math.abs(a).toFixed(2)}`;
|
|
1785
|
+
} : label,
|
|
1786
|
+
withLabel: showValue ? true : obj.attrs.showLabel ?? false,
|
|
1787
|
+
borders: {
|
|
1788
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1789
|
+
strokeWidth: obj.attrs.width ?? 2
|
|
1790
|
+
},
|
|
1791
|
+
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
1792
|
+
fillOpacity: obj.attrs.fillOpacity ?? 0.15,
|
|
1793
|
+
visible: obj.visible,
|
|
1794
|
+
fixed: obj.locked
|
|
1795
|
+
});
|
|
1796
|
+
return poly;
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1799
|
+
registerKind(def11);
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1802
|
+
|
|
1803
|
+
// src/core/scene/kinds/intersection.ts
|
|
1804
|
+
var def12;
|
|
1805
|
+
var init_intersection = __esm({
|
|
1806
|
+
"src/core/scene/kinds/intersection.ts"() {
|
|
1807
|
+
init_registry();
|
|
1808
|
+
def12 = {
|
|
1809
|
+
type: "intersection",
|
|
1810
|
+
schemaVersion: 1,
|
|
1811
|
+
migrate: {},
|
|
1812
|
+
validate: (a) => {
|
|
1813
|
+
if (!a || !("kind" in a)) throw new Error("intersection: kind b\u1EAFt bu\u1ED9c");
|
|
1814
|
+
if (!a.ref1 || !a.ref2) throw new Error("intersection: ref1 v\xE0 ref2 b\u1EAFt bu\u1ED9c");
|
|
1815
|
+
if (a.kind === "lineLine") return;
|
|
1816
|
+
if (a.kind === "lineCircle" || a.kind === "circleCircle") {
|
|
1817
|
+
if (a.branch !== 0 && a.branch !== 1) {
|
|
1818
|
+
throw new Error(`intersection.${a.kind}: branch ph\u1EA3i l\xE0 0 ho\u1EB7c 1`);
|
|
1819
|
+
}
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1822
|
+
throw new Error(`intersection: kind kh\xF4ng h\u1EE3p l\u1EC7 "${a.kind}"`);
|
|
1823
|
+
},
|
|
1824
|
+
dependsOn: (a) => [a.ref1, a.ref2],
|
|
1825
|
+
describe: (obj) => {
|
|
1826
|
+
const a = obj.attrs;
|
|
1827
|
+
return `${obj.label} = giao ${a.ref1} \u2229 ${a.ref2}`;
|
|
1828
|
+
},
|
|
1829
|
+
render: (obj, ctx) => {
|
|
1830
|
+
const board = ctx.jxg;
|
|
1831
|
+
const a = ctx.resolveRef(obj.attrs.ref1);
|
|
1832
|
+
const b = ctx.resolveRef(obj.attrs.ref2);
|
|
1833
|
+
const opts = {
|
|
1834
|
+
name: obj.label,
|
|
1835
|
+
withLabel: true,
|
|
1836
|
+
strokeColor: obj.attrs.color ?? "#dc2626",
|
|
1837
|
+
fillColor: obj.attrs.color ?? "#dc2626",
|
|
1838
|
+
visible: obj.visible,
|
|
1839
|
+
fixed: obj.locked
|
|
1840
|
+
};
|
|
1841
|
+
if (obj.attrs.kind === "lineLine") {
|
|
1842
|
+
return board.create("intersection", [a, b, 0], opts);
|
|
1843
|
+
}
|
|
1844
|
+
const branch = obj.attrs.branch ?? 0;
|
|
1845
|
+
return board.create("intersection", [a, b, branch], opts);
|
|
1846
|
+
}
|
|
321
1847
|
};
|
|
1848
|
+
registerKind(def12);
|
|
322
1849
|
}
|
|
323
1850
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
1851
|
+
|
|
1852
|
+
// src/core/scene/kinds/angle.ts
|
|
1853
|
+
var def13;
|
|
1854
|
+
var init_angle = __esm({
|
|
1855
|
+
"src/core/scene/kinds/angle.ts"() {
|
|
1856
|
+
init_registry();
|
|
1857
|
+
init_labelOf();
|
|
1858
|
+
def13 = {
|
|
1859
|
+
type: "angle",
|
|
1860
|
+
schemaVersion: 1,
|
|
1861
|
+
migrate: {},
|
|
1862
|
+
validate: (a) => {
|
|
1863
|
+
if (!a?.p1 || !a?.vertex || !a?.p2) {
|
|
1864
|
+
throw new Error("angle: p1, vertex, p2 b\u1EAFt bu\u1ED9c");
|
|
1865
|
+
}
|
|
1866
|
+
},
|
|
1867
|
+
dependsOn: (a) => [a.p1, a.vertex, a.p2],
|
|
1868
|
+
describe: (obj, state) => `G\xF3c ${labelOf(obj.attrs.p1, state)}${labelOf(obj.attrs.vertex, state)}${labelOf(obj.attrs.p2, state)}`,
|
|
1869
|
+
render: (obj, ctx) => {
|
|
1870
|
+
const board = ctx.jxg;
|
|
1871
|
+
const pa = ctx.resolveRef(obj.attrs.p1);
|
|
1872
|
+
const pv = ctx.resolveRef(obj.attrs.vertex);
|
|
1873
|
+
const pc = ctx.resolveRef(obj.attrs.p2);
|
|
1874
|
+
let parents = [pa, pv, pc];
|
|
1875
|
+
try {
|
|
1876
|
+
const ax = pa.X() - pv.X(), ay = pa.Y() - pv.Y();
|
|
1877
|
+
const cx = pc.X() - pv.X(), cy = pc.Y() - pv.Y();
|
|
1878
|
+
if (ax * cy - ay * cx < 0) parents = [pc, pv, pa];
|
|
1879
|
+
} catch {
|
|
1880
|
+
}
|
|
1881
|
+
return board.create("angle", parents, {
|
|
1882
|
+
name: obj.label,
|
|
1883
|
+
withLabel: obj.attrs.showLabel ?? true,
|
|
1884
|
+
radius: obj.attrs.radius ?? 1,
|
|
1885
|
+
fillColor: obj.attrs.color ?? "#22c55e",
|
|
1886
|
+
fillOpacity: obj.attrs.fillOpacity ?? 0.25,
|
|
1887
|
+
strokeColor: obj.attrs.color ?? "#16a34a",
|
|
1888
|
+
strokeWidth: 1.5,
|
|
1889
|
+
visible: obj.visible,
|
|
1890
|
+
fixed: obj.locked
|
|
1891
|
+
});
|
|
359
1892
|
}
|
|
360
1893
|
};
|
|
361
|
-
|
|
362
|
-
return () => window.removeEventListener("keydown", onKey, { capture: true });
|
|
363
|
-
}, [store, bindKeyboardShortcuts]);
|
|
364
|
-
}
|
|
365
|
-
var init_useEditorState = __esm({
|
|
366
|
-
"src/core/scene/hooks/useEditorState.ts"() {
|
|
1894
|
+
registerKind(def13);
|
|
367
1895
|
}
|
|
368
1896
|
});
|
|
369
1897
|
|
|
370
|
-
// src/core/scene/
|
|
371
|
-
var
|
|
372
|
-
|
|
373
|
-
|
|
1898
|
+
// src/core/scene/kinds/distance.ts
|
|
1899
|
+
var def14;
|
|
1900
|
+
var init_distance = __esm({
|
|
1901
|
+
"src/core/scene/kinds/distance.ts"() {
|
|
1902
|
+
init_registry();
|
|
1903
|
+
init_labelOf();
|
|
1904
|
+
def14 = {
|
|
1905
|
+
type: "distance",
|
|
1906
|
+
schemaVersion: 1,
|
|
1907
|
+
migrate: {},
|
|
1908
|
+
validate: (a) => {
|
|
1909
|
+
if (!a?.p1 || !a?.p2) throw new Error("distance: p1 v\xE0 p2 b\u1EAFt bu\u1ED9c");
|
|
1910
|
+
},
|
|
1911
|
+
dependsOn: (a) => [a.p1, a.p2],
|
|
1912
|
+
describe: (obj, state) => `Kho\u1EA3ng c\xE1ch ${labelOf(obj.attrs.p1, state)}${labelOf(obj.attrs.p2, state)}`,
|
|
1913
|
+
render: (obj, ctx) => {
|
|
1914
|
+
const board = ctx.jxg;
|
|
1915
|
+
const p1 = ctx.resolveRef(obj.attrs.p1);
|
|
1916
|
+
const p2 = ctx.resolveRef(obj.attrs.p2);
|
|
1917
|
+
const prefix = obj.attrs.prefix ?? "d = ";
|
|
1918
|
+
const precision = obj.attrs.precision ?? 2;
|
|
1919
|
+
return board.create("text", [
|
|
1920
|
+
() => (p1.X() + p2.X()) / 2,
|
|
1921
|
+
() => (p1.Y() + p2.Y()) / 2,
|
|
1922
|
+
() => `${prefix}${Math.hypot(p1.X() - p2.X(), p1.Y() - p2.Y()).toFixed(precision)}`
|
|
1923
|
+
], {
|
|
1924
|
+
fontSize: obj.attrs.fontSize ?? 14,
|
|
1925
|
+
strokeColor: obj.attrs.color ?? "#dc2626",
|
|
1926
|
+
anchorX: "middle",
|
|
1927
|
+
anchorY: "middle",
|
|
1928
|
+
visible: obj.visible,
|
|
1929
|
+
fixed: true
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
};
|
|
1933
|
+
registerKind(def14);
|
|
374
1934
|
}
|
|
375
1935
|
});
|
|
376
1936
|
|
|
@@ -498,6 +2058,375 @@ var init_parser = __esm({
|
|
|
498
2058
|
}
|
|
499
2059
|
});
|
|
500
2060
|
|
|
2061
|
+
// src/core/scene/kinds/function2d.ts
|
|
2062
|
+
var def15;
|
|
2063
|
+
var init_function2d = __esm({
|
|
2064
|
+
"src/core/scene/kinds/function2d.ts"() {
|
|
2065
|
+
init_registry();
|
|
2066
|
+
init_parser();
|
|
2067
|
+
def15 = {
|
|
2068
|
+
type: "function2d",
|
|
2069
|
+
schemaVersion: 1,
|
|
2070
|
+
migrate: {},
|
|
2071
|
+
validate: (a) => {
|
|
2072
|
+
if (!a) throw new Error("function2d: attrs b\u1EAFt bu\u1ED9c");
|
|
2073
|
+
if (typeof a.expression !== "string" || !a.expression.trim()) {
|
|
2074
|
+
throw new Error("function2d: expression r\u1ED7ng");
|
|
2075
|
+
}
|
|
2076
|
+
const v = validate(a.expression);
|
|
2077
|
+
if (!v.ok) throw new Error(`function2d: expression invalid \u2014 ${v.error}`);
|
|
2078
|
+
if (typeof a.color !== "string") throw new Error("function2d: color b\u1EAFt bu\u1ED9c");
|
|
2079
|
+
if (typeof a.visible !== "boolean") throw new Error("function2d: visible b\u1EAFt bu\u1ED9c");
|
|
2080
|
+
if (a.domain) {
|
|
2081
|
+
if (a.domain.min >= a.domain.max) {
|
|
2082
|
+
throw new Error("function2d: domain min ph\u1EA3i < max");
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
},
|
|
2086
|
+
dependsOn: () => [],
|
|
2087
|
+
describe: (obj) => `${obj.label}(x) = ${obj.attrs.expression}`,
|
|
2088
|
+
render: (obj, ctx) => {
|
|
2089
|
+
const board = ctx.jxg;
|
|
2090
|
+
if (!obj.visible || !obj.attrs.visible) return null;
|
|
2091
|
+
const fn = compile(obj.attrs.expression, ctx.paramMap ?? {});
|
|
2092
|
+
if (typeof fn !== "function") return null;
|
|
2093
|
+
const view = ctx.defaults.view;
|
|
2094
|
+
const xMin = obj.attrs.domain?.min ?? view?.xMin ?? -10;
|
|
2095
|
+
const xMax = obj.attrs.domain?.max ?? view?.xMax ?? 10;
|
|
2096
|
+
return board.create("functiongraph", [fn, xMin, xMax], {
|
|
2097
|
+
strokeColor: obj.attrs.color,
|
|
2098
|
+
strokeWidth: 2,
|
|
2099
|
+
name: obj.label,
|
|
2100
|
+
withLabel: false,
|
|
2101
|
+
highlight: false,
|
|
2102
|
+
fixed: true
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
registerKind(def15);
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
// src/core/scene/kinds/parameter.ts
|
|
2111
|
+
var def16;
|
|
2112
|
+
var init_parameter = __esm({
|
|
2113
|
+
"src/core/scene/kinds/parameter.ts"() {
|
|
2114
|
+
init_registry();
|
|
2115
|
+
def16 = {
|
|
2116
|
+
type: "parameter",
|
|
2117
|
+
schemaVersion: 1,
|
|
2118
|
+
migrate: {},
|
|
2119
|
+
validate: (a) => {
|
|
2120
|
+
if (!a) throw new Error("parameter: attrs b\u1EAFt bu\u1ED9c");
|
|
2121
|
+
if (typeof a.value !== "number" || typeof a.min !== "number" || typeof a.max !== "number") {
|
|
2122
|
+
throw new Error("parameter: value/min/max ph\u1EA3i l\xE0 number");
|
|
2123
|
+
}
|
|
2124
|
+
if (a.min >= a.max) throw new Error("parameter: min ph\u1EA3i < max");
|
|
2125
|
+
if (a.value < a.min || a.value > a.max) throw new Error("parameter: value ngo\xE0i [min, max]");
|
|
2126
|
+
if (typeof a.step !== "number" || a.step <= 0) throw new Error("parameter: step ph\u1EA3i > 0");
|
|
2127
|
+
},
|
|
2128
|
+
dependsOn: () => [],
|
|
2129
|
+
describe: (obj) => `${obj.label} = ${obj.attrs.value}`,
|
|
2130
|
+
render: () => null
|
|
2131
|
+
// Không render lên board
|
|
2132
|
+
};
|
|
2133
|
+
registerKind(def16);
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
|
|
2137
|
+
// src/core/scene/kinds/pointOnCurve.ts
|
|
2138
|
+
var def17;
|
|
2139
|
+
var init_pointOnCurve = __esm({
|
|
2140
|
+
"src/core/scene/kinds/pointOnCurve.ts"() {
|
|
2141
|
+
init_registry();
|
|
2142
|
+
def17 = {
|
|
2143
|
+
type: "pointOnCurve",
|
|
2144
|
+
schemaVersion: 1,
|
|
2145
|
+
migrate: {},
|
|
2146
|
+
validate: (a) => {
|
|
2147
|
+
if (!a || typeof a.functionId !== "string" || !a.functionId) {
|
|
2148
|
+
throw new Error("pointOnCurve: functionId b\u1EAFt bu\u1ED9c");
|
|
2149
|
+
}
|
|
2150
|
+
if (typeof a.x !== "number" || !Number.isFinite(a.x)) {
|
|
2151
|
+
throw new Error("pointOnCurve: x ph\u1EA3i l\xE0 finite number");
|
|
2152
|
+
}
|
|
2153
|
+
},
|
|
2154
|
+
dependsOn: (a) => [a.functionId],
|
|
2155
|
+
describe: (obj) => `${obj.label} tr\xEAn ${obj.attrs.functionId} t\u1EA1i x=${obj.attrs.x.toFixed(3)}`,
|
|
2156
|
+
render: (obj, ctx) => {
|
|
2157
|
+
const board = ctx.jxg;
|
|
2158
|
+
const curve = ctx.resolveRef(obj.attrs.functionId);
|
|
2159
|
+
if (!curve) return null;
|
|
2160
|
+
return board.create("glider", [obj.attrs.x, 0, curve], {
|
|
2161
|
+
name: obj.label,
|
|
2162
|
+
size: 3,
|
|
2163
|
+
withLabel: obj.label !== "",
|
|
2164
|
+
fillColor: "#000",
|
|
2165
|
+
strokeColor: "#000"
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
};
|
|
2169
|
+
registerKind(def17);
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2173
|
+
// src/core/scene/kinds/tangent2d.ts
|
|
2174
|
+
var def18;
|
|
2175
|
+
var init_tangent2d = __esm({
|
|
2176
|
+
"src/core/scene/kinds/tangent2d.ts"() {
|
|
2177
|
+
init_registry();
|
|
2178
|
+
def18 = {
|
|
2179
|
+
type: "tangent2d",
|
|
2180
|
+
schemaVersion: 1,
|
|
2181
|
+
migrate: {},
|
|
2182
|
+
validate: (a) => {
|
|
2183
|
+
if (!a || typeof a.pointId !== "string" || !a.pointId) {
|
|
2184
|
+
throw new Error("tangent2d: pointId b\u1EAFt bu\u1ED9c");
|
|
2185
|
+
}
|
|
2186
|
+
},
|
|
2187
|
+
dependsOn: (a) => [a.pointId],
|
|
2188
|
+
describe: (obj) => `Ti\u1EBFp tuy\u1EBFn t\u1EA1i ${obj.attrs.pointId}`,
|
|
2189
|
+
render: (obj, ctx) => {
|
|
2190
|
+
const board = ctx.jxg;
|
|
2191
|
+
const pt = ctx.resolveRef(obj.attrs.pointId);
|
|
2192
|
+
if (!pt) return null;
|
|
2193
|
+
return board.create("tangent", [pt], {
|
|
2194
|
+
strokeColor: "#65a30d",
|
|
2195
|
+
strokeWidth: 1.5,
|
|
2196
|
+
dash: 2,
|
|
2197
|
+
withLabel: false
|
|
2198
|
+
});
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
2201
|
+
registerKind(def18);
|
|
2202
|
+
}
|
|
2203
|
+
});
|
|
2204
|
+
|
|
2205
|
+
// src/core/scene/expressions/evaluator.ts
|
|
2206
|
+
function scanRoots(fn, xMin, xMax, samples = DEFAULT_SAMPLES) {
|
|
2207
|
+
if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || xMin >= xMax) return [];
|
|
2208
|
+
const out = [];
|
|
2209
|
+
const step = (xMax - xMin) / samples;
|
|
2210
|
+
let prev = fn(xMin);
|
|
2211
|
+
for (let i = 1; i <= samples; i++) {
|
|
2212
|
+
const x = xMin + i * step;
|
|
2213
|
+
const curr = fn(x);
|
|
2214
|
+
if (!Number.isFinite(prev) || !Number.isFinite(curr)) {
|
|
2215
|
+
prev = curr;
|
|
2216
|
+
continue;
|
|
2217
|
+
}
|
|
2218
|
+
if (prev * curr < 0) {
|
|
2219
|
+
const root = bisect(fn, x - step, x);
|
|
2220
|
+
if (Number.isFinite(root)) out.push(root);
|
|
2221
|
+
} else if (prev !== 0 && curr === 0) {
|
|
2222
|
+
out.push(x);
|
|
2223
|
+
}
|
|
2224
|
+
prev = curr;
|
|
2225
|
+
}
|
|
2226
|
+
return out;
|
|
2227
|
+
}
|
|
2228
|
+
function bisect(fn, lo, hi) {
|
|
2229
|
+
for (let i = 0; i < 50; i++) {
|
|
2230
|
+
const mid = (lo + hi) / 2;
|
|
2231
|
+
const fmid = fn(mid);
|
|
2232
|
+
if (!Number.isFinite(fmid)) break;
|
|
2233
|
+
if (Math.abs(fmid) < 1e-10) return mid;
|
|
2234
|
+
const flo = fn(lo);
|
|
2235
|
+
if (!Number.isFinite(flo)) break;
|
|
2236
|
+
if (flo * fmid <= 0) hi = mid;
|
|
2237
|
+
else lo = mid;
|
|
2238
|
+
}
|
|
2239
|
+
return (lo + hi) / 2;
|
|
2240
|
+
}
|
|
2241
|
+
function scanExtrema(fn, xMin, xMax, samples = DEFAULT_SAMPLES) {
|
|
2242
|
+
if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || xMin >= xMax) return [];
|
|
2243
|
+
const out = [];
|
|
2244
|
+
const step = (xMax - xMin) / samples;
|
|
2245
|
+
const xs = [];
|
|
2246
|
+
const ys = [];
|
|
2247
|
+
for (let i = 0; i <= samples + 1; i++) {
|
|
2248
|
+
const x = xMin + (i - 1) * step;
|
|
2249
|
+
xs.push(x);
|
|
2250
|
+
ys.push(fn(x));
|
|
2251
|
+
}
|
|
2252
|
+
let prevSign = 0;
|
|
2253
|
+
let prevSignIdx = 1;
|
|
2254
|
+
for (let i = 1; i <= samples; i++) {
|
|
2255
|
+
const d = ys[i + 1] - ys[i - 1];
|
|
2256
|
+
if (!Number.isFinite(d)) continue;
|
|
2257
|
+
const sign = d > 0 ? 1 : d < 0 ? -1 : 0;
|
|
2258
|
+
if (sign === 0) continue;
|
|
2259
|
+
if (prevSign !== 0 && sign !== prevSign) {
|
|
2260
|
+
const type = prevSign > 0 ? "max" : "min";
|
|
2261
|
+
const midI = Math.round((prevSignIdx + i) / 2);
|
|
2262
|
+
out.push({ x: xs[midI], y: ys[midI], type });
|
|
2263
|
+
}
|
|
2264
|
+
prevSign = sign;
|
|
2265
|
+
prevSignIdx = i;
|
|
2266
|
+
}
|
|
2267
|
+
return out;
|
|
2268
|
+
}
|
|
2269
|
+
var DEFAULT_SAMPLES;
|
|
2270
|
+
var init_evaluator = __esm({
|
|
2271
|
+
"src/core/scene/expressions/evaluator.ts"() {
|
|
2272
|
+
DEFAULT_SAMPLES = 1e3;
|
|
2273
|
+
}
|
|
2274
|
+
});
|
|
2275
|
+
|
|
2276
|
+
// src/core/scene/kinds/extremum2d.ts
|
|
2277
|
+
var def19;
|
|
2278
|
+
var init_extremum2d = __esm({
|
|
2279
|
+
"src/core/scene/kinds/extremum2d.ts"() {
|
|
2280
|
+
init_registry();
|
|
2281
|
+
init_evaluator();
|
|
2282
|
+
init_parser();
|
|
2283
|
+
def19 = {
|
|
2284
|
+
type: "extremum2d",
|
|
2285
|
+
schemaVersion: 1,
|
|
2286
|
+
migrate: {},
|
|
2287
|
+
validate: (a) => {
|
|
2288
|
+
if (!a || typeof a.functionId !== "string" || !a.functionId) {
|
|
2289
|
+
throw new Error("extremum2d: functionId b\u1EAFt bu\u1ED9c");
|
|
2290
|
+
}
|
|
2291
|
+
if (!a.interval || a.interval.min >= a.interval.max) {
|
|
2292
|
+
throw new Error("extremum2d: interval min ph\u1EA3i < max");
|
|
2293
|
+
}
|
|
2294
|
+
if (a.mode !== "max" && a.mode !== "min") {
|
|
2295
|
+
throw new Error('extremum2d: mode ph\u1EA3i l\xE0 "max" ho\u1EB7c "min"');
|
|
2296
|
+
}
|
|
2297
|
+
},
|
|
2298
|
+
dependsOn: (a) => [a.functionId],
|
|
2299
|
+
describe: (obj) => `${obj.attrs.mode === "max" ? "C\u1EF1c \u0111\u1EA1i" : "C\u1EF1c ti\u1EC3u"} c\u1EE7a ${obj.attrs.functionId} trong [${obj.attrs.interval.min}, ${obj.attrs.interval.max}]`,
|
|
2300
|
+
render: (obj, ctx) => {
|
|
2301
|
+
const board = ctx.jxg;
|
|
2302
|
+
const expr = ctx.defaults._functionExpr?.[obj.attrs.functionId];
|
|
2303
|
+
if (!expr) return null;
|
|
2304
|
+
const fn = compile(expr, ctx.paramMap ?? {});
|
|
2305
|
+
if (typeof fn !== "function") return null;
|
|
2306
|
+
const extrema = scanExtrema(fn, obj.attrs.interval.min, obj.attrs.interval.max).filter((e) => e.type === obj.attrs.mode);
|
|
2307
|
+
return extrema.map((e) => board.create("point", [e.x, e.y], {
|
|
2308
|
+
name: obj.label,
|
|
2309
|
+
size: 3,
|
|
2310
|
+
fillColor: "#dc2626",
|
|
2311
|
+
strokeColor: "#dc2626",
|
|
2312
|
+
withLabel: obj.label !== ""
|
|
2313
|
+
}));
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
registerKind(def19);
|
|
2317
|
+
}
|
|
2318
|
+
});
|
|
2319
|
+
|
|
2320
|
+
// src/core/scene/kinds/root2d.ts
|
|
2321
|
+
var def20;
|
|
2322
|
+
var init_root2d = __esm({
|
|
2323
|
+
"src/core/scene/kinds/root2d.ts"() {
|
|
2324
|
+
init_registry();
|
|
2325
|
+
init_evaluator();
|
|
2326
|
+
init_parser();
|
|
2327
|
+
def20 = {
|
|
2328
|
+
type: "root2d",
|
|
2329
|
+
schemaVersion: 1,
|
|
2330
|
+
migrate: {},
|
|
2331
|
+
validate: (a) => {
|
|
2332
|
+
if (!a || typeof a.functionId !== "string" || !a.functionId) {
|
|
2333
|
+
throw new Error("root2d: functionId b\u1EAFt bu\u1ED9c");
|
|
2334
|
+
}
|
|
2335
|
+
if (!a.interval || a.interval.min >= a.interval.max) {
|
|
2336
|
+
throw new Error("root2d: interval min ph\u1EA3i < max");
|
|
2337
|
+
}
|
|
2338
|
+
},
|
|
2339
|
+
dependsOn: (a) => [a.functionId],
|
|
2340
|
+
describe: (obj) => `Nghi\u1EC7m c\u1EE7a ${obj.attrs.functionId} trong [${obj.attrs.interval.min}, ${obj.attrs.interval.max}]`,
|
|
2341
|
+
render: (obj, ctx) => {
|
|
2342
|
+
const board = ctx.jxg;
|
|
2343
|
+
const expr = ctx.defaults._functionExpr?.[obj.attrs.functionId];
|
|
2344
|
+
if (!expr) return null;
|
|
2345
|
+
const fn = compile(expr, ctx.paramMap ?? {});
|
|
2346
|
+
if (typeof fn !== "function") return null;
|
|
2347
|
+
const roots = scanRoots(fn, obj.attrs.interval.min, obj.attrs.interval.max);
|
|
2348
|
+
return roots.map((x) => board.create("point", [x, 0], {
|
|
2349
|
+
name: obj.label,
|
|
2350
|
+
size: 3,
|
|
2351
|
+
fillColor: "#dc2626",
|
|
2352
|
+
strokeColor: "#dc2626",
|
|
2353
|
+
withLabel: obj.label !== ""
|
|
2354
|
+
}));
|
|
2355
|
+
}
|
|
2356
|
+
};
|
|
2357
|
+
registerKind(def20);
|
|
2358
|
+
}
|
|
2359
|
+
});
|
|
2360
|
+
|
|
2361
|
+
// src/core/scene/kinds/slope2d.ts
|
|
2362
|
+
var def21;
|
|
2363
|
+
var init_slope2d = __esm({
|
|
2364
|
+
"src/core/scene/kinds/slope2d.ts"() {
|
|
2365
|
+
init_registry();
|
|
2366
|
+
def21 = {
|
|
2367
|
+
type: "slope2d",
|
|
2368
|
+
schemaVersion: 1,
|
|
2369
|
+
migrate: {},
|
|
2370
|
+
validate: (a) => {
|
|
2371
|
+
if (!a || typeof a.pointId !== "string" || !a.pointId) {
|
|
2372
|
+
throw new Error("slope2d: pointId b\u1EAFt bu\u1ED9c");
|
|
2373
|
+
}
|
|
2374
|
+
},
|
|
2375
|
+
dependsOn: (a) => [a.pointId],
|
|
2376
|
+
describe: (obj) => `Slope t\u1EA1i ${obj.attrs.pointId}`,
|
|
2377
|
+
render: (obj, ctx) => {
|
|
2378
|
+
const board = ctx.jxg;
|
|
2379
|
+
const pt = ctx.resolveRef(obj.attrs.pointId);
|
|
2380
|
+
if (!pt) return null;
|
|
2381
|
+
return board.create("slopetriangle", [pt], {
|
|
2382
|
+
name: obj.label,
|
|
2383
|
+
withLabel: true,
|
|
2384
|
+
fillColor: "#9333ea",
|
|
2385
|
+
strokeColor: "#9333ea",
|
|
2386
|
+
fillOpacity: 0.2
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
};
|
|
2390
|
+
registerKind(def21);
|
|
2391
|
+
}
|
|
2392
|
+
});
|
|
2393
|
+
|
|
2394
|
+
// src/core/scene/kinds/index.ts
|
|
2395
|
+
var init_kinds = __esm({
|
|
2396
|
+
"src/core/scene/kinds/index.ts"() {
|
|
2397
|
+
init_point3d();
|
|
2398
|
+
init_segment3d();
|
|
2399
|
+
init_line3d();
|
|
2400
|
+
init_ray3d();
|
|
2401
|
+
init_vector3d();
|
|
2402
|
+
init_plane3d();
|
|
2403
|
+
init_polygon3d();
|
|
2404
|
+
init_sphere3d();
|
|
2405
|
+
init_polyhedron3d();
|
|
2406
|
+
init_cylinder3d();
|
|
2407
|
+
init_cone3d();
|
|
2408
|
+
init_point();
|
|
2409
|
+
init_segment();
|
|
2410
|
+
init_line();
|
|
2411
|
+
init_ray();
|
|
2412
|
+
init_vector();
|
|
2413
|
+
init_circle();
|
|
2414
|
+
init_arc();
|
|
2415
|
+
init_sector();
|
|
2416
|
+
init_polygon();
|
|
2417
|
+
init_intersection();
|
|
2418
|
+
init_angle();
|
|
2419
|
+
init_distance();
|
|
2420
|
+
init_function2d();
|
|
2421
|
+
init_parameter();
|
|
2422
|
+
init_pointOnCurve();
|
|
2423
|
+
init_tangent2d();
|
|
2424
|
+
init_extremum2d();
|
|
2425
|
+
init_root2d();
|
|
2426
|
+
init_slope2d();
|
|
2427
|
+
}
|
|
2428
|
+
});
|
|
2429
|
+
|
|
501
2430
|
// src/core/scene/index.ts
|
|
502
2431
|
var init_scene = __esm({
|
|
503
2432
|
"src/core/scene/index.ts"() {
|
|
@@ -505,6 +2434,7 @@ var init_scene = __esm({
|
|
|
505
2434
|
init_store();
|
|
506
2435
|
init_selectors();
|
|
507
2436
|
init_hooks();
|
|
2437
|
+
init_kinds();
|
|
508
2438
|
}
|
|
509
2439
|
});
|
|
510
2440
|
|
|
@@ -662,8 +2592,8 @@ var init_JxgRenderer = __esm({
|
|
|
662
2592
|
}
|
|
663
2593
|
create(obj) {
|
|
664
2594
|
try {
|
|
665
|
-
const
|
|
666
|
-
const el =
|
|
2595
|
+
const def22 = getKind(obj.kind);
|
|
2596
|
+
const el = def22.render(obj, this.ctx());
|
|
667
2597
|
this.elements.set(obj.id, el);
|
|
668
2598
|
this.attachFreePointDragSync(obj, el);
|
|
669
2599
|
} catch (err) {
|
|
@@ -741,11 +2671,11 @@ var init_JxgRenderer = __esm({
|
|
|
741
2671
|
continue;
|
|
742
2672
|
}
|
|
743
2673
|
if (Object.is(old, cur)) continue;
|
|
744
|
-
const
|
|
2674
|
+
const def22 = getKind(cur.kind);
|
|
745
2675
|
const existing = this.elements.get(id);
|
|
746
|
-
if (
|
|
2676
|
+
if (def22.update && existing) {
|
|
747
2677
|
try {
|
|
748
|
-
|
|
2678
|
+
def22.update(cur, old, this.ctx(), existing);
|
|
749
2679
|
continue;
|
|
750
2680
|
} catch (err) {
|
|
751
2681
|
console.warn(`[scene/render/2d] update fail, recreate:`, err);
|
|
@@ -2152,47 +4082,20 @@ var init_StampLeftPanel = __esm({
|
|
|
2152
4082
|
}
|
|
2153
4083
|
});
|
|
2154
4084
|
function UndoIcon3() {
|
|
2155
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "
|
|
2156
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2157
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3
|
|
4085
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4086
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "3 7 3 13 9 13" }),
|
|
4087
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.51 13a9 9 0 1 0 2.13-9.36L3 7" })
|
|
2158
4088
|
] });
|
|
2159
4089
|
}
|
|
2160
4090
|
function RedoIcon3() {
|
|
2161
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "
|
|
2162
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2163
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "
|
|
4091
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4092
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "21 7 21 13 15 13" }),
|
|
4093
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20.49 13a9 9 0 1 1-2.12-9.36L21 7" })
|
|
2164
4094
|
] });
|
|
2165
4095
|
}
|
|
2166
|
-
var GeometryIconHeader;
|
|
4096
|
+
var C_POINT, C_CONSTRUCT, C_FILL, C_ARC, Icon, GeometryIconHeader;
|
|
2167
4097
|
var init_icons = __esm({
|
|
2168
4098
|
"src/stamps/geometry-2d/editor/icons.tsx"() {
|
|
2169
|
-
GeometryIconHeader = /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2170
|
-
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "4,20 20,20 12,5" }),
|
|
2171
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4", cy: "20", r: "1.5", fill: "currentColor", stroke: "none" }),
|
|
2172
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "20", cy: "20", r: "1.5", fill: "currentColor", stroke: "none" }),
|
|
2173
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "1.5", fill: "currentColor", stroke: "none" })
|
|
2174
|
-
] });
|
|
2175
|
-
}
|
|
2176
|
-
});
|
|
2177
|
-
function letterForGroup(g) {
|
|
2178
|
-
const idx = GROUP_ORDER.indexOf(g);
|
|
2179
|
-
return idx >= 0 ? String.fromCharCode(A_CODE + idx) : "";
|
|
2180
|
-
}
|
|
2181
|
-
function objKind(obj) {
|
|
2182
|
-
if (!obj) return "other";
|
|
2183
|
-
const ec = typeof obj.elementClass === "number" ? obj.elementClass : null;
|
|
2184
|
-
if (ec === 1) return "point";
|
|
2185
|
-
if (ec === 2) return "line";
|
|
2186
|
-
if (ec === 3) return "circle";
|
|
2187
|
-
const e = (obj.elType || obj.type || "").toString().toLowerCase();
|
|
2188
|
-
if (e === "point" || e === "glider" || e === "midpoint" || e === "intersection" || e === "otherintersection" || e === "reflection" || e === "mirrorpoint" || e === "mirrorelement" || e === "orthogonalprojection" || e === "parallelpoint") return "point";
|
|
2189
|
-
if (e === "line" || e === "segment" || e === "arrow" || e === "axis" || e === "normal" || e === "parallel" || e === "perpendicular" || e === "tangent" || e === "bisector" || e === "perpendicularsegment") return "line";
|
|
2190
|
-
if (e === "circle" || e === "circumcircle") return "circle";
|
|
2191
|
-
return "other";
|
|
2192
|
-
}
|
|
2193
|
-
var C_POINT, C_CONSTRUCT, C_FILL, C_ARC, Icon, TOOLS, GROUP_LABELS, GROUP_ORDER, A_CODE;
|
|
2194
|
-
var init_tools = __esm({
|
|
2195
|
-
"src/stamps/geometry-2d/editor/tools.tsx"() {
|
|
2196
4099
|
C_POINT = "#2563eb";
|
|
2197
4100
|
C_CONSTRUCT = "#dc2626";
|
|
2198
4101
|
C_FILL = "#f59e0b";
|
|
@@ -2460,6 +4363,36 @@ var init_tools = __esm({
|
|
|
2460
4363
|
/* @__PURE__ */ jsxRuntime.jsx("text", { x: "10.5", y: "10.5", fontSize: "8", fontFamily: "serif", fontStyle: "italic", fontWeight: "700", fill: "currentColor", children: "k" })
|
|
2461
4364
|
] })
|
|
2462
4365
|
};
|
|
4366
|
+
GeometryIconHeader = /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4367
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "4,20 20,20 12,5" }),
|
|
4368
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4", cy: "20", r: "1.5", fill: "currentColor", stroke: "none" }),
|
|
4369
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "20", cy: "20", r: "1.5", fill: "currentColor", stroke: "none" }),
|
|
4370
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "1.5", fill: "currentColor", stroke: "none" })
|
|
4371
|
+
] });
|
|
4372
|
+
}
|
|
4373
|
+
});
|
|
4374
|
+
|
|
4375
|
+
// src/stamps/geometry-2d/editor/tools.tsx
|
|
4376
|
+
function letterForGroup(g) {
|
|
4377
|
+
const idx = GROUP_ORDER.indexOf(g);
|
|
4378
|
+
return idx >= 0 ? String.fromCharCode(A_CODE + idx) : "";
|
|
4379
|
+
}
|
|
4380
|
+
function objKind(obj) {
|
|
4381
|
+
if (!obj) return "other";
|
|
4382
|
+
const ec = typeof obj.elementClass === "number" ? obj.elementClass : null;
|
|
4383
|
+
if (ec === 1) return "point";
|
|
4384
|
+
if (ec === 2) return "line";
|
|
4385
|
+
if (ec === 3) return "circle";
|
|
4386
|
+
const e = (obj.elType || obj.type || "").toString().toLowerCase();
|
|
4387
|
+
if (e === "point" || e === "glider" || e === "midpoint" || e === "intersection" || e === "otherintersection" || e === "reflection" || e === "mirrorpoint" || e === "mirrorelement" || e === "orthogonalprojection" || e === "parallelpoint") return "point";
|
|
4388
|
+
if (e === "line" || e === "segment" || e === "arrow" || e === "axis" || e === "normal" || e === "parallel" || e === "perpendicular" || e === "tangent" || e === "bisector" || e === "perpendicularsegment") return "line";
|
|
4389
|
+
if (e === "circle" || e === "circumcircle") return "circle";
|
|
4390
|
+
return "other";
|
|
4391
|
+
}
|
|
4392
|
+
var TOOLS, GROUP_LABELS, GROUP_ORDER, A_CODE;
|
|
4393
|
+
var init_tools = __esm({
|
|
4394
|
+
"src/stamps/geometry-2d/editor/tools.tsx"() {
|
|
4395
|
+
init_icons();
|
|
2463
4396
|
TOOLS = [
|
|
2464
4397
|
{ key: "move", label: "Di chuy\u1EC3n", hint: "K\xE9o \u0111i\u1EC3m ho\u1EB7c xoay n\u1EC1n", icon: Icon.cursor, group: "move", needs: 0 },
|
|
2465
4398
|
{ key: "select", label: "Ch\u1ECDn", hint: "Click \u0111\u1EC3 ch\u1ECDn 1 / Shift+click \u0111\u1EC3 b\u1ECF th\xEAm / K\xE9o n\u1EC1n \u0111\u1EC3 khoanh v\xF9ng / DEL \u0111\u1EC3 xo\xE1", icon: Icon.select, group: "move", needs: 0 },
|
|
@@ -2687,7 +4620,7 @@ function handlePointTool(ctx, _e, x, y, hits) {
|
|
|
2687
4620
|
}
|
|
2688
4621
|
dispatchAddFreePoint(ctx, x, y);
|
|
2689
4622
|
}
|
|
2690
|
-
var
|
|
4623
|
+
var init_point2 = __esm({
|
|
2691
4624
|
"src/stamps/geometry-2d/editor/handlers/pointerDown/point.ts"() {
|
|
2692
4625
|
init_tools();
|
|
2693
4626
|
init_safeJsx();
|
|
@@ -2783,7 +4716,7 @@ function handlePolygonTool(ctx, t, toolDef, e, x, y, bestHit) {
|
|
|
2783
4716
|
ctx.setPendingCount(ctx.pendingIdsRef.current.length);
|
|
2784
4717
|
return true;
|
|
2785
4718
|
}
|
|
2786
|
-
var
|
|
4719
|
+
var init_polygon2 = __esm({
|
|
2787
4720
|
"src/stamps/geometry-2d/editor/handlers/pointerDown/polygon.ts"() {
|
|
2788
4721
|
init_tools();
|
|
2789
4722
|
init_safeJsx();
|
|
@@ -3477,9 +5410,9 @@ var init_pointerDown = __esm({
|
|
|
3477
5410
|
init_tools();
|
|
3478
5411
|
init_move();
|
|
3479
5412
|
init_select();
|
|
3480
|
-
|
|
5413
|
+
init_point2();
|
|
3481
5414
|
init_singleTarget();
|
|
3482
|
-
|
|
5415
|
+
init_polygon2();
|
|
3483
5416
|
init_multiClick();
|
|
3484
5417
|
}
|
|
3485
5418
|
});
|
|
@@ -4557,7 +6490,6 @@ var init_MiniBoard = __esm({
|
|
|
4557
6490
|
deleteSelection,
|
|
4558
6491
|
emitTransform
|
|
4559
6492
|
}),
|
|
4560
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4561
6493
|
[store, clearSelection, deleteSelection, clearPending, emitTransform]
|
|
4562
6494
|
);
|
|
4563
6495
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -6685,8 +8617,8 @@ var init_JxgRenderer3D = __esm({
|
|
|
6685
8617
|
}
|
|
6686
8618
|
create(obj) {
|
|
6687
8619
|
try {
|
|
6688
|
-
const
|
|
6689
|
-
const el =
|
|
8620
|
+
const def22 = getKind(obj.kind);
|
|
8621
|
+
const el = def22.render(obj, this.ctx());
|
|
6690
8622
|
this.elements.set(obj.id, el);
|
|
6691
8623
|
} catch (err) {
|
|
6692
8624
|
console.warn(`[scene/render] kh\xF4ng render \u0111\u01B0\u1EE3c ${obj.kind} id="${obj.id}":`, err);
|
|
@@ -6742,16 +8674,16 @@ var init_JxgRenderer3D = __esm({
|
|
|
6742
8674
|
if (Object.is(old, cur)) {
|
|
6743
8675
|
continue;
|
|
6744
8676
|
}
|
|
6745
|
-
let
|
|
8677
|
+
let def22;
|
|
6746
8678
|
try {
|
|
6747
|
-
|
|
8679
|
+
def22 = getKind(cur.kind);
|
|
6748
8680
|
} catch {
|
|
6749
8681
|
continue;
|
|
6750
8682
|
}
|
|
6751
8683
|
const existing = this.elements.get(id);
|
|
6752
|
-
if (
|
|
8684
|
+
if (def22.update && existing !== void 0) {
|
|
6753
8685
|
try {
|
|
6754
|
-
|
|
8686
|
+
def22.update(cur, old, this.ctx(), existing);
|
|
6755
8687
|
continue;
|
|
6756
8688
|
} catch (err) {
|
|
6757
8689
|
console.warn(`[scene/render] update fail, recreate id="${id}":`, err);
|
|
@@ -7093,7 +9025,7 @@ function buildPoint(args, store) {
|
|
|
7093
9025
|
return addPoint(store, c);
|
|
7094
9026
|
}
|
|
7095
9027
|
var buildPointOnObject;
|
|
7096
|
-
var
|
|
9028
|
+
var init_point3 = __esm({
|
|
7097
9029
|
"src/stamps/geometry-3d/editor/tools/handlers/point.ts"() {
|
|
7098
9030
|
init_ensurePoint();
|
|
7099
9031
|
buildPointOnObject = buildPoint;
|
|
@@ -7148,7 +9080,7 @@ function buildVector(args, store) {
|
|
|
7148
9080
|
if (!from || !to || from === to) return null;
|
|
7149
9081
|
return addDerived(store, "vector3d", "v", { from, to });
|
|
7150
9082
|
}
|
|
7151
|
-
var
|
|
9083
|
+
var init_segment2 = __esm({
|
|
7152
9084
|
"src/stamps/geometry-3d/editor/tools/handlers/segment.ts"() {
|
|
7153
9085
|
init_scene();
|
|
7154
9086
|
init_ensurePoint();
|
|
@@ -7175,7 +9107,7 @@ function buildPolygon(args, store) {
|
|
|
7175
9107
|
store.dispatch({ type: "ADD", payload: { obj } });
|
|
7176
9108
|
return id;
|
|
7177
9109
|
}
|
|
7178
|
-
var
|
|
9110
|
+
var init_polygon3 = __esm({
|
|
7179
9111
|
"src/stamps/geometry-3d/editor/tools/handlers/polygon.ts"() {
|
|
7180
9112
|
init_scene();
|
|
7181
9113
|
init_ensurePoint();
|
|
@@ -7691,9 +9623,9 @@ var init_cone = __esm({
|
|
|
7691
9623
|
var stubBuild, ALL_SURFACES, OBJECT_ONLY, NO_SURFACE, TOOLS2;
|
|
7692
9624
|
var init_spec = __esm({
|
|
7693
9625
|
"src/stamps/geometry-3d/editor/tools/spec.ts"() {
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
9626
|
+
init_point3();
|
|
9627
|
+
init_segment2();
|
|
9628
|
+
init_polygon3();
|
|
7697
9629
|
init_plane();
|
|
7698
9630
|
init_pyramid();
|
|
7699
9631
|
init_prism();
|
|
@@ -12119,7 +14051,6 @@ function useStampDoubleClick({ enabled, stamps, onOpen }) {
|
|
|
12119
14051
|
elementId: null
|
|
12120
14052
|
});
|
|
12121
14053
|
return React18.useCallback(
|
|
12122
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12123
14054
|
(_activeTool, pointerDownState) => {
|
|
12124
14055
|
if (!enabled) return;
|
|
12125
14056
|
const hitElement = pointerDownState?.hit?.element;
|
|
@@ -12972,11 +14903,8 @@ function useScenePersist(opts) {
|
|
|
12972
14903
|
api.addFiles(
|
|
12973
14904
|
entries.map(([id, f]) => ({
|
|
12974
14905
|
id,
|
|
12975
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12976
14906
|
dataURL: f.dataURL,
|
|
12977
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12978
14907
|
mimeType: f.mimeType,
|
|
12979
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12980
14908
|
created: f.created ?? Date.now()
|
|
12981
14909
|
}))
|
|
12982
14910
|
);
|
|
@@ -12998,11 +14926,8 @@ function useScenePersist(opts) {
|
|
|
12998
14926
|
api.addFiles(
|
|
12999
14927
|
entries.map(([id, f]) => ({
|
|
13000
14928
|
id,
|
|
13001
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13002
14929
|
dataURL: f.dataURL,
|
|
13003
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13004
14930
|
mimeType: f.mimeType,
|
|
13005
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13006
14931
|
created: f.created ?? Date.now()
|
|
13007
14932
|
}))
|
|
13008
14933
|
);
|
|
@@ -13115,7 +15040,6 @@ function Whiteboard({
|
|
|
13115
15040
|
const handledCropIdRef = React18.useRef(null);
|
|
13116
15041
|
const prevExcalidrawToolRef = React18.useRef("selection");
|
|
13117
15042
|
const handleChange = React18.useCallback(
|
|
13118
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13119
15043
|
(elements, appState, files) => {
|
|
13120
15044
|
syncThemeFromAppState(appState);
|
|
13121
15045
|
if (readOnly) return;
|