@canvas-harness/core 0.1.6 → 0.1.7
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/index.cjs +117 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +117 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -233,53 +233,6 @@ var rotatePoint = (px, py, cx, cy, cos, sin) => {
|
|
|
233
233
|
return { x: cx + dx * cos - dy * sin, y: cy + dx * sin + dy * cos };
|
|
234
234
|
};
|
|
235
235
|
|
|
236
|
-
// src/edges/auto-route.ts
|
|
237
|
-
var CONTROL_MAX = 200;
|
|
238
|
-
var CONTROL_FRACTION = 0.4;
|
|
239
|
-
var sideOf = (node, localX, localY) => {
|
|
240
|
-
const distLeft = localX;
|
|
241
|
-
const distRight = node.w - localX;
|
|
242
|
-
const distTop = localY;
|
|
243
|
-
const distBottom = node.h - localY;
|
|
244
|
-
const minDist = Math.min(distLeft, distRight, distTop, distBottom);
|
|
245
|
-
if (minDist === distLeft) return "w";
|
|
246
|
-
if (minDist === distRight) return "e";
|
|
247
|
-
if (minDist === distTop) return "n";
|
|
248
|
-
return "s";
|
|
249
|
-
};
|
|
250
|
-
var sideNormalLocal = (side) => {
|
|
251
|
-
switch (side) {
|
|
252
|
-
case "n":
|
|
253
|
-
return { x: 0, y: -1 };
|
|
254
|
-
case "s":
|
|
255
|
-
return { x: 0, y: 1 };
|
|
256
|
-
case "e":
|
|
257
|
-
return { x: 1, y: 0 };
|
|
258
|
-
case "w":
|
|
259
|
-
return { x: -1, y: 0 };
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
var rotateVecByAngle = (v, angle) => {
|
|
263
|
-
if (angle === 0) return v;
|
|
264
|
-
const cos = Math.cos(angle);
|
|
265
|
-
const sin = Math.sin(angle);
|
|
266
|
-
return { x: v.x * cos - v.y * sin, y: v.x * sin + v.y * cos };
|
|
267
|
-
};
|
|
268
|
-
var autoRouteControls = (sourceWorld, targetWorld, sourceNormalWorld, targetNormalWorld) => {
|
|
269
|
-
const dx = targetWorld.x - sourceWorld.x;
|
|
270
|
-
const dy = targetWorld.y - sourceWorld.y;
|
|
271
|
-
const dist = Math.hypot(dx, dy);
|
|
272
|
-
const offset = Math.min(CONTROL_MAX, CONTROL_FRACTION * dist);
|
|
273
|
-
const fallbackSource = dist > 0 ? { x: dx / dist, y: dy / dist } : { x: 1, y: 0 };
|
|
274
|
-
const fallbackTarget = dist > 0 ? { x: -dx / dist, y: -dy / dist } : { x: -1, y: 0 };
|
|
275
|
-
const ns = sourceNormalWorld ?? fallbackSource;
|
|
276
|
-
const nt = targetNormalWorld ?? fallbackTarget;
|
|
277
|
-
return {
|
|
278
|
-
c1: { x: sourceWorld.x + ns.x * offset, y: sourceWorld.y + ns.y * offset },
|
|
279
|
-
c2: { x: targetWorld.x + nt.x * offset, y: targetWorld.y + nt.y * offset }
|
|
280
|
-
};
|
|
281
|
-
};
|
|
282
|
-
|
|
283
236
|
// src/edges/project.ts
|
|
284
237
|
var projectEndToWorld = (end, getNode) => {
|
|
285
238
|
if (!isAttached(end)) return end.worldPoint;
|
|
@@ -328,6 +281,112 @@ var projectToNodeBoundary = (world, node) => {
|
|
|
328
281
|
return { x: clampedX, y: node.h };
|
|
329
282
|
};
|
|
330
283
|
|
|
284
|
+
// src/edges/auto-route.ts
|
|
285
|
+
var CONTROL_MAX = 200;
|
|
286
|
+
var CONTROL_FRACTION = 0.4;
|
|
287
|
+
var BOUNDARY_EPS = 0.5;
|
|
288
|
+
var isLocalOffsetInsideBody = (localOffset, node) => {
|
|
289
|
+
const onLeft = Math.abs(localOffset.x) <= BOUNDARY_EPS;
|
|
290
|
+
const onRight = Math.abs(localOffset.x - node.w) <= BOUNDARY_EPS;
|
|
291
|
+
const onTop = Math.abs(localOffset.y) <= BOUNDARY_EPS;
|
|
292
|
+
const onBottom = Math.abs(localOffset.y - node.h) <= BOUNDARY_EPS;
|
|
293
|
+
const inside = localOffset.x > -BOUNDARY_EPS && localOffset.x < node.w + BOUNDARY_EPS && localOffset.y > -BOUNDARY_EPS && localOffset.y < node.h + BOUNDARY_EPS;
|
|
294
|
+
return inside && !onLeft && !onRight && !onTop && !onBottom;
|
|
295
|
+
};
|
|
296
|
+
var sideOf = (node, localX, localY) => {
|
|
297
|
+
const distLeft = localX;
|
|
298
|
+
const distRight = node.w - localX;
|
|
299
|
+
const distTop = localY;
|
|
300
|
+
const distBottom = node.h - localY;
|
|
301
|
+
const minDist = Math.min(distLeft, distRight, distTop, distBottom);
|
|
302
|
+
if (minDist === distLeft) return "w";
|
|
303
|
+
if (minDist === distRight) return "e";
|
|
304
|
+
if (minDist === distTop) return "n";
|
|
305
|
+
return "s";
|
|
306
|
+
};
|
|
307
|
+
var sideNormalLocal = (side) => {
|
|
308
|
+
switch (side) {
|
|
309
|
+
case "n":
|
|
310
|
+
return { x: 0, y: -1 };
|
|
311
|
+
case "s":
|
|
312
|
+
return { x: 0, y: 1 };
|
|
313
|
+
case "e":
|
|
314
|
+
return { x: 1, y: 0 };
|
|
315
|
+
case "w":
|
|
316
|
+
return { x: -1, y: 0 };
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
var rotateVecByAngle = (v, angle) => {
|
|
320
|
+
if (angle === 0) return v;
|
|
321
|
+
const cos = Math.cos(angle);
|
|
322
|
+
const sin = Math.sin(angle);
|
|
323
|
+
return { x: v.x * cos - v.y * sin, y: v.x * sin + v.y * cos };
|
|
324
|
+
};
|
|
325
|
+
var autoRouteControls = (sourceWorld, targetWorld, sourceNormalWorld, targetNormalWorld) => {
|
|
326
|
+
const dx = targetWorld.x - sourceWorld.x;
|
|
327
|
+
const dy = targetWorld.y - sourceWorld.y;
|
|
328
|
+
const dist = Math.hypot(dx, dy);
|
|
329
|
+
const offset = Math.min(CONTROL_MAX, CONTROL_FRACTION * dist);
|
|
330
|
+
const fallbackSource = dist > 0 ? { x: dx / dist, y: dy / dist } : { x: 1, y: 0 };
|
|
331
|
+
const fallbackTarget = dist > 0 ? { x: -dx / dist, y: -dy / dist } : { x: -1, y: 0 };
|
|
332
|
+
const ns = sourceNormalWorld ?? fallbackSource;
|
|
333
|
+
const nt = targetNormalWorld ?? fallbackTarget;
|
|
334
|
+
return {
|
|
335
|
+
c1: { x: sourceWorld.x + ns.x * offset, y: sourceWorld.y + ns.y * offset },
|
|
336
|
+
c2: { x: targetWorld.x + nt.x * offset, y: targetWorld.y + nt.y * offset }
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
var computeAsymmetricRoute = (sourceNode, targetNode) => {
|
|
340
|
+
const srcCenterWorld = {
|
|
341
|
+
x: sourceNode.x + sourceNode.w / 2,
|
|
342
|
+
y: sourceNode.y + sourceNode.h / 2
|
|
343
|
+
};
|
|
344
|
+
const srcInTgtLocal = worldToNodeLocal(srcCenterWorld, targetNode);
|
|
345
|
+
const tgtHalfW = targetNode.w / 2;
|
|
346
|
+
const tgtHalfH = targetNode.h / 2;
|
|
347
|
+
const dxNorm = (srcInTgtLocal.x - tgtHalfW) / Math.max(1, tgtHalfW);
|
|
348
|
+
const dyNorm = (srcInTgtLocal.y - tgtHalfH) / Math.max(1, tgtHalfH);
|
|
349
|
+
const targetSide = Math.abs(dxNorm) >= Math.abs(dyNorm) ? dxNorm > 0 ? "e" : "w" : dyNorm > 0 ? "s" : "n";
|
|
350
|
+
let tgtEntryLocal;
|
|
351
|
+
if (targetSide === "n" || targetSide === "s") {
|
|
352
|
+
const sideY = targetSide === "n" ? 0 : targetNode.h;
|
|
353
|
+
const clampX = Math.max(0, Math.min(targetNode.w, srcInTgtLocal.x));
|
|
354
|
+
tgtEntryLocal = { x: clampX, y: sideY };
|
|
355
|
+
} else {
|
|
356
|
+
const sideX = targetSide === "w" ? 0 : targetNode.w;
|
|
357
|
+
const clampY = Math.max(0, Math.min(targetNode.h, srcInTgtLocal.y));
|
|
358
|
+
tgtEntryLocal = { x: sideX, y: clampY };
|
|
359
|
+
}
|
|
360
|
+
const targetEntryWorld = nodeLocalToWorld(tgtEntryLocal, targetNode);
|
|
361
|
+
const tgtEntryInSrcLocal = worldToNodeLocal(targetEntryWorld, sourceNode);
|
|
362
|
+
const srcHalfW = sourceNode.w / 2;
|
|
363
|
+
const srcHalfH = sourceNode.h / 2;
|
|
364
|
+
const rayDx = tgtEntryInSrcLocal.x - srcHalfW;
|
|
365
|
+
const rayDy = tgtEntryInSrcLocal.y - srcHalfH;
|
|
366
|
+
const tx = rayDx === 0 ? Number.POSITIVE_INFINITY : (rayDx > 0 ? srcHalfW : -srcHalfW) / rayDx;
|
|
367
|
+
const ty = rayDy === 0 ? Number.POSITIVE_INFINITY : (rayDy > 0 ? srcHalfH : -srcHalfH) / rayDy;
|
|
368
|
+
const t = Math.min(tx, ty);
|
|
369
|
+
const srcExitLocal = {
|
|
370
|
+
x: srcHalfW + rayDx * t,
|
|
371
|
+
y: srcHalfH + rayDy * t
|
|
372
|
+
};
|
|
373
|
+
const sourceExitWorld = nodeLocalToWorld(srcExitLocal, sourceNode);
|
|
374
|
+
const dxWorld = targetEntryWorld.x - sourceExitWorld.x;
|
|
375
|
+
const dyWorld = targetEntryWorld.y - sourceExitWorld.y;
|
|
376
|
+
const distance2 = Math.hypot(dxWorld, dyWorld);
|
|
377
|
+
const offset = Math.min(CONTROL_MAX, CONTROL_FRACTION * distance2);
|
|
378
|
+
const c1 = distance2 > 0 ? {
|
|
379
|
+
x: sourceExitWorld.x + dxWorld / distance2 * offset,
|
|
380
|
+
y: sourceExitWorld.y + dyWorld / distance2 * offset
|
|
381
|
+
} : { ...sourceExitWorld };
|
|
382
|
+
const tgtNormalWorld = rotateVecByAngle(sideNormalLocal(targetSide), targetNode.angle);
|
|
383
|
+
const c2 = {
|
|
384
|
+
x: targetEntryWorld.x + tgtNormalWorld.x * offset,
|
|
385
|
+
y: targetEntryWorld.y + tgtNormalWorld.y * offset
|
|
386
|
+
};
|
|
387
|
+
return { source: sourceExitWorld, target: targetEntryWorld, c1, c2 };
|
|
388
|
+
};
|
|
389
|
+
|
|
331
390
|
// src/edges/clip.ts
|
|
332
391
|
var fullVisibleClipResult = (samples) => ({
|
|
333
392
|
startIndex: 0,
|
|
@@ -588,8 +647,8 @@ var computeEdgeGeometry = (edge, getNode) => {
|
|
|
588
647
|
targetNodeId
|
|
589
648
|
};
|
|
590
649
|
}
|
|
591
|
-
|
|
592
|
-
|
|
650
|
+
let sourceWorld = projectEndToWorld(edge.source, getNode);
|
|
651
|
+
let targetWorld = projectEndToWorld(edge.target, getNode);
|
|
593
652
|
if (!sourceWorld || !targetWorld) return null;
|
|
594
653
|
let samples;
|
|
595
654
|
if (edge.pathStyle === "bezier") {
|
|
@@ -598,6 +657,12 @@ var computeEdgeGeometry = (edge, getNode) => {
|
|
|
598
657
|
if (edge.control && edge.control.length >= 2) {
|
|
599
658
|
c1 = edge.control[0];
|
|
600
659
|
c2 = edge.control[1];
|
|
660
|
+
} else if (sourceNode && targetNode && isAttached(edge.source) && isAttached(edge.target) && isLocalOffsetInsideBody(edge.source.localOffset, sourceNode) && isLocalOffsetInsideBody(edge.target.localOffset, targetNode)) {
|
|
661
|
+
const r = computeAsymmetricRoute(sourceNode, targetNode);
|
|
662
|
+
sourceWorld = r.source;
|
|
663
|
+
targetWorld = r.target;
|
|
664
|
+
c1 = r.c1;
|
|
665
|
+
c2 = r.c2;
|
|
601
666
|
} else {
|
|
602
667
|
const sourceNormal = sourceNode && isAttached(edge.source) ? rotateVecByAngle(
|
|
603
668
|
sideNormalLocal(
|
|
@@ -1607,7 +1672,7 @@ var buildPath = (type, x, y, w, h, radius) => {
|
|
|
1607
1672
|
};
|
|
1608
1673
|
|
|
1609
1674
|
// src/text/tokens.ts
|
|
1610
|
-
var INLINE_PATTERN = /(
|
|
1675
|
+
var INLINE_PATTERN = /(\$\$[^\n]+?\$\$|\*\*[^*]+\*\*|==[^=\s](?:[^=]*?[^=\s])?==|`[^`]+`|\*[^*]+\*|__[^_]+__|~~[^~]+~~|_[^_]+_|\[[^\]]+\]\([^)]+\))/g;
|
|
1611
1676
|
var HR_LINE_PATTERN = /^[ \t]*---[ \t]*$/;
|
|
1612
1677
|
var DOUBLE_HR_LINE_PATTERN = /^[ \t]*===[ \t]*$/;
|
|
1613
1678
|
var transformSymbols = (value) => value.replace(/<=>|<->|<-|->|\[\]|\[[vx]\]/gi, (match) => {
|
|
@@ -1645,8 +1710,8 @@ var tokenizeInline = (segment) => {
|
|
|
1645
1710
|
tokens.push({ type: "link", content: transformSymbols(match.slice(1, splitIndex)) });
|
|
1646
1711
|
} else if (match.startsWith("`") && match.endsWith("`")) {
|
|
1647
1712
|
tokens.push({ type: "code", content: match.slice(1, -1) });
|
|
1648
|
-
} else if (match.startsWith("
|
|
1649
|
-
tokens.push({ type: "math", content: match.slice(
|
|
1713
|
+
} else if (match.startsWith("$$") && match.endsWith("$$")) {
|
|
1714
|
+
tokens.push({ type: "math", content: match.slice(2, -2) });
|
|
1650
1715
|
} else {
|
|
1651
1716
|
tokens.push({ type: "text", content: transformSymbols(match) });
|
|
1652
1717
|
}
|