@xom11/whiteboard 0.29.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 (93) hide show
  1. package/dist/ai.d.mts +259 -33
  2. package/dist/ai.d.ts +259 -33
  3. package/dist/ai.js +5424 -470
  4. package/dist/ai.js.map +1 -1
  5. package/dist/ai.mjs +4971 -351
  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-GEC2D2EQ.mjs → chunk-BMYC2ILT.mjs} +4 -4
  11. package/dist/{chunk-GEC2D2EQ.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-E6EDOPGT.mjs → chunk-DWIEVCGK.mjs} +254 -16
  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-QK6OVDLC.mjs +103 -0
  33. package/dist/chunk-QK6OVDLC.mjs.map +1 -0
  34. package/dist/{chunk-QGNU34T7.mjs → chunk-QLQ4MJNO.mjs} +10 -4
  35. package/dist/chunk-QLQ4MJNO.mjs.map +1 -0
  36. package/dist/{chunk-BU5KLO3P.mjs → chunk-T3N4BSJV.mjs} +4 -4
  37. package/dist/{chunk-BU5KLO3P.mjs.map → chunk-T3N4BSJV.mjs.map} +1 -1
  38. package/dist/{chunk-5JM35CXV.mjs → chunk-TMRFSOM7.mjs} +4 -4
  39. package/dist/{chunk-5JM35CXV.mjs.map → chunk-TMRFSOM7.mjs.map} +1 -1
  40. package/dist/geometry-2d.d.mts +1 -1
  41. package/dist/geometry-2d.d.ts +1 -1
  42. package/dist/geometry-2d.js +841 -204
  43. package/dist/geometry-2d.js.map +1 -1
  44. package/dist/geometry-2d.mjs +5 -5
  45. package/dist/geometry-3d.d.mts +1 -1
  46. package/dist/geometry-3d.d.ts +1 -1
  47. package/dist/geometry-3d.js +172 -22
  48. package/dist/geometry-3d.js.map +1 -1
  49. package/dist/geometry-3d.mjs +4 -4
  50. package/dist/graph-2d.d.mts +1 -1
  51. package/dist/graph-2d.d.ts +1 -1
  52. package/dist/graph-2d.js +307 -100
  53. package/dist/graph-2d.js.map +1 -1
  54. package/dist/graph-2d.mjs +7 -7
  55. package/dist/handleExtractProblem-BrDY9ifM.d.mts +58 -0
  56. package/dist/handleExtractProblem-BrDY9ifM.d.ts +58 -0
  57. package/dist/{host-HOSJHQ5H.mjs → host-4FIUNIDQ.mjs} +13 -12
  58. package/dist/host-4FIUNIDQ.mjs.map +1 -0
  59. package/dist/{host-2ISGVO7O.mjs → host-4ZB4XD4S.mjs} +9 -8
  60. package/dist/host-4ZB4XD4S.mjs.map +1 -0
  61. package/dist/{host-ZQCDAT6O.mjs → host-H2IGOKJU.mjs} +3 -3
  62. package/dist/{host-ZQCDAT6O.mjs.map → host-H2IGOKJU.mjs.map} +1 -1
  63. package/dist/{host-HKMZSCIT.mjs → host-KMWP7KBT.mjs} +286 -74
  64. package/dist/host-KMWP7KBT.mjs.map +1 -0
  65. package/dist/index.d.mts +3 -2
  66. package/dist/index.d.ts +3 -2
  67. package/dist/index.js +849 -206
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +22 -21
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/latex.d.mts +1 -1
  72. package/dist/latex.d.ts +1 -1
  73. package/dist/latex.js +8 -2
  74. package/dist/latex.js.map +1 -1
  75. package/dist/latex.mjs +1 -1
  76. package/dist/render-NMS7OAV6.mjs +10 -0
  77. package/dist/{render-ZX2O2IK7.mjs.map → render-NMS7OAV6.mjs.map} +1 -1
  78. package/dist/serialize-PGHQZEPV.mjs +9 -0
  79. package/dist/{serialize-N4G6RFBB.mjs.map → serialize-PGHQZEPV.mjs.map} +1 -1
  80. package/dist/{types-C3FjpoUi.d.ts → types-tePd94vW.d.mts} +8 -0
  81. package/dist/{types-C3FjpoUi.d.mts → types-tePd94vW.d.ts} +8 -0
  82. package/package.json +2 -1
  83. package/dist/chunk-E6EDOPGT.mjs.map +0 -1
  84. package/dist/chunk-H22OZYTW.mjs.map +0 -1
  85. package/dist/chunk-IHUFOV7L.mjs.map +0 -1
  86. package/dist/chunk-QGNU34T7.mjs.map +0 -1
  87. package/dist/chunk-SZDAS7LK.mjs.map +0 -1
  88. package/dist/chunk-ZTQBUKLJ.mjs.map +0 -1
  89. package/dist/host-2ISGVO7O.mjs.map +0 -1
  90. package/dist/host-HKMZSCIT.mjs.map +0 -1
  91. package/dist/host-HOSJHQ5H.mjs.map +0 -1
  92. package/dist/render-ZX2O2IK7.mjs +0 -10
  93. package/dist/serialize-N4G6RFBB.mjs +0 -9
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- export { geometryStamp } from './chunk-GEC2D2EQ.mjs';
3
- import './chunk-H22OZYTW.mjs';
2
+ export { geometryStamp } from './chunk-BMYC2ILT.mjs';
3
+ import './chunk-KOXOC2FI.mjs';
4
4
  import './chunk-R5FL6S7L.mjs';
5
- import './chunk-SZDAS7LK.mjs';
5
+ import './chunk-IE2GGHNF.mjs';
6
6
  import './chunk-ICR4CVOE.mjs';
7
- import './chunk-ZTQBUKLJ.mjs';
8
- import './chunk-IHUFOV7L.mjs';
7
+ import './chunk-JJ4FPCBE.mjs';
8
+ import './chunk-CH6SFONH.mjs';
9
9
  import './chunk-73Q7ADVL.mjs';
10
10
  import './chunk-B4NJJZFR.mjs';
11
11
  import './chunk-5UTGXHLJ.mjs';
@@ -1,4 +1,4 @@
1
- import { B as BaseStampCustomData, S as StampType } from './types-C3FjpoUi.mjs';
1
+ import { B as BaseStampCustomData, S as StampType } from './types-tePd94vW.mjs';
2
2
  import 'react';
3
3
  import '@excalidraw/excalidraw/element/types';
4
4
 
@@ -1,4 +1,4 @@
1
- import { B as BaseStampCustomData, S as StampType } from './types-C3FjpoUi.js';
1
+ import { B as BaseStampCustomData, S as StampType } from './types-tePd94vW.js';
2
2
  import 'react';
3
3
  import '@excalidraw/excalidraw/element/types';
4
4
 
@@ -939,8 +939,12 @@ function constraintRefs2D(c) {
939
939
  return [c.line, c.circle, c.other];
940
940
  case "tangencyPoint":
941
941
  return [c.circle, c.onLine];
942
- case "arcMidpoint":
943
- return [c.circle, c.a, c.b, c.notContaining];
942
+ case "arcMidpoint": {
943
+ const containment = c.notContaining ?? c.containing;
944
+ return containment ? [c.circle, c.a, c.b, containment] : [c.circle, c.a, c.b];
945
+ }
946
+ case "mixtilinearPoint":
947
+ return [c.vertices[0], c.vertices[1], c.vertices[2]];
944
948
  case "pointAtDistance": {
945
949
  const d = c.distance;
946
950
  const extra = d.kind === "circleRadius" ? [d.circle] : d.kind === "segmentLength" ? [d.p1, d.p2] : [];
@@ -1227,7 +1231,7 @@ function dist(p, q) {
1227
1231
  function sideOf(a, b, p) {
1228
1232
  return (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]);
1229
1233
  }
1230
- function arcMidpoint(center, radius, a, b, notContaining) {
1234
+ function arcMidpoint(center, radius, a, b, reference, sameSide = false) {
1231
1235
  const mcx = (a[0] + b[0]) / 2;
1232
1236
  const mcy = (a[1] + b[1]) / 2;
1233
1237
  let ux = mcx - center[0];
@@ -1242,12 +1246,18 @@ function arcMidpoint(center, radius, a, b, notContaining) {
1242
1246
  uy /= len;
1243
1247
  const cand1 = [center[0] + radius * ux, center[1] + radius * uy];
1244
1248
  const cand2 = [center[0] - radius * ux, center[1] - radius * uy];
1249
+ if (!reference) return cand1[1] >= cand2[1] ? cand1 : cand2;
1250
+ const notContaining = reference;
1245
1251
  const sN = sideOf(a, b, notContaining);
1246
1252
  if (Math.abs(sN) < 1e-9) {
1247
- return dist(cand1, notContaining) >= dist(cand2, notContaining) ? cand1 : cand2;
1253
+ const far = dist(cand1, notContaining) >= dist(cand2, notContaining) ? cand1 : cand2;
1254
+ const near = far === cand1 ? cand2 : cand1;
1255
+ return sameSide ? near : far;
1248
1256
  }
1249
1257
  const s1 = sideOf(a, b, cand1);
1250
- return s1 * sN < 0 ? cand1 : cand2;
1258
+ const opp = s1 * sN < 0 ? cand1 : cand2;
1259
+ const same = opp === cand1 ? cand2 : cand1;
1260
+ return sameSide ? same : opp;
1251
1261
  }
1252
1262
  function excenter(vertices, oppositeIndex) {
1253
1263
  const [A, B, C] = vertices;
@@ -1263,6 +1273,35 @@ function excenter(vertices, oppositeIndex) {
1263
1273
  (w[0] * A[1] + w[1] * B[1] + w[2] * C[1]) / sum
1264
1274
  ];
1265
1275
  }
1276
+ function circumcenterXY(a, b, c) {
1277
+ const ax = a[0], ay = a[1], bx = b[0], by = b[1], cx = c[0], cy = c[1];
1278
+ const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
1279
+ if (Math.abs(d) < 1e-12) return [(ax + bx + cx) / 3, (ay + by + cy) / 3];
1280
+ const ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
1281
+ const uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
1282
+ return [ux, uy];
1283
+ }
1284
+ function mixtilinearPoint(a, b, c, which) {
1285
+ const O = circumcenterXY(a, b, c);
1286
+ const R = Math.hypot(O[0] - a[0], O[1] - a[1]);
1287
+ const ux1 = (b[0] - a[0]) / (Math.hypot(b[0] - a[0], b[1] - a[1]) || 1);
1288
+ const uy1 = (b[1] - a[1]) / (Math.hypot(b[0] - a[0], b[1] - a[1]) || 1);
1289
+ const ux2 = (c[0] - a[0]) / (Math.hypot(c[0] - a[0], c[1] - a[1]) || 1);
1290
+ const uy2 = (c[1] - a[1]) / (Math.hypot(c[0] - a[0], c[1] - a[1]) || 1);
1291
+ let bx = ux1 + ux2, by = uy1 + uy2;
1292
+ const bl = Math.hypot(bx, by) || 1;
1293
+ bx /= bl;
1294
+ by /= bl;
1295
+ const cosA = ux1 * ux2 + uy1 * uy2;
1296
+ const sinHalf = Math.sqrt(Math.max(0, (1 - cosA) / 2));
1297
+ const cos2Half = Math.max(1e-9, (1 + cosA) / 2);
1298
+ const dotAO = bx * (O[0] - a[0]) + by * (O[1] - a[1]);
1299
+ const d = 2 * (dotAO - R * sinHalf) / cos2Half;
1300
+ const K = [a[0] + d * bx, a[1] + d * by];
1301
+ if (which === "center") return K;
1302
+ const kl = Math.hypot(K[0] - O[0], K[1] - O[1]) || 1;
1303
+ return [O[0] + R * (K[0] - O[0]) / kl, O[1] + R * (K[1] - O[1]) / kl];
1304
+ }
1266
1305
  function pointAtDistanceCoord(from, through, d) {
1267
1306
  const dx = through[0] - from[0];
1268
1307
  const dy = through[1] - from[1];
@@ -1290,29 +1329,38 @@ var init_arcMidpoint = __esm({
1290
1329
  arcMidpointConstraint = definePointConstraint({
1291
1330
  kind: "arcMidpoint",
1292
1331
  validate: (c) => {
1293
- if (!c.circle || !c.a || !c.b || !c.notContaining) {
1294
- throw new Error("point.arcMidpoint: circle, a, b, notContaining b\u1EAFt bu\u1ED9c");
1332
+ if (!c.circle || !c.a || !c.b) {
1333
+ throw new Error("point.arcMidpoint: circle, a, b b\u1EAFt bu\u1ED9c");
1334
+ }
1335
+ if (c.notContaining && c.containing) {
1336
+ throw new Error("point.arcMidpoint: kh\xF4ng th\u1EC3 v\u1EEBa notContaining v\u1EEBa containing");
1295
1337
  }
1296
1338
  },
1297
1339
  describe: (obj, state, c) => {
1298
1340
  const al = state?.objects[c.a]?.label ?? c.a;
1299
1341
  const bl = state?.objects[c.b]?.label ?? c.b;
1300
- const nl = state?.objects[c.notContaining]?.label ?? c.notContaining;
1301
- return `${obj.label} = trung \u0111i\u1EC3m cung ${al}${bl} (kh\xF4ng ch\u1EE9a ${nl})`;
1342
+ const ref = c.containing ?? c.notContaining;
1343
+ if (!ref) return `${obj.label} = trung \u0111i\u1EC3m cung ${al}${bl}`;
1344
+ const rl = state?.objects[ref]?.label ?? ref;
1345
+ const rel = c.containing ? "ch\u1EE9a" : "kh\xF4ng ch\u1EE9a";
1346
+ return `${obj.label} = trung \u0111i\u1EC3m cung ${al}${bl} (${rel} ${rl})`;
1302
1347
  },
1303
1348
  render: (obj, ctx, c, opts) => {
1304
1349
  const board = ctx.jxg;
1305
1350
  const circle = ctx.resolveRef(c.circle);
1306
1351
  const A = ctx.resolveRef(c.a);
1307
1352
  const B = ctx.resolveRef(c.b);
1308
- const N = ctx.resolveRef(c.notContaining);
1353
+ const refName = c.containing ?? c.notContaining;
1354
+ const ref = refName ? ctx.resolveRef(refName) : void 0;
1355
+ const sameSide = !!c.containing;
1309
1356
  const O = circle?.center ?? circle?.midpoint ?? circle;
1310
1357
  const am = () => arcMidpoint(
1311
1358
  [O.X(), O.Y()],
1312
1359
  circle.Radius(),
1313
1360
  [A.X(), A.Y()],
1314
1361
  [B.X(), B.Y()],
1315
- [N.X(), N.Y()]
1362
+ ref ? [ref.X(), ref.Y()] : void 0,
1363
+ sameSide
1316
1364
  );
1317
1365
  return board.create("point", [() => am()[0], () => am()[1]], opts);
1318
1366
  }
@@ -1362,6 +1410,53 @@ var init_excenter = __esm({
1362
1410
  }
1363
1411
  });
1364
1412
 
1413
+ // src/core/scene/kinds/point-constraints/mixtilinearPoint.ts
1414
+ var mixtilinearPointConstraint;
1415
+ var init_mixtilinearPoint = __esm({
1416
+ "src/core/scene/kinds/point-constraints/mixtilinearPoint.ts"() {
1417
+ init_pointConstructions();
1418
+ init_types2();
1419
+ mixtilinearPointConstraint = definePointConstraint({
1420
+ kind: "mixtilinearPoint",
1421
+ validate: (c) => {
1422
+ if (!Array.isArray(c.vertices) || c.vertices.length !== 3 || !c.vertices.every(Boolean)) {
1423
+ throw new Error("point.mixtilinearPoint: vertices ph\u1EA3i l\xE0 tuple 3 id non-empty");
1424
+ }
1425
+ if (c.which !== "center" && c.which !== "touch") {
1426
+ throw new Error("point.mixtilinearPoint: which ph\u1EA3i 'center' | 'touch'");
1427
+ }
1428
+ },
1429
+ describe: (obj, state, c) => {
1430
+ const labels = c.vertices.map((id) => state?.objects[id]?.label ?? id).join("");
1431
+ 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)`;
1432
+ },
1433
+ render: (obj, ctx, c, opts) => {
1434
+ const board = ctx.jxg;
1435
+ const a = ctx.resolveRef(c.vertices[0]);
1436
+ const b = ctx.resolveRef(c.vertices[1]);
1437
+ const d = ctx.resolveRef(c.vertices[2]);
1438
+ const mp = () => mixtilinearPoint(
1439
+ [a.X(), a.Y()],
1440
+ [b.X(), b.Y()],
1441
+ [d.X(), d.Y()],
1442
+ c.which
1443
+ );
1444
+ return board.create("point", [() => mp()[0], () => mp()[1]], opts);
1445
+ }
1446
+ });
1447
+ }
1448
+ });
1449
+
1450
+ // src/core/scene/kinds/_label.ts
1451
+ function labelOpts(labelOffset, dflt) {
1452
+ const offset = labelOffset ?? dflt;
1453
+ return { label: { fixed: false, ...offset ? { offset } : {} } };
1454
+ }
1455
+ var init_label = __esm({
1456
+ "src/core/scene/kinds/_label.ts"() {
1457
+ }
1458
+ });
1459
+
1365
1460
  // src/core/scene/kinds/point-constraints/shared.ts
1366
1461
  function buildJxgTransforms(board, ctx, t) {
1367
1462
  switch (t.kind) {
@@ -1413,11 +1508,13 @@ function buildPointOpts(obj) {
1413
1508
  strokeColor: obj.attrs.color ?? "#1e40af",
1414
1509
  fillColor: obj.attrs.color ?? "#1e40af",
1415
1510
  face: obj.attrs.face ?? "o",
1416
- size: obj.attrs.size ?? 4
1511
+ size: obj.attrs.size ?? 4,
1512
+ ...labelOpts(obj.attrs.labelOffset, [10, 10])
1417
1513
  };
1418
1514
  }
1419
1515
  var init_shared = __esm({
1420
1516
  "src/core/scene/kinds/point-constraints/shared.ts"() {
1517
+ init_label();
1421
1518
  }
1422
1519
  });
1423
1520
 
@@ -1726,6 +1823,7 @@ var init_registry2 = __esm({
1726
1823
  init_centroid();
1727
1824
  init_arcMidpoint();
1728
1825
  init_excenter();
1826
+ init_mixtilinearPoint();
1729
1827
  init_pointAtDistance();
1730
1828
  init_circleIntersection();
1731
1829
  init_circleSecondIntersection();
@@ -1751,6 +1849,7 @@ var init_registry2 = __esm({
1751
1849
  centroidConstraint,
1752
1850
  arcMidpointConstraint,
1753
1851
  excenterConstraint,
1852
+ mixtilinearPointConstraint,
1754
1853
  pointAtDistanceConstraint,
1755
1854
  circleIntersectionConstraint,
1756
1855
  circleSecondIntersectionConstraint,
@@ -1775,6 +1874,7 @@ var init_point = __esm({
1775
1874
  init_d_constraint2();
1776
1875
  init_registry2();
1777
1876
  init_shared();
1877
+ init_label();
1778
1878
  def3 = {
1779
1879
  type: "point",
1780
1880
  schemaVersion: 1,
@@ -1842,7 +1942,8 @@ var init_point = __esm({
1842
1942
  strokeColor: obj.attrs.color ?? "#1e40af",
1843
1943
  fillColor: obj.attrs.color ?? "#1e40af",
1844
1944
  face: obj.attrs.face ?? "o",
1845
- size: obj.attrs.size ?? 4
1945
+ size: obj.attrs.size ?? 4,
1946
+ ...labelOpts(obj.attrs.labelOffset, [10, 10])
1846
1947
  });
1847
1948
  } catch {
1848
1949
  }
@@ -1862,6 +1963,7 @@ var init_segment = __esm({
1862
1963
  "src/core/scene/kinds/segment.ts"() {
1863
1964
  init_registry();
1864
1965
  init_labelOf();
1966
+ init_label();
1865
1967
  def4 = {
1866
1968
  type: "segment",
1867
1969
  schemaVersion: 1,
@@ -1893,7 +1995,8 @@ var init_segment = __esm({
1893
1995
  strokeWidth: obj.attrs.width ?? 2,
1894
1996
  dash: obj.attrs.dash ?? 0,
1895
1997
  visible: obj.visible,
1896
- fixed: obj.locked
1998
+ fixed: obj.locked,
1999
+ ...labelOpts(obj.attrs.labelOffset)
1897
2000
  });
1898
2001
  }
1899
2002
  };
@@ -1930,6 +2033,7 @@ var init_line = __esm({
1930
2033
  "src/core/scene/kinds/line.ts"() {
1931
2034
  init_registry();
1932
2035
  init_labelOf();
2036
+ init_label();
1933
2037
  init_pointConstructions();
1934
2038
  def5 = {
1935
2039
  type: "line",
@@ -1972,7 +2076,8 @@ var init_line = __esm({
1972
2076
  strokeWidth: obj.attrs.width ?? 2,
1973
2077
  dash: obj.attrs.dash ?? 0,
1974
2078
  visible: obj.visible,
1975
- fixed: obj.locked
2079
+ fixed: obj.locked,
2080
+ ...labelOpts(obj.attrs.labelOffset)
1976
2081
  };
1977
2082
  const c = obj.attrs.construction;
1978
2083
  if (!c) {
@@ -2228,6 +2333,7 @@ var init_circle = __esm({
2228
2333
  "src/core/scene/kinds/circle.ts"() {
2229
2334
  init_registry();
2230
2335
  init_labelOf();
2336
+ init_label();
2231
2337
  init_pointConstructions();
2232
2338
  def8 = {
2233
2339
  type: "circle",
@@ -2289,15 +2395,17 @@ var init_circle = __esm({
2289
2395
  const board = ctx.jxg;
2290
2396
  const isCenterLabel = (l) => /^[A-Z]['′]?\d*$/u.test(l);
2291
2397
  const isCenter = isCenterLabel(obj.label);
2398
+ const isRenamedCircle = /_c$/.test(obj.label);
2292
2399
  const baseOpts = {
2293
2400
  name: obj.label,
2294
- withLabel: isCenter ? obj.attrs.showLabel ?? false : true,
2401
+ withLabel: isCenter ? obj.attrs.showLabel ?? false : isRenamedCircle ? false : true,
2295
2402
  strokeColor: obj.attrs.color ?? "#0f172a",
2296
2403
  strokeWidth: obj.attrs.width ?? 2,
2297
2404
  dash: obj.attrs.dash ?? 0,
2298
2405
  fillColor: "none",
2299
2406
  visible: obj.visible,
2300
- fixed: obj.locked
2407
+ fixed: obj.locked,
2408
+ ...labelOpts(obj.attrs.labelOffset)
2301
2409
  };
2302
2410
  const c = asConstruction(obj.attrs);
2303
2411
  if (c?.kind === "circumscribed") {
@@ -2782,8 +2890,11 @@ var init_intersection = __esm({
2782
2890
  const opts = {
2783
2891
  name: obj.label,
2784
2892
  withLabel: true,
2785
- strokeColor: obj.attrs.color ?? "#dc2626",
2786
- fillColor: obj.attrs.color ?? "#dc2626",
2893
+ // Cùng màu xanh với mọi điểm khác (buildPointOpts dùng '#1e40af').
2894
+ // Trước đây điểm giao tô đỏ '#dc2626' → tách biệt thị giác nhưng gây
2895
+ // khó hiểu ("vì sao điểm này khác màu?"). Giữ chung một màu.
2896
+ strokeColor: obj.attrs.color ?? "#1e40af",
2897
+ fillColor: obj.attrs.color ?? "#1e40af",
2787
2898
  visible: obj.visible,
2788
2899
  fixed: obj.locked
2789
2900
  };
@@ -2792,6 +2903,38 @@ var init_intersection = __esm({
2792
2903
  }
2793
2904
  const branch = obj.attrs.branch ?? 0;
2794
2905
  return board.create("intersection", [a, b, branch], opts);
2906
+ },
2907
+ /**
2908
+ * Cập nhật TẠI CHỖ các thuộc tính "trang trí" (tên/màu/ẩn-hiện/khoá) qua
2909
+ * setAttribute — giữ nguyên JxgObj identity nên các object phụ thuộc điểm
2910
+ * giao (đường thẳng qua nó, …) KHÔNG bị stale parent ref. Mô phỏng update
2911
+ * hook của point.ts.
2912
+ *
2913
+ * Nếu định nghĩa hình học đổi (kind/ref1/ref2/branch) thì throw → renderer
2914
+ * fallback remove + create để JSXGraph dựng lại phép giao đúng.
2915
+ */
2916
+ update: (obj, prev, ctx, existing) => {
2917
+ const a = obj.attrs;
2918
+ const p = prev.attrs;
2919
+ const branchA = a.branch;
2920
+ const branchP = p.branch;
2921
+ if (a.kind !== p.kind || a.ref1 !== p.ref1 || a.ref2 !== p.ref2 || branchA !== branchP) {
2922
+ throw new Error("intersection: \u0111\u1ECBnh ngh\u0129a h\xECnh h\u1ECDc \u0111\u1ED5i \u2014 recreate");
2923
+ }
2924
+ const el = existing;
2925
+ if (typeof el.setAttribute === "function") {
2926
+ try {
2927
+ el.setAttribute({
2928
+ name: obj.label,
2929
+ withLabel: true,
2930
+ strokeColor: a.color ?? "#1e40af",
2931
+ fillColor: a.color ?? "#1e40af",
2932
+ visible: obj.visible,
2933
+ fixed: obj.locked
2934
+ });
2935
+ } catch {
2936
+ }
2937
+ }
2795
2938
  }
2796
2939
  };
2797
2940
  registerKind(def12);
@@ -7911,11 +8054,17 @@ async function insertStampImage(api, opts) {
7911
8054
  const elements = api.getSceneElements();
7912
8055
  const editingId = opts.editingElementId ?? null;
7913
8056
  if (editingId) {
8057
+ const old = elements.find((e) => e.id === editingId) ;
8058
+ const oldLongest = old ? Math.max(old.width ?? 0, old.height ?? 0) : 0;
8059
+ const newLongest = Math.max(width, height);
8060
+ const scale3 = oldLongest > 0 && newLongest > 0 ? oldLongest / newLongest : 1;
8061
+ const w = width * scale3;
8062
+ const h = height * scale3;
7914
8063
  const updated = elements.map(
7915
- (e) => e.id === editingId ? { ...e, fileId, customData, width, height } : e
8064
+ (e) => e.id === editingId ? { ...e, fileId, customData, width: w, height: h } : e
7916
8065
  );
7917
8066
  api.updateScene({ elements: updated, appState: clearAppStateAfterInsert() });
7918
- return { fileId, width, height, elementId: editingId };
8067
+ return { fileId, width: w, height: h, elementId: editingId };
7919
8068
  }
7920
8069
  const newElement = buildStampImageElement(
7921
8070
  api,
@@ -8065,7 +8214,8 @@ var init_host = __esm({
8065
8214
  version: 2,
8066
8215
  jsonState
8067
8216
  }),
8068
- editingElementId: editingElement?.id ?? null
8217
+ editingElementId: editingElement?.id ?? null,
8218
+ preserveExistingSize: true
8069
8219
  });
8070
8220
  onClose();
8071
8221
  },