@xom11/whiteboard 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/ai.d.mts +226 -32
  2. package/dist/ai.d.ts +226 -32
  3. package/dist/ai.js +5126 -351
  4. package/dist/ai.js.map +1 -1
  5. package/dist/ai.mjs +4970 -352
  6. package/dist/ai.mjs.map +1 -1
  7. package/dist/catalog.json +5 -5
  8. package/dist/{chunk-V3YJ6JFL.mjs → chunk-44JY2AKC.mjs} +3 -3
  9. package/dist/{chunk-V3YJ6JFL.mjs.map → chunk-44JY2AKC.mjs.map} +1 -1
  10. package/dist/{chunk-XVVLT6B3.mjs → chunk-BMYC2ILT.mjs} +4 -4
  11. package/dist/{chunk-XVVLT6B3.mjs.map → chunk-BMYC2ILT.mjs.map} +1 -1
  12. package/dist/{chunk-PPKHCRRE.mjs → chunk-C76SOFXF.mjs} +3 -3
  13. package/dist/{chunk-PPKHCRRE.mjs.map → chunk-C76SOFXF.mjs.map} +1 -1
  14. package/dist/{chunk-IHUFOV7L.mjs → chunk-CH6SFONH.mjs} +15 -3
  15. package/dist/chunk-CH6SFONH.mjs.map +1 -0
  16. package/dist/{chunk-SF3U7ZF4.mjs → chunk-DWIEVCGK.mjs} +180 -15
  17. package/dist/chunk-DWIEVCGK.mjs.map +1 -0
  18. package/dist/{chunk-SZDAS7LK.mjs → chunk-IE2GGHNF.mjs} +131 -81
  19. package/dist/chunk-IE2GGHNF.mjs.map +1 -0
  20. package/dist/{chunk-ZTQBUKLJ.mjs → chunk-JJ4FPCBE.mjs} +142 -22
  21. package/dist/chunk-JJ4FPCBE.mjs.map +1 -0
  22. package/dist/{chunk-QRUAEXLR.mjs → chunk-K5BS2H56.mjs} +5 -5
  23. package/dist/{chunk-QRUAEXLR.mjs.map → chunk-K5BS2H56.mjs.map} +1 -1
  24. package/dist/{chunk-BNBOIDO5.mjs → chunk-K7VJU7LQ.mjs} +3 -3
  25. package/dist/{chunk-BNBOIDO5.mjs.map → chunk-K7VJU7LQ.mjs.map} +1 -1
  26. package/dist/{chunk-H22OZYTW.mjs → chunk-KOXOC2FI.mjs} +48 -39
  27. package/dist/chunk-KOXOC2FI.mjs.map +1 -0
  28. package/dist/{chunk-CXHNVYMD.mjs → chunk-KWDBVLST.mjs} +5 -5
  29. package/dist/{chunk-CXHNVYMD.mjs.map → chunk-KWDBVLST.mjs.map} +1 -1
  30. package/dist/{chunk-OQIQNKPQ.mjs → chunk-LTLLQUMN.mjs} +4 -4
  31. package/dist/{chunk-OQIQNKPQ.mjs.map → chunk-LTLLQUMN.mjs.map} +1 -1
  32. package/dist/{chunk-QGNU34T7.mjs → chunk-QLQ4MJNO.mjs} +10 -4
  33. package/dist/chunk-QLQ4MJNO.mjs.map +1 -0
  34. package/dist/{chunk-BU5KLO3P.mjs → chunk-T3N4BSJV.mjs} +4 -4
  35. package/dist/{chunk-BU5KLO3P.mjs.map → chunk-T3N4BSJV.mjs.map} +1 -1
  36. package/dist/{chunk-5JM35CXV.mjs → chunk-TMRFSOM7.mjs} +4 -4
  37. package/dist/{chunk-5JM35CXV.mjs.map → chunk-TMRFSOM7.mjs.map} +1 -1
  38. package/dist/geometry-2d.d.mts +1 -1
  39. package/dist/geometry-2d.d.ts +1 -1
  40. package/dist/geometry-2d.js +449 -172
  41. package/dist/geometry-2d.js.map +1 -1
  42. package/dist/geometry-2d.mjs +5 -5
  43. package/dist/geometry-3d.d.mts +1 -1
  44. package/dist/geometry-3d.d.ts +1 -1
  45. package/dist/geometry-3d.js +172 -22
  46. package/dist/geometry-3d.js.map +1 -1
  47. package/dist/geometry-3d.mjs +4 -4
  48. package/dist/graph-2d.d.mts +1 -1
  49. package/dist/graph-2d.d.ts +1 -1
  50. package/dist/graph-2d.js +307 -100
  51. package/dist/graph-2d.js.map +1 -1
  52. package/dist/graph-2d.mjs +7 -7
  53. package/dist/{host-HOSJHQ5H.mjs → host-4FIUNIDQ.mjs} +13 -12
  54. package/dist/host-4FIUNIDQ.mjs.map +1 -0
  55. package/dist/{host-2ISGVO7O.mjs → host-4ZB4XD4S.mjs} +9 -8
  56. package/dist/host-4ZB4XD4S.mjs.map +1 -0
  57. package/dist/{host-ZQCDAT6O.mjs → host-H2IGOKJU.mjs} +3 -3
  58. package/dist/{host-ZQCDAT6O.mjs.map → host-H2IGOKJU.mjs.map} +1 -1
  59. package/dist/{host-3UFGFMJ2.mjs → host-KMWP7KBT.mjs} +90 -43
  60. package/dist/host-KMWP7KBT.mjs.map +1 -0
  61. package/dist/index.d.mts +2 -2
  62. package/dist/index.d.ts +2 -2
  63. package/dist/index.js +453 -174
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +21 -21
  66. package/dist/latex.d.mts +1 -1
  67. package/dist/latex.d.ts +1 -1
  68. package/dist/latex.js +8 -2
  69. package/dist/latex.js.map +1 -1
  70. package/dist/latex.mjs +1 -1
  71. package/dist/render-NMS7OAV6.mjs +10 -0
  72. package/dist/{render-ZX2O2IK7.mjs.map → render-NMS7OAV6.mjs.map} +1 -1
  73. package/dist/serialize-PGHQZEPV.mjs +9 -0
  74. package/dist/{serialize-N4G6RFBB.mjs.map → serialize-PGHQZEPV.mjs.map} +1 -1
  75. package/dist/{types-C3FjpoUi.d.ts → types-tePd94vW.d.mts} +8 -0
  76. package/dist/{types-C3FjpoUi.d.mts → types-tePd94vW.d.ts} +8 -0
  77. package/package.json +1 -1
  78. package/dist/chunk-H22OZYTW.mjs.map +0 -1
  79. package/dist/chunk-IHUFOV7L.mjs.map +0 -1
  80. package/dist/chunk-QGNU34T7.mjs.map +0 -1
  81. package/dist/chunk-SF3U7ZF4.mjs.map +0 -1
  82. package/dist/chunk-SZDAS7LK.mjs.map +0 -1
  83. package/dist/chunk-ZTQBUKLJ.mjs.map +0 -1
  84. package/dist/host-2ISGVO7O.mjs.map +0 -1
  85. package/dist/host-3UFGFMJ2.mjs.map +0 -1
  86. package/dist/host-HOSJHQ5H.mjs.map +0 -1
  87. package/dist/render-ZX2O2IK7.mjs +0 -10
  88. package/dist/serialize-N4G6RFBB.mjs +0 -9
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { collectFreeVars } from './chunk-IHUFOV7L.mjs';
2
+ import { readLabelOffset, collectFreeVars } from './chunk-CH6SFONH.mjs';
3
3
  import { getKind } from './chunk-B4NJJZFR.mjs';
4
4
 
5
5
  // src/core/scene/render/types2d.ts
@@ -81,6 +81,7 @@ var JxgRenderer = class {
81
81
  this.elements.set(obj.id, el);
82
82
  this.attachFreePointDragSync(obj, el);
83
83
  this.attachGliderDragSync(obj, el);
84
+ this.attachLabelDragSync(obj, el);
84
85
  } catch (err) {
85
86
  console.warn(`[scene/render/2d] kh\xF4ng render \u0111\u01B0\u1EE3c ${obj.kind} id="${obj.id}":`, err);
86
87
  }
@@ -195,6 +196,54 @@ var JxgRenderer = class {
195
196
  });
196
197
  });
197
198
  }
199
+ /**
200
+ * Cho phép kéo NHÃN của bất kỳ object nào có label (point/line/segment/
201
+ * circle...). Khi user kéo nhãn, JSXGraph cộng dồn vào label.relativeCoords
202
+ * (drag-delta screen px) nhưng KHÔNG đổi attribute offset → vị trí cuối =
203
+ * offset + relativeCoords. Ta gộp lại thành offset thuần (readLabelOffset),
204
+ * zero relativeCoords để khỏi double-count khi update-hook/recreate áp lại
205
+ * offset, rồi dispatch UPDATE_ATTRS { labelOffset }. Right-click → reset.
206
+ */
207
+ attachLabelDragSync(obj, el) {
208
+ const label = el?.label;
209
+ if (!label || typeof label.on !== "function") return;
210
+ const sceneId = obj.id;
211
+ label.on("up", () => {
212
+ if (this.disposed) return;
213
+ const off = readLabelOffset(label);
214
+ if (!off) return;
215
+ const cur = this.store.getState().objects[sceneId];
216
+ if (!cur) return;
217
+ const prev = cur.attrs.labelOffset;
218
+ if (prev && prev[0] === off[0] && prev[1] === off[1]) return;
219
+ try {
220
+ label.setAttribute({ offset: off });
221
+ if (label.relativeCoords?.scrCoords) {
222
+ label.relativeCoords.scrCoords[1] = 0;
223
+ label.relativeCoords.scrCoords[2] = 0;
224
+ }
225
+ } catch {
226
+ }
227
+ this.store.dispatch({
228
+ type: "UPDATE_ATTRS",
229
+ payload: { id: sceneId, patch: { labelOffset: off } }
230
+ });
231
+ });
232
+ const node = label.rendNode;
233
+ if (node?.addEventListener) {
234
+ node.addEventListener("contextmenu", (ev) => {
235
+ if (this.disposed) return;
236
+ ev.preventDefault();
237
+ const c = this.store.getState().objects[sceneId];
238
+ if (!c) return;
239
+ if (c.attrs.labelOffset === void 0) return;
240
+ this.store.dispatch({
241
+ type: "UPDATE_ATTRS",
242
+ payload: { id: sceneId, patch: { labelOffset: void 0 } }
243
+ });
244
+ });
245
+ }
246
+ }
198
247
  remove(id) {
199
248
  this.removeHalo(id);
200
249
  this.selectedIds.delete(id);
@@ -331,88 +380,89 @@ var JxgRenderer = class {
331
380
  layer: 4,
332
381
  needsRegularUpdate: true
333
382
  };
383
+ const elementClass = el.elementClass;
384
+ const elType = el.elType;
385
+ const isPointLike = elementClass === 1 || elType === "point" || elType === "glider" || elType === "intersection";
386
+ const isPolygonLike = Array.isArray(el.vertices) && el.vertices.length >= 3;
387
+ const isCircleLike = elementClass === 3 || elType === "circle" || elType === "circumcircle" || elType === "incircle";
388
+ const isSegment = elType === "segment";
389
+ const isLineLike = elementClass === 2 || elType === "line" || elType === "arrow" || elType === "ray" || elType === "vector" || elType === "tangent" || elType === "normal" || elType === "parallel" || elType === "perpendicular" || elType === "bisector";
334
390
  const halos = [];
335
391
  try {
336
- switch (el.elType) {
337
- case "point":
338
- case "glider":
339
- case "intersection": {
340
- const baseSize = el.getAttribute?.("size") ?? 4;
341
- const halo = board.create("point", [
342
- () => el.X?.() ?? 0,
343
- () => el.Y?.() ?? 0
344
- ], {
345
- ...haloBase,
346
- size: baseSize + 6,
347
- face: "o",
348
- strokeWidth: 2,
349
- strokeOpacity: 0.75,
350
- fillOpacity: 0.25
351
- });
352
- halos.push(halo);
353
- break;
354
- }
355
- case "segment": {
356
- if (el.point1 && el.point2) {
357
- const halo = board.create("segment", [el.point1, el.point2], {
358
- ...haloBase,
359
- strokeWidth: 9,
360
- straightFirst: false,
361
- straightLast: false
362
- });
363
- halos.push(halo);
364
- }
365
- break;
366
- }
367
- case "line":
368
- case "arrow":
369
- case "ray":
370
- case "vector":
371
- case "tangent":
372
- case "normal":
373
- case "parallel":
374
- case "perpendicular":
375
- case "bisector": {
376
- if (el.point1 && el.point2) {
377
- const halo = board.create("line", [el.point1, el.point2], {
378
- ...haloBase,
379
- strokeWidth: 9
380
- });
381
- halos.push(halo);
382
- }
383
- break;
384
- }
385
- case "circle": {
386
- if (el.center && typeof el.Radius === "function") {
387
- const halo = board.create("circle", [el.center, () => el.Radius?.() ?? 0], {
388
- ...haloBase,
389
- strokeWidth: 9,
390
- fillOpacity: 0
391
- });
392
- halos.push(halo);
393
- }
394
- break;
395
- }
396
- case "polygon": {
397
- if (Array.isArray(el.vertices) && el.vertices.length >= 3) {
398
- const last = el.vertices.length - 1;
399
- const verts = el.vertices[last] === el.vertices[0] ? el.vertices.slice(0, last) : el.vertices.slice();
400
- const halo = board.create("polygon", verts, {
401
- ...haloBase,
402
- fillOpacity: 0.2,
403
- borders: {
404
- strokeColor: SEL_STROKE,
405
- strokeWidth: 7,
406
- strokeOpacity: 0.55,
407
- highlight: false
408
- }
409
- });
410
- halos.push(halo);
392
+ if (isPointLike) {
393
+ const baseSize = el.getAttribute?.("size") ?? 4;
394
+ const halo = board.create("point", [
395
+ () => el.X?.() ?? 0,
396
+ () => el.Y?.() ?? 0
397
+ ], {
398
+ ...haloBase,
399
+ size: baseSize + 6,
400
+ face: "o",
401
+ strokeWidth: 2,
402
+ strokeOpacity: 0.75,
403
+ fillOpacity: 0.25
404
+ });
405
+ halos.push(halo);
406
+ } else if (isPolygonLike) {
407
+ const verts = el.vertices;
408
+ const last = verts.length - 1;
409
+ const trimmed = verts[last] === verts[0] ? verts.slice(0, last) : verts.slice();
410
+ const halo = board.create("polygon", trimmed, {
411
+ ...haloBase,
412
+ fillOpacity: 0.2,
413
+ borders: {
414
+ strokeColor: SEL_STROKE,
415
+ strokeWidth: 7,
416
+ strokeOpacity: 0.55,
417
+ highlight: false
411
418
  }
412
- break;
419
+ });
420
+ halos.push(halo);
421
+ } else if (isCircleLike && el.center && typeof el.Radius === "function") {
422
+ const halo = board.create("circle", [el.center, () => el.Radius?.() ?? 0], {
423
+ ...haloBase,
424
+ strokeWidth: 9,
425
+ fillOpacity: 0
426
+ });
427
+ halos.push(halo);
428
+ } else if (isSegment && el.point1 && el.point2) {
429
+ const halo = board.create("segment", [el.point1, el.point2], {
430
+ ...haloBase,
431
+ strokeWidth: 9,
432
+ straightFirst: false,
433
+ straightLast: false
434
+ });
435
+ halos.push(halo);
436
+ } else if (isLineLike && el.point1 && el.point2) {
437
+ const halo = board.create("line", [el.point1, el.point2], {
438
+ ...haloBase,
439
+ strokeWidth: 9
440
+ });
441
+ halos.push(halo);
442
+ } else if (el.center && (el.radiuspoint ?? el.radiusPoint) && (el.anglepoint ?? el.anglePoint) && (elType === "arc" || elType === "semicircle" || elType === "circumcirclearc" || elType === "sector" || elType === "angle")) {
443
+ const rp = el.radiuspoint ?? el.radiusPoint;
444
+ const ap = el.anglepoint ?? el.anglePoint;
445
+ if (elType === "sector") {
446
+ halos.push(board.create("sector", [el.center, rp, ap], {
447
+ ...haloBase,
448
+ strokeWidth: 7,
449
+ fillOpacity: 0.2
450
+ }));
451
+ } else if (elType === "angle") {
452
+ halos.push(board.create("angle", [rp, el.center, ap], {
453
+ ...haloBase,
454
+ strokeWidth: 7,
455
+ fillOpacity: 0.2,
456
+ radius: el.getAttribute?.("radius") ?? 1
457
+ }));
458
+ } else {
459
+ halos.push(board.create("arc", [el.center, rp, ap], {
460
+ ...haloBase,
461
+ strokeWidth: 9,
462
+ fillColor: "none",
463
+ fillOpacity: 0
464
+ }));
413
465
  }
414
- default:
415
- break;
416
466
  }
417
467
  } catch (err) {
418
468
  console.warn("[scene/render/2d] halo create fail:", err);
@@ -422,5 +472,5 @@ var JxgRenderer = class {
422
472
  };
423
473
 
424
474
  export { DEFAULT_THEME_2D, JxgRenderer };
425
- //# sourceMappingURL=chunk-SZDAS7LK.mjs.map
426
- //# sourceMappingURL=chunk-SZDAS7LK.mjs.map
475
+ //# sourceMappingURL=chunk-IE2GGHNF.mjs.map
476
+ //# sourceMappingURL=chunk-IE2GGHNF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/scene/render/types2d.ts","../src/core/scene/render/JxgRenderer.ts"],"names":[],"mappings":"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","file":"chunk-IE2GGHNF.mjs","sourcesContent":["// src/core/scene/render/types2d.ts\nimport type { RenderCtx } from '../types';\n\nexport type Theme2D = {\n stroke: string;\n fill: string;\n label: string;\n axis: string;\n grid: string;\n pointFill: string;\n};\n\nexport const DEFAULT_THEME_2D: Theme2D = {\n stroke: '#0f172a',\n fill: '#60a5fa',\n label: '#0f172a',\n axis: '#94a3b8',\n grid: '#e2e8f0',\n pointFill: '#1e40af',\n};\n\nexport type RenderCtx2D = RenderCtx & {\n theme: Theme2D;\n};\n","// src/core/scene/render/JxgRenderer.ts\nimport type { Store } from '../store';\nimport type { State, SceneObject, RenderCtx } from '../types';\nimport { getKind } from '../registry';\nimport { DEFAULT_THEME_2D, type Theme2D } from './types2d';\nimport { collectFreeVars } from '../expressions/parser';\nimport { readLabelOffset } from '../kinds/_label';\n\nexport type JxgRendererOptions = { theme?: Theme2D };\n\nexport class JxgRenderer {\n private board: unknown;\n private store: Store;\n private theme: Theme2D;\n private elements = new Map<string, unknown>();\n private unsubscribe: () => void;\n private disposed = false;\n\n /** Chỉ dùng cho domain='graph2d': parameter.label → parameter.value */\n private paramMap: Record<string, number> = {};\n /** Chỉ dùng cho domain='graph2d': function2d.id → expression string */\n private functionExpr: Record<string, string> = {};\n\n constructor(store: Store, board: unknown, options: JxgRendererOptions = {}) {\n this.store = store;\n this.board = board;\n this.theme = options.theme ?? DEFAULT_THEME_2D;\n this.unsubscribe = store.subscribe((next, prev) => this.applyDiff(prev, next));\n // Render state hiện tại (vd LOAD chạy trước khi subscribe).\n this.applyDiff(undefined, store.getState());\n }\n\n private ctx(): RenderCtx {\n return {\n jxg: this.board,\n resolveRef: (id: string) => {\n // Synthetic \"<polyId>:border:<N>\" → polygon.borders[N]. Polygon edges\n // là sub-segment do JSXGraph auto-tạo bên trong polygon; chúng không\n // có scene id riêng. Synthetic id cho phép construct tools (vd\n // perpendicular qua một cạnh đa giác) tham chiếu cạnh như một line.\n const m = /^(.+):border:(\\d+)$/.exec(id);\n if (m) {\n const poly = this.elements.get(m[1]) as { borders?: unknown[] } | undefined;\n if (!poly) throw new Error(`[scene/2d] resolveRef: chưa render polygon id=\"${m[1]}\"`);\n const borders = poly.borders;\n const idx = parseInt(m[2], 10);\n if (!Array.isArray(borders) || !borders[idx]) {\n throw new Error(`[scene/2d] resolveRef: polygon \"${m[1]}\" không có border[${idx}]`);\n }\n return borders[idx];\n }\n const el = this.elements.get(id);\n if (!el) throw new Error(`[scene/2d] resolveRef: chưa render id=\"${id}\"`);\n return el;\n },\n defaults: { theme: this.theme, _functionExpr: this.functionExpr },\n paramMap: this.paramMap,\n };\n }\n\n /**\n * Rebuild `paramMap` và `functionExpr` từ state hiện tại.\n * Chỉ chạy khi domain='graph2d'. Chi phí thấp vì parameters thường ≤ 8.\n */\n private rebuildGraphMaps(state: State): void {\n if (state.meta.domain !== 'graph2d') return;\n const params: Record<string, number> = {};\n const fns: Record<string, string> = {};\n for (const id of state.order) {\n const obj = state.objects[id];\n if (obj.kind === 'parameter') {\n params[obj.label] = (obj.attrs as { value: number }).value;\n } else if (obj.kind === 'function2d') {\n fns[obj.id] = (obj.attrs as { expression: string }).expression;\n }\n }\n this.paramMap = params;\n this.functionExpr = fns;\n }\n\n private create(obj: SceneObject): void {\n try {\n const def = getKind(obj.kind);\n const el = def.render(obj, this.ctx());\n this.elements.set(obj.id, el);\n this.attachFreePointDragSync(obj, el);\n this.attachGliderDragSync(obj, el);\n this.attachLabelDragSync(obj, el);\n } catch (err) {\n console.warn(`[scene/render/2d] không render được ${obj.kind} id=\"${obj.id}\":`, err);\n }\n }\n\n /**\n * Sync vị trí glider của 3 constraint mới (onPerpendicular / onPerpBisector /\n * onCircleAroundPoint) — kéo → recompute t/theta dựa trên ref points + vị trí\n * glider hiện tại → UPDATE_ATTRS. Không đụng onLine/onSegment/onCircle hiện\n * tại (giữ behavior cũ).\n */\n private attachGliderDragSync(obj: SceneObject, el: unknown): void {\n if (obj.kind !== 'point') return;\n const c = (obj.attrs as { constraint?: { kind?: string } }).constraint as\n | { kind: string; [k: string]: unknown }\n | undefined;\n if (!c) return;\n if (\n c.kind !== 'onPerpendicular' &&\n c.kind !== 'onPerpBisector' &&\n c.kind !== 'onCircleAroundPoint'\n ) {\n return;\n }\n\n const point = el as { on?: (ev: string, cb: () => void) => void; X?: () => number; Y?: () => number };\n if (typeof point.on !== 'function') return;\n const sceneId = obj.id;\n\n point.on('up', () => {\n if (this.disposed) return;\n const cur = this.store.getState().objects[sceneId];\n if (!cur) return;\n const curC = (cur.attrs as { constraint?: { kind?: string; [k: string]: unknown } }).constraint as\n | { kind: string; [k: string]: unknown }\n | undefined;\n if (!curC) return;\n if (typeof point.X !== 'function' || typeof point.Y !== 'function') return;\n const x = point.X();\n const y = point.Y();\n if (!Number.isFinite(x) || !Number.isFinite(y)) return;\n\n if (curC.kind === 'onPerpendicular') {\n const T = this.elements.get(curC.through as string) as { X: () => number; Y: () => number } | null;\n const A = this.elements.get(curC.perpToA as string) as { X: () => number; Y: () => number } | null;\n const B = this.elements.get(curC.perpToB as string) as { X: () => number; Y: () => number } | null;\n if (!T || !A || !B) return;\n const dx = B.X() - A.X();\n const dy = B.Y() - A.Y();\n const len = Math.hypot(dx, dy) || 1;\n const ux = -dy / len;\n const uy = dx / len;\n const newT = (x - T.X()) * ux + (y - T.Y()) * uy;\n if (Math.abs(newT - (curC.t as number)) < 1e-9) return;\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { constraint: { ...curC, t: newT } } },\n });\n return;\n }\n\n if (curC.kind === 'onPerpBisector') {\n const A = this.elements.get(curC.p1 as string) as { X: () => number; Y: () => number } | null;\n const B = this.elements.get(curC.p2 as string) as { X: () => number; Y: () => number } | null;\n if (!A || !B) return;\n const Mx = (A.X() + B.X()) / 2;\n const My = (A.Y() + B.Y()) / 2;\n const dx = B.X() - A.X();\n const dy = B.Y() - A.Y();\n const len = Math.hypot(dx, dy) || 1;\n const ux = -dy / len;\n const uy = dx / len;\n const newT = (x - Mx) * ux + (y - My) * uy;\n if (Math.abs(newT - (curC.t as number)) < 1e-9) return;\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { constraint: { ...curC, t: newT } } },\n });\n return;\n }\n\n if (curC.kind === 'onCircleAroundPoint') {\n const C = this.elements.get(curC.center as string) as { X: () => number; Y: () => number } | null;\n if (!C) return;\n const newTheta = Math.atan2(y - C.Y(), x - C.X());\n if (Math.abs(newTheta - (curC.theta as number)) < 1e-9) return;\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { constraint: { ...curC, theta: newTheta } } },\n });\n return;\n }\n });\n }\n\n /**\n * Đồng bộ toạ độ live của free point về scene.constraint khi user kéo bằng\n * tay (Move tool / mobile drag). JSXGraph mutate obj.X()/Y() ngay nhưng\n * constraint vẫn giữ giá trị lúc tạo → serialize sẽ ra SVG y hệt cũ →\n * fileId SHA-256 trùng → Excalidraw bỏ qua refresh. (Regression từ\n * commit f41f366 sau scene v2 port.)\n *\n * Chỉ áp dụng cho free point — glider/intersection/midpoint không drag được\n * trực tiếp (toạ độ derived từ ref khác).\n */\n private attachFreePointDragSync(obj: SceneObject, el: unknown): void {\n if (obj.kind !== 'point') return;\n const c = (obj.attrs as { constraint?: { kind?: string } }).constraint;\n if (!c || c.kind !== 'free') return;\n \n const point = el as any;\n if (typeof point.on !== 'function') return;\n const sceneId = obj.id;\n point.on('up', () => {\n if (this.disposed) return;\n if (typeof point.X !== 'function' || typeof point.Y !== 'function') return;\n const x = point.X();\n const y = point.Y();\n if (!Number.isFinite(x) || !Number.isFinite(y)) return;\n const cur = this.store.getState().objects[sceneId];\n if (!cur) return;\n const curC = (cur.attrs as { constraint?: { kind?: string; x?: number; y?: number } }).constraint;\n if (!curC || curC.kind !== 'free') return;\n if (curC.x === x && curC.y === y) return;\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { constraint: { kind: 'free', x, y } } },\n });\n });\n }\n\n /**\n * Cho phép kéo NHÃN của bất kỳ object nào có label (point/line/segment/\n * circle...). Khi user kéo nhãn, JSXGraph cộng dồn vào label.relativeCoords\n * (drag-delta screen px) nhưng KHÔNG đổi attribute offset → vị trí cuối =\n * offset + relativeCoords. Ta gộp lại thành offset thuần (readLabelOffset),\n * zero relativeCoords để khỏi double-count khi update-hook/recreate áp lại\n * offset, rồi dispatch UPDATE_ATTRS { labelOffset }. Right-click → reset.\n */\n private attachLabelDragSync(obj: SceneObject, el: unknown): void {\n\n const label = (el as { label?: any })?.label;\n if (!label || typeof label.on !== 'function') return;\n const sceneId = obj.id;\n\n label.on('up', () => {\n if (this.disposed) return;\n const off = readLabelOffset(label);\n if (!off) return;\n const cur = this.store.getState().objects[sceneId];\n if (!cur) return;\n const prev = (cur.attrs as { labelOffset?: [number, number] }).labelOffset;\n if (prev && prev[0] === off[0] && prev[1] === off[1]) return;\n // Gộp drag-delta vào offset thuần + zero relativeCoords → vị trí không đổi,\n // tránh double-count khi update-hook/recreate áp lại offset.\n try {\n label.setAttribute({ offset: off });\n if (label.relativeCoords?.scrCoords) {\n label.relativeCoords.scrCoords[1] = 0;\n label.relativeCoords.scrCoords[2] = 0;\n }\n } catch { /* ignore */ }\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { labelOffset: off } },\n });\n });\n\n // Reset bằng chuột phải trên nhãn.\n const node = (label as { rendNode?: { addEventListener?: (e: string, cb: (ev: Event) => void) => void } }).rendNode;\n if (node?.addEventListener) {\n node.addEventListener('contextmenu', (ev: Event) => {\n if (this.disposed) return;\n ev.preventDefault();\n const c = this.store.getState().objects[sceneId];\n if (!c) return;\n if ((c.attrs as { labelOffset?: unknown }).labelOffset === undefined) return;\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { labelOffset: undefined } },\n });\n });\n }\n }\n\n private remove(id: string): void {\n // Selection halo (nếu có) phải bị xoá TRƯỚC element gốc — halo tham chiếu\n // tới point1/point2/center/vertices của element gốc qua lambda; xoá element\n // gốc trước sẽ làm halo dangling.\n this.removeHalo(id);\n this.selectedIds.delete(id);\n const el = this.elements.get(id);\n if (!el) return;\n try {\n const helpers = (el as Record<string, unknown>)._helpers;\n // Element chính bị remove trước, sau đó helpers (glider phụ trợ cho\n // tangent ...). Helpers thường là parent của element chính — nếu xoá\n // parent trước, JSXGraph có thể phàn nàn dangling reference.\n (this.board as { removeObject?: (e: unknown) => void }).removeObject?.(el);\n if (Array.isArray(helpers)) {\n for (const h of helpers) {\n try {\n (this.board as { removeObject?: (e: unknown) => void }).removeObject?.(h);\n } catch { /* ignore */ }\n }\n }\n } catch (err) {\n console.warn(`[scene/render/2d] không remove được id=\"${id}\":`, err);\n }\n this.elements.delete(id);\n }\n\n private applyDiff(prev: State | undefined, next: State): void {\n if (this.disposed) return;\n\n // Rebuild paramMap + functionExpr TRƯỚC khi diff, để ctx() có đúng\n // paramMap khi render lần đầu tiên.\n this.rebuildGraphMaps(next);\n\n const prevObjs = prev?.objects ?? {};\n const nextObjs = next.objects;\n\n // Xoá ids biến mất.\n for (const id of Object.keys(prevObjs)) {\n if (!(id in nextObjs)) this.remove(id);\n }\n\n // Thêm/cập nhật theo state.order — đảm bảo refs có trước.\n for (const id of next.order) {\n const cur = nextObjs[id];\n const old = prevObjs[id] as SceneObject | undefined;\n if (!old) {\n this.create(cur);\n continue;\n }\n if (Object.is(old, cur)) continue;\n const def = getKind(cur.kind);\n const existing = this.elements.get(id);\n if (def.update && existing) {\n try { def.update(cur, old, this.ctx(), existing); continue; }\n catch (err) { console.warn(`[scene/render/2d] update fail, recreate:`, err); }\n }\n this.remove(id);\n this.create(cur);\n }\n\n // Sau diff bình thường: nếu domain='graph2d', detect parameter value changes\n // và force re-render các function2d phụ thuộc.\n if (next.meta.domain === 'graph2d' && prev) {\n const changedParams = new Set<string>();\n for (const id of next.order) {\n const cur = next.objects[id];\n const old = prev.objects[id] as SceneObject | undefined;\n if (cur.kind !== 'parameter' || old?.kind !== 'parameter') continue;\n if ((cur.attrs as { value: number }).value !== (old.attrs as { value: number }).value) {\n changedParams.add(cur.label);\n }\n }\n if (changedParams.size > 0) {\n for (const id of next.order) {\n const obj = next.objects[id];\n if (obj.kind !== 'function2d') continue;\n const expr = (obj.attrs as { expression: string }).expression;\n const refs = collectFreeVars(expr);\n if (refs.some((r) => changedParams.has(r))) {\n this.remove(id);\n this.create(obj);\n }\n }\n }\n }\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.unsubscribe();\n for (const id of Array.from(this.elements.keys())) this.remove(id);\n this.disposed = true;\n }\n\n /** Return the rendered JSXGraph element for a scene id, or null if not found. */\n getElement(id: string): unknown {\n return this.elements.get(id) ?? null;\n }\n\n /** Return a read-only view of the scene id → JSXGraph element map (for hit-test). */\n listElements(): Map<string, unknown> {\n return this.elements;\n }\n\n // Selection halo overlay model: thay vì đổi màu element gốc thành đỏ, tạo\n // một halo element gray phía sau (lower layer) → giữ nguyên màu gốc. Hỗ\n // trợ multi-select cho cả canvas click-selection lẫn ObjectListPanel.\n private selectedIds: Set<string> = new Set();\n private haloMap: Map<string, unknown[]> = new Map();\n\n highlight(ids: string | string[] | null): void {\n if (this.disposed) return;\n const newIds = new Set<string>(\n ids == null ? [] : Array.isArray(ids) ? ids : [ids],\n );\n // Remove halos cho ids đã bị bỏ chọn.\n for (const id of this.selectedIds) {\n if (!newIds.has(id)) this.removeHalo(id);\n }\n // Add halos cho ids mới chọn.\n for (const id of newIds) {\n if (!this.selectedIds.has(id) && this.elements.has(id)) this.addHalo(id);\n }\n this.selectedIds = newIds;\n try {\n (this.board as { update?: () => void }).update?.();\n } catch { /* ignore */ }\n }\n\n private removeHalo(id: string): void {\n const halos = this.haloMap.get(id);\n if (!halos) return;\n const board = this.board as { removeObject?: (e: unknown) => void };\n for (const h of halos) {\n try { board.removeObject?.(h); } catch { /* ignore */ }\n }\n this.haloMap.delete(id);\n }\n\n private addHalo(id: string): void {\n const el = this.elements.get(id) as\n | {\n elType?: string;\n getAttribute?: (k: string) => unknown;\n X?: () => number;\n Y?: () => number;\n point1?: unknown;\n point2?: unknown;\n center?: unknown;\n Radius?: () => number;\n vertices?: unknown[];\n // Arc: radiuspoint/anglepoint (chữ thường). Sector/Angle: radiusPoint/\n // anglePoint (chữ P HOA). center dùng chung.\n radiuspoint?: unknown;\n anglepoint?: unknown;\n radiusPoint?: unknown;\n anglePoint?: unknown;\n }\n | undefined;\n if (!el) return;\n const board = this.board as {\n create?: (kind: string, parents: unknown[], attrs?: unknown) => unknown;\n };\n if (!board.create) return;\n\n // Selection palette — gray fill + darker gray border (xem\n // tham chiếu /tmp/ss.png).\n const SEL_STROKE = '#475569'; // slate-600\n const SEL_FILL = '#cbd5e1'; // slate-300\n const haloBase = {\n strokeColor: SEL_STROKE,\n strokeOpacity: 0.55,\n fillColor: SEL_FILL,\n fillOpacity: 0.3,\n fixed: true,\n withLabel: false,\n name: '',\n highlight: false,\n layer: 4,\n needsRegularUpdate: true,\n };\n // Phân loại element bằng `elementClass` (JSXGraph constant: 1=POINT, 2=LINE,\n // 3=CIRCLE) — set ĐÚNG cho MỌI cách dựng phái sinh (circumcenter,\n // otherintersection, perpendicularpoint, circumcircle, incircle, perpendicular,\n // parallel, tangent...). elType string KHÔNG đủ vì mỗi construction 1 tên riêng\n // → trước đây O/M/N/D/E/F (điểm), O_c (circumcircle), square (regularpolygon)\n // bị bỏ halo. Đồng bộ với objKind (tools.tsx). Polygon nhận qua `vertices`\n // (elementClass polygon ≠ 1/2/3). Fallback elType cho test mock không set class.\n const elementClass = (el as { elementClass?: number }).elementClass;\n const elType = el.elType;\n const isPointLike =\n elementClass === 1 || elType === 'point' || elType === 'glider' || elType === 'intersection';\n const isPolygonLike = Array.isArray(el.vertices) && el.vertices.length >= 3;\n const isCircleLike =\n elementClass === 3 || elType === 'circle' || elType === 'circumcircle' || elType === 'incircle';\n const isSegment = elType === 'segment';\n const isLineLike =\n elementClass === 2 ||\n elType === 'line' || elType === 'arrow' || elType === 'ray' || elType === 'vector' ||\n elType === 'tangent' || elType === 'normal' || elType === 'parallel' ||\n elType === 'perpendicular' || elType === 'bisector';\n\n const halos: unknown[] = [];\n try {\n if (isPointLike) {\n const baseSize = (el.getAttribute?.('size') as number | undefined) ?? 4;\n const halo = board.create('point', [\n () => el.X?.() ?? 0,\n () => el.Y?.() ?? 0,\n ], {\n ...haloBase,\n size: baseSize + 6,\n face: 'o',\n strokeWidth: 2,\n strokeOpacity: 0.75,\n fillOpacity: 0.25,\n });\n halos.push(halo);\n } else if (isPolygonLike) {\n // JSXGraph polygon.vertices có thể append vertex đầu lặp lại ở cuối để\n // đóng path — trim cho an toàn. Bắt cả 'polygon' lẫn 'regularpolygon'.\n const verts = el.vertices!;\n const last = verts.length - 1;\n const trimmed = verts[last] === verts[0] ? verts.slice(0, last) : verts.slice();\n const halo = board.create('polygon', trimmed, {\n ...haloBase,\n fillOpacity: 0.2,\n borders: {\n strokeColor: SEL_STROKE,\n strokeWidth: 7,\n strokeOpacity: 0.55,\n highlight: false,\n },\n });\n halos.push(halo);\n } else if (isCircleLike && el.center && typeof el.Radius === 'function') {\n // Bắt cả 'circle', 'circumcircle', 'incircle' (elementClass 3).\n const halo = board.create('circle', [el.center, () => el.Radius?.() ?? 0], {\n ...haloBase,\n strokeWidth: 9,\n fillOpacity: 0,\n });\n halos.push(halo);\n } else if (isSegment && el.point1 && el.point2) {\n const halo = board.create('segment', [el.point1, el.point2], {\n ...haloBase,\n strokeWidth: 9,\n straightFirst: false,\n straightLast: false,\n });\n halos.push(halo);\n } else if (isLineLike && el.point1 && el.point2) {\n // Gồm cả slopetriangle (extends Line, elementClass 2) → halo line dọc\n // đường dốc.\n const halo = board.create('line', [el.point1, el.point2], {\n ...haloBase,\n strokeWidth: 9,\n });\n halos.push(halo);\n } else if (\n el.center && (el.radiuspoint ?? el.radiusPoint) && (el.anglepoint ?? el.anglePoint) &&\n (elType === 'arc' || elType === 'semicircle' || elType === 'circumcirclearc' ||\n elType === 'sector' || elType === 'angle')\n ) {\n // Arc/Sector/Angle (CURVE class) — dựng lại element cùng loại, dày xám.\n // ⚠️ Runtime JSXGraph dùng `radiuspoint`/`anglepoint` (chữ THƯỜNG) cho cả\n // Arc LẪN Sector/Angle — .d.ts ghi `radiusPoint`/`anglePoint` (P HOA) cho\n // Sector/Angle là SAI (đã verify bằng Playwright). Đọc cả hai cho an toàn.\n const rp = el.radiuspoint ?? el.radiusPoint;\n const ap = el.anglepoint ?? el.anglePoint;\n if (elType === 'sector') {\n halos.push(board.create('sector', [el.center, rp, ap], {\n ...haloBase, strokeWidth: 7, fillOpacity: 0.2,\n }));\n } else if (elType === 'angle') {\n // create('angle', [p1, vertex, p2]); vertex = center.\n halos.push(board.create('angle', [rp, el.center, ap], {\n ...haloBase, strokeWidth: 7, fillOpacity: 0.2,\n radius: (el.getAttribute?.('radius') as number | undefined) ?? 1,\n }));\n } else {\n halos.push(board.create('arc', [el.center, rp, ap], {\n ...haloBase, strokeWidth: 9, fillColor: 'none', fillOpacity: 0,\n }));\n }\n }\n // Còn lại (functiongraph/curve, text...) — chưa hỗ trợ halo; hiếm khi chọn.\n } catch (err) {\n console.warn('[scene/render/2d] halo create fail:', err);\n }\n if (halos.length) this.haloMap.set(id, halos);\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { compile, validate } from './chunk-IHUFOV7L.mjs';
2
+ import { labelOpts, compile, validate } from './chunk-CH6SFONH.mjs';
3
3
  import { createEmptyState } from './chunk-73Q7ADVL.mjs';
4
4
  import { registerKind } from './chunk-B4NJJZFR.mjs';
5
5
  import * as React from 'react';
@@ -563,8 +563,12 @@ function constraintRefs2D(c) {
563
563
  return [c.line, c.circle, c.other];
564
564
  case "tangencyPoint":
565
565
  return [c.circle, c.onLine];
566
- case "arcMidpoint":
567
- return [c.circle, c.a, c.b, c.notContaining];
566
+ case "arcMidpoint": {
567
+ const containment = c.notContaining ?? c.containing;
568
+ return containment ? [c.circle, c.a, c.b, containment] : [c.circle, c.a, c.b];
569
+ }
570
+ case "mixtilinearPoint":
571
+ return [c.vertices[0], c.vertices[1], c.vertices[2]];
568
572
  case "pointAtDistance": {
569
573
  const d = c.distance;
570
574
  const extra = d.kind === "circleRadius" ? [d.circle] : d.kind === "segmentLength" ? [d.p1, d.p2] : [];
@@ -777,7 +781,7 @@ function dist(p, q) {
777
781
  function sideOf(a, b, p) {
778
782
  return (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]);
779
783
  }
780
- function arcMidpoint(center, radius, a, b, notContaining) {
784
+ function arcMidpoint(center, radius, a, b, reference, sameSide = false) {
781
785
  const mcx = (a[0] + b[0]) / 2;
782
786
  const mcy = (a[1] + b[1]) / 2;
783
787
  let ux = mcx - center[0];
@@ -792,12 +796,18 @@ function arcMidpoint(center, radius, a, b, notContaining) {
792
796
  uy /= len;
793
797
  const cand1 = [center[0] + radius * ux, center[1] + radius * uy];
794
798
  const cand2 = [center[0] - radius * ux, center[1] - radius * uy];
799
+ if (!reference) return cand1[1] >= cand2[1] ? cand1 : cand2;
800
+ const notContaining = reference;
795
801
  const sN = sideOf(a, b, notContaining);
796
802
  if (Math.abs(sN) < 1e-9) {
797
- return dist(cand1, notContaining) >= dist(cand2, notContaining) ? cand1 : cand2;
803
+ const far = dist(cand1, notContaining) >= dist(cand2, notContaining) ? cand1 : cand2;
804
+ const near = far === cand1 ? cand2 : cand1;
805
+ return sameSide ? near : far;
798
806
  }
799
807
  const s1 = sideOf(a, b, cand1);
800
- return s1 * sN < 0 ? cand1 : cand2;
808
+ const opp = s1 * sN < 0 ? cand1 : cand2;
809
+ const same = opp === cand1 ? cand2 : cand1;
810
+ return sameSide ? same : opp;
801
811
  }
802
812
  function excenter(vertices, oppositeIndex) {
803
813
  const [A, B, C] = vertices;
@@ -813,6 +823,35 @@ function excenter(vertices, oppositeIndex) {
813
823
  (w[0] * A[1] + w[1] * B[1] + w[2] * C[1]) / sum
814
824
  ];
815
825
  }
826
+ function circumcenterXY(a, b, c) {
827
+ const ax = a[0], ay = a[1], bx = b[0], by = b[1], cx = c[0], cy = c[1];
828
+ const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
829
+ if (Math.abs(d) < 1e-12) return [(ax + bx + cx) / 3, (ay + by + cy) / 3];
830
+ const ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
831
+ const uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
832
+ return [ux, uy];
833
+ }
834
+ function mixtilinearPoint(a, b, c, which) {
835
+ const O = circumcenterXY(a, b, c);
836
+ const R = Math.hypot(O[0] - a[0], O[1] - a[1]);
837
+ const ux1 = (b[0] - a[0]) / (Math.hypot(b[0] - a[0], b[1] - a[1]) || 1);
838
+ const uy1 = (b[1] - a[1]) / (Math.hypot(b[0] - a[0], b[1] - a[1]) || 1);
839
+ const ux2 = (c[0] - a[0]) / (Math.hypot(c[0] - a[0], c[1] - a[1]) || 1);
840
+ const uy2 = (c[1] - a[1]) / (Math.hypot(c[0] - a[0], c[1] - a[1]) || 1);
841
+ let bx = ux1 + ux2, by = uy1 + uy2;
842
+ const bl = Math.hypot(bx, by) || 1;
843
+ bx /= bl;
844
+ by /= bl;
845
+ const cosA = ux1 * ux2 + uy1 * uy2;
846
+ const sinHalf = Math.sqrt(Math.max(0, (1 - cosA) / 2));
847
+ const cos2Half = Math.max(1e-9, (1 + cosA) / 2);
848
+ const dotAO = bx * (O[0] - a[0]) + by * (O[1] - a[1]);
849
+ const d = 2 * (dotAO - R * sinHalf) / cos2Half;
850
+ const K = [a[0] + d * bx, a[1] + d * by];
851
+ if (which === "center") return K;
852
+ const kl = Math.hypot(K[0] - O[0], K[1] - O[1]) || 1;
853
+ return [O[0] + R * (K[0] - O[0]) / kl, O[1] + R * (K[1] - O[1]) / kl];
854
+ }
816
855
  function pointAtDistanceCoord(from, through, d) {
817
856
  const dx = through[0] - from[0];
818
857
  const dy = through[1] - from[1];
@@ -831,29 +870,38 @@ function radicalAxisFoot(o1, r1, o2, r2) {
831
870
  var arcMidpointConstraint = definePointConstraint({
832
871
  kind: "arcMidpoint",
833
872
  validate: (c) => {
834
- if (!c.circle || !c.a || !c.b || !c.notContaining) {
835
- throw new Error("point.arcMidpoint: circle, a, b, notContaining b\u1EAFt bu\u1ED9c");
873
+ if (!c.circle || !c.a || !c.b) {
874
+ throw new Error("point.arcMidpoint: circle, a, b b\u1EAFt bu\u1ED9c");
875
+ }
876
+ if (c.notContaining && c.containing) {
877
+ throw new Error("point.arcMidpoint: kh\xF4ng th\u1EC3 v\u1EEBa notContaining v\u1EEBa containing");
836
878
  }
837
879
  },
838
880
  describe: (obj, state, c) => {
839
881
  const al = state?.objects[c.a]?.label ?? c.a;
840
882
  const bl = state?.objects[c.b]?.label ?? c.b;
841
- const nl = state?.objects[c.notContaining]?.label ?? c.notContaining;
842
- return `${obj.label} = trung \u0111i\u1EC3m cung ${al}${bl} (kh\xF4ng ch\u1EE9a ${nl})`;
883
+ const ref = c.containing ?? c.notContaining;
884
+ if (!ref) return `${obj.label} = trung \u0111i\u1EC3m cung ${al}${bl}`;
885
+ const rl = state?.objects[ref]?.label ?? ref;
886
+ const rel = c.containing ? "ch\u1EE9a" : "kh\xF4ng ch\u1EE9a";
887
+ return `${obj.label} = trung \u0111i\u1EC3m cung ${al}${bl} (${rel} ${rl})`;
843
888
  },
844
889
  render: (obj, ctx, c, opts) => {
845
890
  const board = ctx.jxg;
846
891
  const circle = ctx.resolveRef(c.circle);
847
892
  const A = ctx.resolveRef(c.a);
848
893
  const B = ctx.resolveRef(c.b);
849
- const N = ctx.resolveRef(c.notContaining);
894
+ const refName = c.containing ?? c.notContaining;
895
+ const ref = refName ? ctx.resolveRef(refName) : void 0;
896
+ const sameSide = !!c.containing;
850
897
  const O = circle?.center ?? circle?.midpoint ?? circle;
851
898
  const am = () => arcMidpoint(
852
899
  [O.X(), O.Y()],
853
900
  circle.Radius(),
854
901
  [A.X(), A.Y()],
855
902
  [B.X(), B.Y()],
856
- [N.X(), N.Y()]
903
+ ref ? [ref.X(), ref.Y()] : void 0,
904
+ sameSide
857
905
  );
858
906
  return board.create("point", [() => am()[0], () => am()[1]], opts);
859
907
  }
@@ -894,6 +942,36 @@ var excenterConstraint = definePointConstraint({
894
942
  }
895
943
  });
896
944
 
945
+ // src/core/scene/kinds/point-constraints/mixtilinearPoint.ts
946
+ var mixtilinearPointConstraint = definePointConstraint({
947
+ kind: "mixtilinearPoint",
948
+ validate: (c) => {
949
+ if (!Array.isArray(c.vertices) || c.vertices.length !== 3 || !c.vertices.every(Boolean)) {
950
+ throw new Error("point.mixtilinearPoint: vertices ph\u1EA3i l\xE0 tuple 3 id non-empty");
951
+ }
952
+ if (c.which !== "center" && c.which !== "touch") {
953
+ throw new Error("point.mixtilinearPoint: which ph\u1EA3i 'center' | 'touch'");
954
+ }
955
+ },
956
+ describe: (obj, state, c) => {
957
+ const labels = c.vertices.map((id) => state?.objects[id]?.label ?? id).join("");
958
+ return c.which === "center" ? `${obj.label} = t\xE2m \u0111\u01B0\u1EDDng tr\xF2n mixtilinear \u0394${labels}` : `${obj.label} = ti\u1EBFp \u0111i\u1EC3m mixtilinear \u0394${labels} v\u1EDBi (O)`;
959
+ },
960
+ render: (obj, ctx, c, opts) => {
961
+ const board = ctx.jxg;
962
+ const a = ctx.resolveRef(c.vertices[0]);
963
+ const b = ctx.resolveRef(c.vertices[1]);
964
+ const d = ctx.resolveRef(c.vertices[2]);
965
+ const mp = () => mixtilinearPoint(
966
+ [a.X(), a.Y()],
967
+ [b.X(), b.Y()],
968
+ [d.X(), d.Y()],
969
+ c.which
970
+ );
971
+ return board.create("point", [() => mp()[0], () => mp()[1]], opts);
972
+ }
973
+ });
974
+
897
975
  // src/core/scene/kinds/point-constraints/shared.ts
898
976
  function buildJxgTransforms(board, ctx, t) {
899
977
  switch (t.kind) {
@@ -945,7 +1023,8 @@ function buildPointOpts(obj) {
945
1023
  strokeColor: obj.attrs.color ?? "#1e40af",
946
1024
  fillColor: obj.attrs.color ?? "#1e40af",
947
1025
  face: obj.attrs.face ?? "o",
948
- size: obj.attrs.size ?? 4
1026
+ size: obj.attrs.size ?? 4,
1027
+ ...labelOpts(obj.attrs.labelOffset, [10, 10])
949
1028
  };
950
1029
  }
951
1030
 
@@ -1183,6 +1262,7 @@ var ALL = [
1183
1262
  centroidConstraint,
1184
1263
  arcMidpointConstraint,
1185
1264
  excenterConstraint,
1265
+ mixtilinearPointConstraint,
1186
1266
  pointAtDistanceConstraint,
1187
1267
  circleIntersectionConstraint,
1188
1268
  circleSecondIntersectionConstraint,
@@ -1265,7 +1345,8 @@ var def3 = {
1265
1345
  strokeColor: obj.attrs.color ?? "#1e40af",
1266
1346
  fillColor: obj.attrs.color ?? "#1e40af",
1267
1347
  face: obj.attrs.face ?? "o",
1268
- size: obj.attrs.size ?? 4
1348
+ size: obj.attrs.size ?? 4,
1349
+ ...labelOpts(obj.attrs.labelOffset, [10, 10])
1269
1350
  });
1270
1351
  } catch {
1271
1352
  }
@@ -1309,7 +1390,8 @@ var def4 = {
1309
1390
  strokeWidth: obj.attrs.width ?? 2,
1310
1391
  dash: obj.attrs.dash ?? 0,
1311
1392
  visible: obj.visible,
1312
- fixed: obj.locked
1393
+ fixed: obj.locked,
1394
+ ...labelOpts(obj.attrs.labelOffset)
1313
1395
  });
1314
1396
  }
1315
1397
  };
@@ -1380,7 +1462,8 @@ var def5 = {
1380
1462
  strokeWidth: obj.attrs.width ?? 2,
1381
1463
  dash: obj.attrs.dash ?? 0,
1382
1464
  visible: obj.visible,
1383
- fixed: obj.locked
1465
+ fixed: obj.locked,
1466
+ ...labelOpts(obj.attrs.labelOffset)
1384
1467
  };
1385
1468
  const c = obj.attrs.construction;
1386
1469
  if (!c) {
@@ -1675,15 +1758,17 @@ var def8 = {
1675
1758
  const board = ctx.jxg;
1676
1759
  const isCenterLabel = (l) => /^[A-Z]['′]?\d*$/u.test(l);
1677
1760
  const isCenter = isCenterLabel(obj.label);
1761
+ const isRenamedCircle = /_c$/.test(obj.label);
1678
1762
  const baseOpts = {
1679
1763
  name: obj.label,
1680
- withLabel: isCenter ? obj.attrs.showLabel ?? false : true,
1764
+ withLabel: isCenter ? obj.attrs.showLabel ?? false : isRenamedCircle ? false : true,
1681
1765
  strokeColor: obj.attrs.color ?? "#0f172a",
1682
1766
  strokeWidth: obj.attrs.width ?? 2,
1683
1767
  dash: obj.attrs.dash ?? 0,
1684
1768
  fillColor: "none",
1685
1769
  visible: obj.visible,
1686
- fixed: obj.locked
1770
+ fixed: obj.locked,
1771
+ ...labelOpts(obj.attrs.labelOffset)
1687
1772
  };
1688
1773
  const c = asConstruction(obj.attrs);
1689
1774
  if (c?.kind === "circumscribed") {
@@ -2141,8 +2226,11 @@ var def12 = {
2141
2226
  const opts = {
2142
2227
  name: obj.label,
2143
2228
  withLabel: true,
2144
- strokeColor: obj.attrs.color ?? "#dc2626",
2145
- fillColor: obj.attrs.color ?? "#dc2626",
2229
+ // Cùng màu xanh với mọi điểm khác (buildPointOpts dùng '#1e40af').
2230
+ // Trước đây điểm giao tô đỏ '#dc2626' → tách biệt thị giác nhưng gây
2231
+ // khó hiểu ("vì sao điểm này khác màu?"). Giữ chung một màu.
2232
+ strokeColor: obj.attrs.color ?? "#1e40af",
2233
+ fillColor: obj.attrs.color ?? "#1e40af",
2146
2234
  visible: obj.visible,
2147
2235
  fixed: obj.locked
2148
2236
  };
@@ -2151,6 +2239,38 @@ var def12 = {
2151
2239
  }
2152
2240
  const branch = obj.attrs.branch ?? 0;
2153
2241
  return board.create("intersection", [a, b, branch], opts);
2242
+ },
2243
+ /**
2244
+ * Cập nhật TẠI CHỖ các thuộc tính "trang trí" (tên/màu/ẩn-hiện/khoá) qua
2245
+ * setAttribute — giữ nguyên JxgObj identity nên các object phụ thuộc điểm
2246
+ * giao (đường thẳng qua nó, …) KHÔNG bị stale parent ref. Mô phỏng update
2247
+ * hook của point.ts.
2248
+ *
2249
+ * Nếu định nghĩa hình học đổi (kind/ref1/ref2/branch) thì throw → renderer
2250
+ * fallback remove + create để JSXGraph dựng lại phép giao đúng.
2251
+ */
2252
+ update: (obj, prev, ctx, existing) => {
2253
+ const a = obj.attrs;
2254
+ const p = prev.attrs;
2255
+ const branchA = a.branch;
2256
+ const branchP = p.branch;
2257
+ if (a.kind !== p.kind || a.ref1 !== p.ref1 || a.ref2 !== p.ref2 || branchA !== branchP) {
2258
+ throw new Error("intersection: \u0111\u1ECBnh ngh\u0129a h\xECnh h\u1ECDc \u0111\u1ED5i \u2014 recreate");
2259
+ }
2260
+ const el = existing;
2261
+ if (typeof el.setAttribute === "function") {
2262
+ try {
2263
+ el.setAttribute({
2264
+ name: obj.label,
2265
+ withLabel: true,
2266
+ strokeColor: a.color ?? "#1e40af",
2267
+ fillColor: a.color ?? "#1e40af",
2268
+ visible: obj.visible,
2269
+ fixed: obj.locked
2270
+ });
2271
+ } catch {
2272
+ }
2273
+ }
2154
2274
  }
2155
2275
  };
2156
2276
  registerKind(def12);
@@ -2532,5 +2652,5 @@ function deserializeScene(domain, raw) {
2532
2652
  }
2533
2653
 
2534
2654
  export { deserializeScene, listObjects, nextLabel, serializeScene, useEditorState };
2535
- //# sourceMappingURL=chunk-ZTQBUKLJ.mjs.map
2536
- //# sourceMappingURL=chunk-ZTQBUKLJ.mjs.map
2655
+ //# sourceMappingURL=chunk-JJ4FPCBE.mjs.map
2656
+ //# sourceMappingURL=chunk-JJ4FPCBE.mjs.map