@canvas-harness/core 0.1.4 → 0.1.6
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 +211 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +211 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1050,7 +1050,6 @@ var COMPOSITE = /* @__PURE__ */ new Set([
|
|
|
1050
1050
|
var isCompositePrimitive = (type) => COMPOSITE.has(type);
|
|
1051
1051
|
var isDrawablePrimitive = (type) => ATOMIC.has(type) || COMPOSITE.has(type);
|
|
1052
1052
|
var PLAIN_RECT_CORNER_THRESHOLD_PX = 1.5;
|
|
1053
|
-
var STROKE_VISIBILITY_THRESHOLD_PX = 0.5;
|
|
1054
1053
|
var LAYERED_OFFSET = 12;
|
|
1055
1054
|
var drawShape = (ctx, node, scale, theme, opts) => {
|
|
1056
1055
|
if (!isDrawablePrimitive(node.type)) return;
|
|
@@ -1069,7 +1068,7 @@ var drawAtomic = (ctx, type, w, h, style, scale, theme, opts) => {
|
|
|
1069
1068
|
const fill = resolveColor(style, "backgroundColor", DEFAULT_STYLE.backgroundColor, theme);
|
|
1070
1069
|
const stroke = resolveColor(style, "strokeColor", DEFAULT_STYLE.strokeColor, theme);
|
|
1071
1070
|
const fillVisible = !isFullyTransparent(fill);
|
|
1072
|
-
const strokeVisible = strokeWidth > 0 &&
|
|
1071
|
+
const strokeVisible = strokeWidth > 0 && !isFullyTransparent(stroke);
|
|
1073
1072
|
if (!fillVisible && !strokeVisible) return;
|
|
1074
1073
|
const cornerRadius = (style?.roundness ?? DEFAULT_STYLE.roundness) * 4;
|
|
1075
1074
|
switch (type) {
|
|
@@ -1106,7 +1105,7 @@ var drawAtomic = (ctx, type, w, h, style, scale, theme, opts) => {
|
|
|
1106
1105
|
}
|
|
1107
1106
|
if (strokeVisible && !opts?.skipStroke) {
|
|
1108
1107
|
ctx.strokeStyle = stroke;
|
|
1109
|
-
ctx.lineWidth = strokeWidth;
|
|
1108
|
+
ctx.lineWidth = Math.max(strokeWidth, 1 / scale);
|
|
1110
1109
|
ctx.setLineDash(dashPatternFor(style?.strokeStyle, strokeWidth));
|
|
1111
1110
|
ctx.stroke();
|
|
1112
1111
|
}
|
|
@@ -1482,13 +1481,16 @@ var paintAtomicRough = (rc, ctx, type, w, h, style, scale, theme, seed) => {
|
|
|
1482
1481
|
const isDark = theme?.("mode") === "dark";
|
|
1483
1482
|
const fill = resolveColor(style, "backgroundColor", DEFAULT_STYLE.backgroundColor, theme);
|
|
1484
1483
|
const strokeColor = deriveRoughStrokeColor(rawStroke, fill, isDark);
|
|
1485
|
-
const
|
|
1486
|
-
if (
|
|
1484
|
+
const rawStrokeWidth = resolveStrokeWidth(style, theme);
|
|
1485
|
+
if (rawStrokeWidth <= 0) return;
|
|
1487
1486
|
const roughness = style?.roughness ?? 0;
|
|
1488
1487
|
if (roughness <= 0) return;
|
|
1488
|
+
const isNoBorderIntent = isFullyTransparent(rawStroke);
|
|
1489
|
+
const effectiveStrokeStyle = isNoBorderIntent ? "solid" : style?.strokeStyle ?? "solid";
|
|
1490
|
+
const strokeWidth = isNoBorderIntent ? DEFAULT_STYLE.strokeWidth : rawStrokeWidth;
|
|
1489
1491
|
const cornerRadius = (style?.roundness ?? DEFAULT_STYLE.roundness) * 4;
|
|
1490
1492
|
const radius = Math.max(0, Math.min(cornerRadius, w / 2, h / 2));
|
|
1491
|
-
const dash = dashPatternFor(
|
|
1493
|
+
const dash = dashPatternFor(effectiveStrokeStyle, strokeWidth);
|
|
1492
1494
|
const detail = apparentDetail(Math.max(w, h), scale);
|
|
1493
1495
|
const cacheKey = [
|
|
1494
1496
|
type,
|
|
@@ -1497,7 +1499,7 @@ var paintAtomicRough = (rc, ctx, type, w, h, style, scale, theme, seed) => {
|
|
|
1497
1499
|
radius.toFixed(1),
|
|
1498
1500
|
strokeColor,
|
|
1499
1501
|
strokeWidth.toFixed(2),
|
|
1500
|
-
|
|
1502
|
+
effectiveStrokeStyle,
|
|
1501
1503
|
roughness.toFixed(2),
|
|
1502
1504
|
seed,
|
|
1503
1505
|
detail.curveStepCount,
|
|
@@ -2648,7 +2650,7 @@ var DEFAULT_EDGE_STYLE = {
|
|
|
2648
2650
|
sourceArrowhead: "none",
|
|
2649
2651
|
targetArrowhead: "arrow-filled"
|
|
2650
2652
|
};
|
|
2651
|
-
var
|
|
2653
|
+
var STROKE_VISIBILITY_THRESHOLD_PX = 0.5;
|
|
2652
2654
|
var ARROWHEAD_VISIBILITY_THRESHOLD_PX = 2;
|
|
2653
2655
|
var samplePaintStride = (scale) => {
|
|
2654
2656
|
if (scale < 0.15) return 8;
|
|
@@ -2662,7 +2664,7 @@ var drawEdge = (ctx, edge, geom, sourceNode, targetNode, scale, theme, opts) =>
|
|
|
2662
2664
|
if (samples.length < 2) return;
|
|
2663
2665
|
const style = edge.style;
|
|
2664
2666
|
const strokeWidth = typeof style?.strokeWidth === "number" ? style.strokeWidth : theme?.("strokeWidth") ?? DEFAULT_EDGE_STYLE.strokeWidth;
|
|
2665
|
-
if (strokeWidth * scale <
|
|
2667
|
+
if (strokeWidth * scale < STROKE_VISIBILITY_THRESHOLD_PX) return;
|
|
2666
2668
|
const strokeColor = typeof style?.strokeColor === "string" ? style.strokeColor : theme?.("edge.strokeColor") ?? DEFAULT_EDGE_STYLE.strokeColor;
|
|
2667
2669
|
const sourceArrowhead = style?.sourceArrowhead ?? DEFAULT_EDGE_STYLE.sourceArrowhead;
|
|
2668
2670
|
const targetArrowhead = style?.targetArrowhead ?? DEFAULT_EDGE_STYLE.targetArrowhead;
|
|
@@ -3378,6 +3380,8 @@ var idleInteractionState = () => ({
|
|
|
3378
3380
|
resizeHandle: null,
|
|
3379
3381
|
resizeLockAspect: false,
|
|
3380
3382
|
resizeFromCenter: false,
|
|
3383
|
+
resizeDraft: null,
|
|
3384
|
+
midpointDraft: null,
|
|
3381
3385
|
marqueeRect: null,
|
|
3382
3386
|
marqueeAdditive: false,
|
|
3383
3387
|
draftEdge: null,
|
|
@@ -4886,7 +4890,7 @@ var drawWithNodeTransform = (ctx, node, fn) => {
|
|
|
4886
4890
|
};
|
|
4887
4891
|
|
|
4888
4892
|
// src/render/renderer.ts
|
|
4889
|
-
var
|
|
4893
|
+
var SCENE_CACHE_MARGIN_PX = 256;
|
|
4890
4894
|
var MIN_ON_SCREEN_SIZE_PX = 1.5;
|
|
4891
4895
|
var MIN_READABLE_FONT_PX = 3;
|
|
4892
4896
|
var createRenderer = (opts) => {
|
|
@@ -4903,6 +4907,30 @@ var createRenderer = (opts) => {
|
|
|
4903
4907
|
let interactiveDirty = false;
|
|
4904
4908
|
let overlaySet = /* @__PURE__ */ new Set();
|
|
4905
4909
|
let lastDrawn = 0;
|
|
4910
|
+
let cacheSurface = null;
|
|
4911
|
+
let cacheCamX = 0;
|
|
4912
|
+
let cacheCamY = 0;
|
|
4913
|
+
let cacheCamZ = 1;
|
|
4914
|
+
let cacheStale = true;
|
|
4915
|
+
const ensureCacheSurface = () => {
|
|
4916
|
+
const dpr = staticSurface.dpr;
|
|
4917
|
+
const cssW = staticSurface.cssWidth + 2 * SCENE_CACHE_MARGIN_PX;
|
|
4918
|
+
const cssH = staticSurface.cssHeight + 2 * SCENE_CACHE_MARGIN_PX;
|
|
4919
|
+
if (!cacheSurface) {
|
|
4920
|
+
const canvas = document.createElement("canvas");
|
|
4921
|
+
const ctx = canvas.getContext("2d");
|
|
4922
|
+
if (!ctx) throw new Error("Canvas 2d context unavailable");
|
|
4923
|
+
cacheSurface = { canvas, ctx, cssWidth: 0, cssHeight: 0, dpr: 1 };
|
|
4924
|
+
}
|
|
4925
|
+
if (cacheSurface.cssWidth !== cssW || cacheSurface.cssHeight !== cssH || cacheSurface.dpr !== dpr) {
|
|
4926
|
+
cacheSurface.cssWidth = cssW;
|
|
4927
|
+
cacheSurface.cssHeight = cssH;
|
|
4928
|
+
cacheSurface.dpr = dpr;
|
|
4929
|
+
cacheSurface.canvas.width = Math.max(1, Math.round(cssW * dpr));
|
|
4930
|
+
cacheSurface.canvas.height = Math.max(1, Math.round(cssH * dpr));
|
|
4931
|
+
}
|
|
4932
|
+
return cacheSurface;
|
|
4933
|
+
};
|
|
4906
4934
|
let sortedNodeIdsCache = null;
|
|
4907
4935
|
let sortedEdgeIdsCache = null;
|
|
4908
4936
|
const invalidateSortedCaches = () => {
|
|
@@ -4911,6 +4939,7 @@ var createRenderer = (opts) => {
|
|
|
4911
4939
|
};
|
|
4912
4940
|
const requestRepaint = () => {
|
|
4913
4941
|
staticDirty = true;
|
|
4942
|
+
cacheStale = true;
|
|
4914
4943
|
loop.requestFrame();
|
|
4915
4944
|
};
|
|
4916
4945
|
const assetCache = createAssetCache({ onReady: requestRepaint });
|
|
@@ -4925,16 +4954,14 @@ var createRenderer = (opts) => {
|
|
|
4925
4954
|
interactiveDirty = false;
|
|
4926
4955
|
}
|
|
4927
4956
|
};
|
|
4928
|
-
const
|
|
4929
|
-
const
|
|
4930
|
-
clearSurface(staticSurface);
|
|
4931
|
-
applyCameraTransform(staticSurface, camera);
|
|
4932
|
-
const scale = camera.z * staticSurface.dpr;
|
|
4957
|
+
const paintSceneBody = (surface, camera, viewport, fullRender = true) => {
|
|
4958
|
+
const scale = camera.z * surface.dpr;
|
|
4933
4959
|
const interaction = store.getInteractionState();
|
|
4934
4960
|
const excludedNodes = interaction.mode === "dragging" || interaction.mode === "resizing" ? new Set(interaction.draggedIds) : null;
|
|
4935
|
-
const
|
|
4936
|
-
const
|
|
4937
|
-
|
|
4961
|
+
const baseExcludedEdges = excludedNodes ? incidentEdgeIds(excludedNodes) : null;
|
|
4962
|
+
const midpointEdgeId = interaction.midpointDraft?.edgeId ?? null;
|
|
4963
|
+
const excludedEdges = midpointEdgeId !== null ? /* @__PURE__ */ new Set([...baseExcludedEdges ?? [], midpointEdgeId]) : baseExcludedEdges;
|
|
4964
|
+
paintBackground(surface.ctx, { viewport, zoom: camera.z, background });
|
|
4938
4965
|
const visible = visibleNodes(camera, viewport);
|
|
4939
4966
|
const isMoving2 = interaction.mode === "panning" || interaction.mode === "zooming" || interaction.mode === "dragging" || interaction.mode === "resizing" || interaction.mode === "rotating";
|
|
4940
4967
|
const minOnScreen = MIN_ON_SCREEN_SIZE_PX;
|
|
@@ -4956,8 +4983,8 @@ var createRenderer = (opts) => {
|
|
|
4956
4983
|
for (const node of visible) {
|
|
4957
4984
|
if (node.type !== "frame") continue;
|
|
4958
4985
|
if (excludedNodes?.has(node.id)) continue;
|
|
4959
|
-
drawWithNodeTransform(
|
|
4960
|
-
paintFrameNode(
|
|
4986
|
+
drawWithNodeTransform(surface.ctx, node, () => {
|
|
4987
|
+
paintFrameNode(surface.ctx, node, scale, theme);
|
|
4961
4988
|
});
|
|
4962
4989
|
drawn++;
|
|
4963
4990
|
}
|
|
@@ -4970,52 +4997,53 @@ var createRenderer = (opts) => {
|
|
|
4970
4997
|
const useRough = roughEnabled && (node.style?.roughness ?? 0) > 0;
|
|
4971
4998
|
const roughReady = useRough ? getRoughCanvasCtor() !== null : false;
|
|
4972
4999
|
const composite = isCompositePrimitive(node.type);
|
|
4973
|
-
drawWithNodeTransform(
|
|
5000
|
+
drawWithNodeTransform(surface.ctx, node, () => {
|
|
4974
5001
|
if (useRough && roughReady) {
|
|
4975
5002
|
if (composite) {
|
|
4976
|
-
drawCompositeRough(
|
|
5003
|
+
drawCompositeRough(surface.ctx, node, camera.z, theme);
|
|
4977
5004
|
} else {
|
|
4978
|
-
|
|
4979
|
-
drawShape(
|
|
4980
|
-
|
|
4981
|
-
drawRoughShape(
|
|
5005
|
+
surface.ctx.translate(ROUGH_FILL_MISREGISTER_X, ROUGH_FILL_MISREGISTER_Y);
|
|
5006
|
+
drawShape(surface.ctx, node, scale, theme, { skipStroke: true });
|
|
5007
|
+
surface.ctx.translate(-ROUGH_FILL_MISREGISTER_X, -ROUGH_FILL_MISREGISTER_Y);
|
|
5008
|
+
drawRoughShape(surface.ctx, node, camera.z, theme);
|
|
4982
5009
|
}
|
|
4983
5010
|
} else {
|
|
4984
|
-
drawShape(
|
|
5011
|
+
drawShape(surface.ctx, node, scale, theme);
|
|
4985
5012
|
if (useRough && !roughReady) {
|
|
4986
5013
|
onRoughReady(() => {
|
|
4987
5014
|
staticDirty = true;
|
|
5015
|
+
cacheStale = true;
|
|
4988
5016
|
loop.requestFrame();
|
|
4989
5017
|
});
|
|
4990
5018
|
}
|
|
4991
5019
|
}
|
|
4992
|
-
if (!isEditingThis) paintNodeContent(
|
|
5020
|
+
if (!isEditingThis) paintNodeContent(surface.ctx, node, renderEnv);
|
|
4993
5021
|
});
|
|
4994
5022
|
drawn++;
|
|
4995
5023
|
continue;
|
|
4996
5024
|
}
|
|
4997
5025
|
if (node.type === "image") {
|
|
4998
|
-
drawWithNodeTransform(
|
|
4999
|
-
paintImageNode(
|
|
5026
|
+
drawWithNodeTransform(surface.ctx, node, () => {
|
|
5027
|
+
paintImageNode(surface.ctx, node, assetCache, theme);
|
|
5000
5028
|
});
|
|
5001
5029
|
drawn++;
|
|
5002
5030
|
continue;
|
|
5003
5031
|
}
|
|
5004
5032
|
if (node.type === "icon") {
|
|
5005
|
-
drawWithNodeTransform(
|
|
5006
|
-
paintIconNode(
|
|
5033
|
+
drawWithNodeTransform(surface.ctx, node, () => {
|
|
5034
|
+
paintIconNode(surface.ctx, node, assetCache, scale, theme);
|
|
5007
5035
|
});
|
|
5008
5036
|
drawn++;
|
|
5009
5037
|
continue;
|
|
5010
5038
|
}
|
|
5011
5039
|
if (node.type === "text") {
|
|
5012
|
-
drawWithNodeTransform(
|
|
5040
|
+
drawWithNodeTransform(surface.ctx, node, () => {
|
|
5013
5041
|
if (isEditingThis) return;
|
|
5014
5042
|
const hasContent = node.content && node.content.trim().length > 0;
|
|
5015
5043
|
if (hasContent) {
|
|
5016
|
-
paintNodeContent(
|
|
5044
|
+
paintNodeContent(surface.ctx, node, renderEnv);
|
|
5017
5045
|
} else {
|
|
5018
|
-
paintEmptyTextPlaceholder(
|
|
5046
|
+
paintEmptyTextPlaceholder(surface.ctx, node, camera.z);
|
|
5019
5047
|
}
|
|
5020
5048
|
});
|
|
5021
5049
|
drawn++;
|
|
@@ -5027,7 +5055,7 @@ var createRenderer = (opts) => {
|
|
|
5027
5055
|
if (camera.z < def.lod.minZoomForPlaceholder) continue;
|
|
5028
5056
|
const preferCanvas = camera.z < def.lod.minZoomForReact || isMoving2;
|
|
5029
5057
|
if (preferCanvas) {
|
|
5030
|
-
if (paintCustomCanvasFallback(
|
|
5058
|
+
if (paintCustomCanvasFallback(surface.ctx, node, def, scale, renderEnv)) {
|
|
5031
5059
|
drawn++;
|
|
5032
5060
|
}
|
|
5033
5061
|
continue;
|
|
@@ -5037,10 +5065,10 @@ var createRenderer = (opts) => {
|
|
|
5037
5065
|
continue;
|
|
5038
5066
|
}
|
|
5039
5067
|
if (def.renderCanvas) {
|
|
5040
|
-
drawWithNodeTransform(
|
|
5041
|
-
|
|
5042
|
-
def.renderCanvas(
|
|
5043
|
-
|
|
5068
|
+
drawWithNodeTransform(surface.ctx, node, () => {
|
|
5069
|
+
surface.ctx.save();
|
|
5070
|
+
def.renderCanvas(surface.ctx, node, renderEnv);
|
|
5071
|
+
surface.ctx.restore();
|
|
5044
5072
|
});
|
|
5045
5073
|
drawn++;
|
|
5046
5074
|
}
|
|
@@ -5049,15 +5077,120 @@ var createRenderer = (opts) => {
|
|
|
5049
5077
|
const edgeRoughEnabled = !cameraIsMoving && movingNodeCount <= ROUGH_MAX_MOVING_NODES && camera.z >= ROUGH_MIN_ZOOM && visEdges.length <= ROUGH_MAX_NODES;
|
|
5050
5078
|
for (const edge of visEdges) {
|
|
5051
5079
|
if (excludedEdges?.has(edge.id)) continue;
|
|
5052
|
-
paintOneEdge(
|
|
5080
|
+
paintOneEdge(surface.ctx, edge, scale, edgeRoughEnabled, camera.z, isMoving2);
|
|
5053
5081
|
drawn++;
|
|
5054
5082
|
}
|
|
5083
|
+
if (!fullRender) return;
|
|
5055
5084
|
lastDrawn = drawn;
|
|
5056
5085
|
if (!setsEqual(nextOverlaySet, overlaySet)) {
|
|
5057
5086
|
overlaySet = nextOverlaySet;
|
|
5058
5087
|
onOverlayChange?.([...overlaySet]);
|
|
5059
5088
|
}
|
|
5060
5089
|
};
|
|
5090
|
+
const applyCacheTransform = (cache5, centerX, centerY, z) => {
|
|
5091
|
+
const s = z * cache5.dpr;
|
|
5092
|
+
const m = SCENE_CACHE_MARGIN_PX * cache5.dpr;
|
|
5093
|
+
cache5.ctx.setTransform(s, 0, 0, s, -centerX * s + m, -centerY * s + m);
|
|
5094
|
+
};
|
|
5095
|
+
const renderFullCache = (camera) => {
|
|
5096
|
+
const cache5 = ensureCacheSurface();
|
|
5097
|
+
clearSurface(cache5);
|
|
5098
|
+
applyCacheTransform(cache5, camera.x, camera.y, camera.z);
|
|
5099
|
+
const marginWorld = SCENE_CACHE_MARGIN_PX / camera.z;
|
|
5100
|
+
const viewport = inflateRect(worldViewport(staticSurface, camera), marginWorld);
|
|
5101
|
+
paintSceneBody(cache5, camera, viewport);
|
|
5102
|
+
cacheCamX = camera.x;
|
|
5103
|
+
cacheCamY = camera.y;
|
|
5104
|
+
cacheCamZ = camera.z;
|
|
5105
|
+
cacheStale = false;
|
|
5106
|
+
};
|
|
5107
|
+
const canExtend = (camera) => {
|
|
5108
|
+
if (!cacheSurface) return false;
|
|
5109
|
+
const s = camera.z * staticSurface.dpr;
|
|
5110
|
+
const dx = Math.abs((cacheCamX - camera.x) * s);
|
|
5111
|
+
const dy = Math.abs((cacheCamY - camera.y) * s);
|
|
5112
|
+
return dx < cacheSurface.canvas.width && dy < cacheSurface.canvas.height;
|
|
5113
|
+
};
|
|
5114
|
+
const renderCacheStrip = (cache5, centerX, centerY, z, px, py, pw, ph) => {
|
|
5115
|
+
const ctx = cache5.ctx;
|
|
5116
|
+
const s = z * cache5.dpr;
|
|
5117
|
+
const m = SCENE_CACHE_MARGIN_PX * cache5.dpr;
|
|
5118
|
+
ctx.save();
|
|
5119
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5120
|
+
ctx.beginPath();
|
|
5121
|
+
ctx.rect(px, py, pw, ph);
|
|
5122
|
+
ctx.clip();
|
|
5123
|
+
ctx.clearRect(px, py, pw, ph);
|
|
5124
|
+
applyCacheTransform(cache5, centerX, centerY, z);
|
|
5125
|
+
const viewport = {
|
|
5126
|
+
x: (px - m) / s + centerX,
|
|
5127
|
+
y: (py - m) / s + centerY,
|
|
5128
|
+
w: pw / s,
|
|
5129
|
+
h: ph / s
|
|
5130
|
+
};
|
|
5131
|
+
paintSceneBody(cache5, { z }, viewport, false);
|
|
5132
|
+
ctx.restore();
|
|
5133
|
+
};
|
|
5134
|
+
const extendCache = (camera) => {
|
|
5135
|
+
const cache5 = ensureCacheSurface();
|
|
5136
|
+
const s = camera.z * cache5.dpr;
|
|
5137
|
+
const cacheW = cache5.canvas.width;
|
|
5138
|
+
const cacheH = cache5.canvas.height;
|
|
5139
|
+
const dx = Math.round((cacheCamX - camera.x) * s);
|
|
5140
|
+
const dy = Math.round((cacheCamY - camera.y) * s);
|
|
5141
|
+
const newCamX = cacheCamX - dx / s;
|
|
5142
|
+
const newCamY = cacheCamY - dy / s;
|
|
5143
|
+
cache5.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5144
|
+
cache5.ctx.drawImage(cache5.canvas, 0, 0, cacheW, cacheH, dx, dy, cacheW, cacheH);
|
|
5145
|
+
cacheCamX = newCamX;
|
|
5146
|
+
cacheCamY = newCamY;
|
|
5147
|
+
cacheCamZ = camera.z;
|
|
5148
|
+
const hw = Math.abs(dx);
|
|
5149
|
+
const vh = Math.abs(dy);
|
|
5150
|
+
const hx = dx > 0 ? 0 : cacheW - hw;
|
|
5151
|
+
const vy = dy > 0 ? 0 : cacheH - vh;
|
|
5152
|
+
const vx = dx > 0 ? hw : 0;
|
|
5153
|
+
const vw = cacheW - hw;
|
|
5154
|
+
if (hw > 0) renderCacheStrip(cache5, newCamX, newCamY, camera.z, hx, 0, hw, cacheH);
|
|
5155
|
+
if (vh > 0 && vw > 0) renderCacheStrip(cache5, newCamX, newCamY, camera.z, vx, vy, vw, vh);
|
|
5156
|
+
};
|
|
5157
|
+
const cacheSourceOffset = (camera) => {
|
|
5158
|
+
const dpr = staticSurface.dpr;
|
|
5159
|
+
return {
|
|
5160
|
+
x: Math.round(((camera.x - cacheCamX) * cacheCamZ + SCENE_CACHE_MARGIN_PX) * dpr),
|
|
5161
|
+
y: Math.round(((camera.y - cacheCamY) * cacheCamZ + SCENE_CACHE_MARGIN_PX) * dpr)
|
|
5162
|
+
};
|
|
5163
|
+
};
|
|
5164
|
+
const viewportFitsInCache = (camera) => {
|
|
5165
|
+
if (!cacheSurface) return false;
|
|
5166
|
+
const { x, y } = cacheSourceOffset(camera);
|
|
5167
|
+
return x >= 0 && y >= 0 && x + staticSurface.canvas.width <= cacheSurface.canvas.width && y + staticSurface.canvas.height <= cacheSurface.canvas.height;
|
|
5168
|
+
};
|
|
5169
|
+
const presentStatic = (camera) => {
|
|
5170
|
+
const cache5 = ensureCacheSurface();
|
|
5171
|
+
const w = staticSurface.canvas.width;
|
|
5172
|
+
const h = staticSurface.canvas.height;
|
|
5173
|
+
const { x: srcX, y: srcY } = cacheSourceOffset(camera);
|
|
5174
|
+
staticSurface.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5175
|
+
staticSurface.ctx.clearRect(0, 0, w, h);
|
|
5176
|
+
staticSurface.ctx.drawImage(cache5.canvas, srcX, srcY, w, h, 0, 0, w, h);
|
|
5177
|
+
};
|
|
5178
|
+
const paintStatic = () => {
|
|
5179
|
+
const camera = store.getCamera();
|
|
5180
|
+
if (!cacheStale && camera.z === cacheCamZ) {
|
|
5181
|
+
if (viewportFitsInCache(camera)) {
|
|
5182
|
+
presentStatic(camera);
|
|
5183
|
+
return;
|
|
5184
|
+
}
|
|
5185
|
+
if (canExtend(camera)) {
|
|
5186
|
+
extendCache(camera);
|
|
5187
|
+
presentStatic(camera);
|
|
5188
|
+
return;
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
renderFullCache(camera);
|
|
5192
|
+
presentStatic(camera);
|
|
5193
|
+
};
|
|
5061
5194
|
const paintCustomCanvasFallback = (ctx, node, def, drawScale, env) => {
|
|
5062
5195
|
if (def.getSnapshot) {
|
|
5063
5196
|
const snap = def.getSnapshot(node, {
|
|
@@ -5239,6 +5372,23 @@ var createRenderer = (opts) => {
|
|
|
5239
5372
|
}
|
|
5240
5373
|
}
|
|
5241
5374
|
}
|
|
5375
|
+
if (interaction.midpointDraft) {
|
|
5376
|
+
const { edgeId, control } = interaction.midpointDraft;
|
|
5377
|
+
const edge = store.getEdge(edgeId);
|
|
5378
|
+
if (edge) {
|
|
5379
|
+
const draftEdge = { ...edge, control };
|
|
5380
|
+
const geom = computeEdgeGeometry(draftEdge, (id) => store.getNode(id));
|
|
5381
|
+
if (geom) {
|
|
5382
|
+
const sourceNode = geom.sourceNodeId ? store.getNode(geom.sourceNodeId) ?? null : null;
|
|
5383
|
+
const targetNode = geom.targetNodeId ? store.getNode(geom.targetNodeId) ?? null : null;
|
|
5384
|
+
drawEdge(ctx, draftEdge, geom, sourceNode, targetNode, scale, theme, {
|
|
5385
|
+
zoom: camera.z,
|
|
5386
|
+
dpr: interactiveSurface.dpr,
|
|
5387
|
+
isMoving: true
|
|
5388
|
+
});
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5242
5392
|
const selection = store.getSelection();
|
|
5243
5393
|
const selectedNodeIds = [];
|
|
5244
5394
|
const selectedEdgeIds = [];
|
|
@@ -5311,7 +5461,12 @@ var createRenderer = (opts) => {
|
|
|
5311
5461
|
y: orig.y + interaction.dragDelta.y
|
|
5312
5462
|
});
|
|
5313
5463
|
} else {
|
|
5314
|
-
|
|
5464
|
+
const d = interaction.resizeDraft;
|
|
5465
|
+
if (d) {
|
|
5466
|
+
m.set(orig.id, { ...live, x: d.x, y: d.y, w: d.w, h: d.h, angle: d.angle });
|
|
5467
|
+
} else {
|
|
5468
|
+
m.set(orig.id, live);
|
|
5469
|
+
}
|
|
5315
5470
|
}
|
|
5316
5471
|
}
|
|
5317
5472
|
return m;
|
|
@@ -5342,6 +5497,7 @@ var createRenderer = (opts) => {
|
|
|
5342
5497
|
const onStoreChange = () => {
|
|
5343
5498
|
invalidateSortedCaches();
|
|
5344
5499
|
staticDirty = true;
|
|
5500
|
+
cacheStale = true;
|
|
5345
5501
|
interactiveDirty = true;
|
|
5346
5502
|
loop.requestFrame();
|
|
5347
5503
|
};
|
|
@@ -5358,6 +5514,7 @@ var createRenderer = (opts) => {
|
|
|
5358
5514
|
interactiveDirty = true;
|
|
5359
5515
|
if (state.mode === "dragging" || state.mode === "resizing" || state.mode === "rotating" || state.mode === "panning" || state.mode === "zooming" || state.mode === "idle") {
|
|
5360
5516
|
staticDirty = true;
|
|
5517
|
+
cacheStale = true;
|
|
5361
5518
|
}
|
|
5362
5519
|
loop.requestFrame();
|
|
5363
5520
|
};
|
|
@@ -5367,16 +5524,19 @@ var createRenderer = (opts) => {
|
|
|
5367
5524
|
const unsubInteraction = store.subscribe("interaction", onInteractionChange);
|
|
5368
5525
|
const unsubFontEpoch = subscribeFontEpoch(() => {
|
|
5369
5526
|
staticDirty = true;
|
|
5527
|
+
cacheStale = true;
|
|
5370
5528
|
loop.requestFrame();
|
|
5371
5529
|
});
|
|
5372
5530
|
const unsubMathEpoch = subscribeMathEpoch(() => {
|
|
5373
5531
|
staticDirty = true;
|
|
5532
|
+
cacheStale = true;
|
|
5374
5533
|
loop.requestFrame();
|
|
5375
5534
|
});
|
|
5376
5535
|
return {
|
|
5377
5536
|
start() {
|
|
5378
5537
|
loop.start();
|
|
5379
5538
|
staticDirty = true;
|
|
5539
|
+
cacheStale = true;
|
|
5380
5540
|
interactiveDirty = isInteractive(store.getInteractionState());
|
|
5381
5541
|
loop.requestFrame();
|
|
5382
5542
|
},
|
|
@@ -5385,6 +5545,7 @@ var createRenderer = (opts) => {
|
|
|
5385
5545
|
},
|
|
5386
5546
|
invalidate() {
|
|
5387
5547
|
staticDirty = true;
|
|
5548
|
+
cacheStale = true;
|
|
5388
5549
|
interactiveDirty = true;
|
|
5389
5550
|
loop.requestFrame();
|
|
5390
5551
|
},
|
|
@@ -5393,6 +5554,7 @@ var createRenderer = (opts) => {
|
|
|
5393
5554
|
const b = sizeSurface(interactiveSurface, cssW, cssH, maxDpr);
|
|
5394
5555
|
if (a || b) {
|
|
5395
5556
|
staticDirty = true;
|
|
5557
|
+
cacheStale = true;
|
|
5396
5558
|
interactiveDirty = true;
|
|
5397
5559
|
loop.requestFrame();
|
|
5398
5560
|
}
|
|
@@ -5400,6 +5562,7 @@ var createRenderer = (opts) => {
|
|
|
5400
5562
|
setBackground(bg) {
|
|
5401
5563
|
background = bg;
|
|
5402
5564
|
staticDirty = true;
|
|
5565
|
+
cacheStale = true;
|
|
5403
5566
|
loop.requestFrame();
|
|
5404
5567
|
},
|
|
5405
5568
|
setSelectionColor(color) {
|
|
@@ -5410,6 +5573,7 @@ var createRenderer = (opts) => {
|
|
|
5410
5573
|
setHideFrames(hidden) {
|
|
5411
5574
|
hideFrames = hidden;
|
|
5412
5575
|
staticDirty = true;
|
|
5576
|
+
cacheStale = true;
|
|
5413
5577
|
loop.requestFrame();
|
|
5414
5578
|
},
|
|
5415
5579
|
stats: () => loop.stats(),
|
|
@@ -5424,6 +5588,11 @@ var createRenderer = (opts) => {
|
|
|
5424
5588
|
unsubFontEpoch();
|
|
5425
5589
|
unsubMathEpoch();
|
|
5426
5590
|
assetCache.dispose();
|
|
5591
|
+
if (cacheSurface) {
|
|
5592
|
+
cacheSurface.canvas.width = 0;
|
|
5593
|
+
cacheSurface.canvas.height = 0;
|
|
5594
|
+
cacheSurface = null;
|
|
5595
|
+
}
|
|
5427
5596
|
}
|
|
5428
5597
|
};
|
|
5429
5598
|
};
|