@canvas-harness/core 0.1.20 → 0.1.22
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 +152 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +152 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4754,6 +4754,59 @@ var buildPath = (type, x, y, w, h, radius) => {
|
|
|
4754
4754
|
}
|
|
4755
4755
|
};
|
|
4756
4756
|
|
|
4757
|
+
// src/render/scene-cache-math.ts
|
|
4758
|
+
var computeCacheSourceRect = (cache5, view) => {
|
|
4759
|
+
const ratio = cache5.camZ / view.camZ;
|
|
4760
|
+
const srcX = Math.round(((view.camX - cache5.camX) * cache5.camZ + cache5.marginCssPx) * cache5.dpr);
|
|
4761
|
+
const srcY = Math.round(((view.camY - cache5.camY) * cache5.camZ + cache5.marginCssPx) * cache5.dpr);
|
|
4762
|
+
const srcW = view.widthCssPx * ratio * cache5.dpr;
|
|
4763
|
+
const srcH = view.heightCssPx * ratio * cache5.dpr;
|
|
4764
|
+
return { srcX, srcY, srcW, srcH };
|
|
4765
|
+
};
|
|
4766
|
+
var cacheCoversViewport = (cache5, view) => {
|
|
4767
|
+
const { srcX, srcY, srcW, srcH } = computeCacheSourceRect(cache5, view);
|
|
4768
|
+
return srcX >= 0 && srcY >= 0 && srcX + srcW <= cache5.widthDevicePx && srcY + srcH <= cache5.heightDevicePx;
|
|
4769
|
+
};
|
|
4770
|
+
var scaleRatioInBounds = (cacheCamZ, viewCamZ, maxRatio) => {
|
|
4771
|
+
if (viewCamZ <= 0 || cacheCamZ <= 0 || maxRatio <= 0) return false;
|
|
4772
|
+
const ratio = viewCamZ >= cacheCamZ ? viewCamZ / cacheCamZ : cacheCamZ / viewCamZ;
|
|
4773
|
+
return ratio <= maxRatio;
|
|
4774
|
+
};
|
|
4775
|
+
var cacheReuseLayout = (cache5, view) => {
|
|
4776
|
+
const ratio = view.camZ / cache5.camZ;
|
|
4777
|
+
const cacheW = cache5.widthDevicePx;
|
|
4778
|
+
const cacheH = cache5.heightDevicePx;
|
|
4779
|
+
const marginDev = cache5.marginCssPx * cache5.dpr;
|
|
4780
|
+
const destW = cacheW * ratio;
|
|
4781
|
+
const destH = cacheH * ratio;
|
|
4782
|
+
const destX = (cache5.camX - view.camX) * view.camZ * cache5.dpr + marginDev * (1 - ratio);
|
|
4783
|
+
const destY = (cache5.camY - view.camY) * view.camZ * cache5.dpr + marginDev * (1 - ratio);
|
|
4784
|
+
const dest = { x: destX, y: destY, w: destW, h: destH };
|
|
4785
|
+
const strips = {
|
|
4786
|
+
top: { x: 0, y: 0, w: cacheW, h: Math.max(0, destY) },
|
|
4787
|
+
bottom: {
|
|
4788
|
+
x: 0,
|
|
4789
|
+
y: destY + destH,
|
|
4790
|
+
w: cacheW,
|
|
4791
|
+
h: Math.max(0, cacheH - destY - destH)
|
|
4792
|
+
},
|
|
4793
|
+
left: { x: 0, y: destY, w: Math.max(0, destX), h: destH },
|
|
4794
|
+
right: {
|
|
4795
|
+
x: destX + destW,
|
|
4796
|
+
y: destY,
|
|
4797
|
+
w: Math.max(0, cacheW - destX - destW),
|
|
4798
|
+
h: destH
|
|
4799
|
+
}
|
|
4800
|
+
};
|
|
4801
|
+
const valid = destX >= 0 && destY >= 0 && destX + destW <= cacheW && destY + destH <= cacheH;
|
|
4802
|
+
return { dest, strips, valid };
|
|
4803
|
+
};
|
|
4804
|
+
var zoomExtendRatioInBounds = (cacheCamZ, viewCamZ, minRatio) => {
|
|
4805
|
+
if (viewCamZ <= 0 || cacheCamZ <= 0 || minRatio <= 0 || minRatio >= 1) return false;
|
|
4806
|
+
const ratio = viewCamZ / cacheCamZ;
|
|
4807
|
+
return ratio >= minRatio && ratio < 1;
|
|
4808
|
+
};
|
|
4809
|
+
|
|
4757
4810
|
// src/render/shapes/content-bounds.ts
|
|
4758
4811
|
var SQRT2_INV = 1 / Math.SQRT2;
|
|
4759
4812
|
var contentBounds = (node) => {
|
|
@@ -4838,6 +4891,7 @@ var createRenderer = (opts) => {
|
|
|
4838
4891
|
let interactiveDirty = false;
|
|
4839
4892
|
let overlaySet = /* @__PURE__ */ new Set();
|
|
4840
4893
|
let lastDrawn = 0;
|
|
4894
|
+
let lastDrawPath = "idle";
|
|
4841
4895
|
let cacheSurface = null;
|
|
4842
4896
|
let cacheCamX = 0;
|
|
4843
4897
|
let cacheCamY = 0;
|
|
@@ -4895,6 +4949,8 @@ var createRenderer = (opts) => {
|
|
|
4895
4949
|
paintBackground(surface.ctx, { viewport, zoom: camera.z, background });
|
|
4896
4950
|
const visible = visibleNodes(camera, viewport);
|
|
4897
4951
|
const isMoving2 = isMoving(interaction);
|
|
4952
|
+
const viewMotion = interaction.mode === "panning" || interaction.mode === "zooming" || interaction.mode === "marqueeing";
|
|
4953
|
+
const isStripRender = !fullRender;
|
|
4898
4954
|
const minOnScreen = MIN_ON_SCREEN_SIZE_PX;
|
|
4899
4955
|
const nextOverlaySet = /* @__PURE__ */ new Set();
|
|
4900
4956
|
let drawn = 0;
|
|
@@ -4907,9 +4963,8 @@ var createRenderer = (opts) => {
|
|
|
4907
4963
|
theme: (token) => theme ? theme(token) : void 0
|
|
4908
4964
|
};
|
|
4909
4965
|
const editingNodeId = interaction.editingTarget?.kind === "node" ? interaction.editingTarget.id : null;
|
|
4910
|
-
const cameraIsMoving = interaction.mode === "panning" || interaction.mode === "zooming";
|
|
4911
4966
|
const movingNodeCount = excludedNodes?.size ?? 0;
|
|
4912
|
-
const roughEnabled =
|
|
4967
|
+
const roughEnabled = movingNodeCount <= ROUGH_MAX_MOVING_NODES && camera.z >= ROUGH_MIN_ZOOM && visible.length <= ROUGH_MAX_NODES;
|
|
4913
4968
|
if (!hideFrames) {
|
|
4914
4969
|
for (const node of visible) {
|
|
4915
4970
|
if (node.type !== "frame") continue;
|
|
@@ -4984,7 +5039,7 @@ var createRenderer = (opts) => {
|
|
|
4984
5039
|
if (!def) continue;
|
|
4985
5040
|
if (node.w * camera.z < minOnScreen && node.h * camera.z < minOnScreen) continue;
|
|
4986
5041
|
if (camera.z < def.lod.minZoomForPlaceholder) continue;
|
|
4987
|
-
const preferCanvas = camera.z < def.lod.minZoomForReact ||
|
|
5042
|
+
const preferCanvas = camera.z < def.lod.minZoomForReact || viewMotion && isStripRender && !overlaySet.has(node.id);
|
|
4988
5043
|
if (preferCanvas) {
|
|
4989
5044
|
if (paintCustomCanvasFallback(surface.ctx, node, def, scale, renderEnv)) {
|
|
4990
5045
|
drawn++;
|
|
@@ -5005,7 +5060,7 @@ var createRenderer = (opts) => {
|
|
|
5005
5060
|
}
|
|
5006
5061
|
}
|
|
5007
5062
|
const visEdges = visibleEdges(viewport);
|
|
5008
|
-
const edgeRoughEnabled =
|
|
5063
|
+
const edgeRoughEnabled = movingNodeCount <= ROUGH_MAX_MOVING_NODES && camera.z >= ROUGH_MIN_ZOOM && visEdges.length <= ROUGH_MAX_NODES;
|
|
5009
5064
|
for (const edge of visEdges) {
|
|
5010
5065
|
if (excludedEdges?.has(edge.id)) continue;
|
|
5011
5066
|
paintOneEdge(surface.ctx, edge, scale, edgeRoughEnabled, camera.z, isMoving2);
|
|
@@ -5085,6 +5140,44 @@ var createRenderer = (opts) => {
|
|
|
5085
5140
|
if (hw > 0) renderCacheStrip(cache5, newCamX, newCamY, camera.z, hx, 0, hw, cacheH);
|
|
5086
5141
|
if (vh > 0 && vw > 0) renderCacheStrip(cache5, newCamX, newCamY, camera.z, vx, vy, vw, vh);
|
|
5087
5142
|
};
|
|
5143
|
+
let scaledExtendScratch = null;
|
|
5144
|
+
const extendCacheScaled = (camera, layout) => {
|
|
5145
|
+
const cache5 = ensureCacheSurface();
|
|
5146
|
+
const cacheW = cache5.canvas.width;
|
|
5147
|
+
const cacheH = cache5.canvas.height;
|
|
5148
|
+
if (!scaledExtendScratch || scaledExtendScratch.width !== cacheW || scaledExtendScratch.height !== cacheH) {
|
|
5149
|
+
scaledExtendScratch = document.createElement("canvas");
|
|
5150
|
+
scaledExtendScratch.width = cacheW;
|
|
5151
|
+
scaledExtendScratch.height = cacheH;
|
|
5152
|
+
}
|
|
5153
|
+
const sctx = scaledExtendScratch.getContext("2d");
|
|
5154
|
+
sctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5155
|
+
sctx.clearRect(0, 0, cacheW, cacheH);
|
|
5156
|
+
sctx.drawImage(cache5.canvas, 0, 0);
|
|
5157
|
+
cache5.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5158
|
+
cache5.ctx.clearRect(0, 0, cacheW, cacheH);
|
|
5159
|
+
cache5.ctx.drawImage(
|
|
5160
|
+
scaledExtendScratch,
|
|
5161
|
+
layout.dest.x,
|
|
5162
|
+
layout.dest.y,
|
|
5163
|
+
layout.dest.w,
|
|
5164
|
+
layout.dest.h
|
|
5165
|
+
);
|
|
5166
|
+
cacheCamX = camera.x;
|
|
5167
|
+
cacheCamY = camera.y;
|
|
5168
|
+
cacheCamZ = camera.z;
|
|
5169
|
+
const strips = [
|
|
5170
|
+
layout.strips.top,
|
|
5171
|
+
layout.strips.bottom,
|
|
5172
|
+
layout.strips.left,
|
|
5173
|
+
layout.strips.right
|
|
5174
|
+
];
|
|
5175
|
+
for (const s of strips) {
|
|
5176
|
+
if (s.w > 0 && s.h > 0) {
|
|
5177
|
+
renderCacheStrip(cache5, camera.x, camera.y, camera.z, s.x, s.y, s.w, s.h);
|
|
5178
|
+
}
|
|
5179
|
+
}
|
|
5180
|
+
};
|
|
5088
5181
|
const cacheSourceOffset = (camera) => {
|
|
5089
5182
|
const dpr = staticSurface.dpr;
|
|
5090
5183
|
return {
|
|
@@ -5106,21 +5199,72 @@ var createRenderer = (opts) => {
|
|
|
5106
5199
|
staticSurface.ctx.clearRect(0, 0, w, h);
|
|
5107
5200
|
staticSurface.ctx.drawImage(cache5.canvas, srcX, srcY, w, h, 0, 0, w, h);
|
|
5108
5201
|
};
|
|
5202
|
+
const snapshotCacheCamera = (cache5) => ({
|
|
5203
|
+
camX: cacheCamX,
|
|
5204
|
+
camY: cacheCamY,
|
|
5205
|
+
camZ: cacheCamZ,
|
|
5206
|
+
widthDevicePx: cache5.canvas.width,
|
|
5207
|
+
heightDevicePx: cache5.canvas.height,
|
|
5208
|
+
dpr: cache5.dpr,
|
|
5209
|
+
marginCssPx: SCENE_CACHE_MARGIN_PX
|
|
5210
|
+
});
|
|
5211
|
+
const snapshotView = (camera) => ({
|
|
5212
|
+
camX: camera.x,
|
|
5213
|
+
camY: camera.y,
|
|
5214
|
+
camZ: camera.z,
|
|
5215
|
+
widthCssPx: staticSurface.cssWidth,
|
|
5216
|
+
heightCssPx: staticSurface.cssHeight
|
|
5217
|
+
});
|
|
5218
|
+
const presentStaticScaled = (camera) => {
|
|
5219
|
+
const cache5 = ensureCacheSurface();
|
|
5220
|
+
const w = staticSurface.canvas.width;
|
|
5221
|
+
const h = staticSurface.canvas.height;
|
|
5222
|
+
const { srcX, srcY, srcW, srcH } = computeCacheSourceRect(
|
|
5223
|
+
snapshotCacheCamera(cache5),
|
|
5224
|
+
snapshotView(camera)
|
|
5225
|
+
);
|
|
5226
|
+
staticSurface.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5227
|
+
staticSurface.ctx.clearRect(0, 0, w, h);
|
|
5228
|
+
staticSurface.ctx.drawImage(cache5.canvas, srcX, srcY, srcW, srcH, 0, 0, w, h);
|
|
5229
|
+
};
|
|
5230
|
+
const SCALED_BLIT_MAX_RATIO = 4;
|
|
5231
|
+
const SCALED_EXTEND_MIN_RATIO = 0.5;
|
|
5109
5232
|
const paintStatic = () => {
|
|
5110
5233
|
const camera = store.getCamera();
|
|
5111
5234
|
if (!cacheStale && camera.z === cacheCamZ) {
|
|
5112
5235
|
if (viewportFitsInCache(camera)) {
|
|
5113
5236
|
presentStatic(camera);
|
|
5237
|
+
lastDrawPath = "present";
|
|
5114
5238
|
return;
|
|
5115
5239
|
}
|
|
5116
5240
|
if (canExtend(camera)) {
|
|
5117
5241
|
extendCache(camera);
|
|
5118
5242
|
presentStatic(camera);
|
|
5243
|
+
lastDrawPath = "extend";
|
|
5244
|
+
return;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
if (!cacheStale && camera.z !== cacheCamZ && store.getInteractionState().mode === "zooming" && cacheSurface) {
|
|
5248
|
+
const cacheCam = snapshotCacheCamera(cacheSurface);
|
|
5249
|
+
const view = snapshotView(camera);
|
|
5250
|
+
if (scaleRatioInBounds(cacheCam.camZ, view.camZ, SCALED_BLIT_MAX_RATIO) && cacheCoversViewport(cacheCam, view)) {
|
|
5251
|
+
presentStaticScaled(camera);
|
|
5252
|
+
lastDrawPath = "scaled";
|
|
5119
5253
|
return;
|
|
5120
5254
|
}
|
|
5255
|
+
if (zoomExtendRatioInBounds(cacheCam.camZ, view.camZ, SCALED_EXTEND_MIN_RATIO)) {
|
|
5256
|
+
const layout = cacheReuseLayout(cacheCam, view);
|
|
5257
|
+
if (layout.valid) {
|
|
5258
|
+
extendCacheScaled(camera, layout);
|
|
5259
|
+
presentStatic(camera);
|
|
5260
|
+
lastDrawPath = "scaled-extend";
|
|
5261
|
+
return;
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5121
5264
|
}
|
|
5122
5265
|
renderFullCache(camera);
|
|
5123
5266
|
presentStatic(camera);
|
|
5267
|
+
lastDrawPath = "full";
|
|
5124
5268
|
};
|
|
5125
5269
|
const paintCustomCanvasFallback = (ctx, node, def, drawScale, env) => {
|
|
5126
5270
|
if (def.getSnapshot) {
|
|
@@ -5443,9 +5587,11 @@ var createRenderer = (opts) => {
|
|
|
5443
5587
|
};
|
|
5444
5588
|
const onInteractionChange = (state) => {
|
|
5445
5589
|
interactiveDirty = true;
|
|
5446
|
-
if (state.mode === "dragging" || state.mode === "resizing" || state.mode === "rotating" || state.mode === "panning" || state.mode === "
|
|
5590
|
+
if (state.mode === "dragging" || state.mode === "resizing" || state.mode === "rotating" || state.mode === "panning" || state.mode === "idle") {
|
|
5447
5591
|
staticDirty = true;
|
|
5448
5592
|
cacheStale = true;
|
|
5593
|
+
} else if (state.mode === "zooming") {
|
|
5594
|
+
staticDirty = true;
|
|
5449
5595
|
}
|
|
5450
5596
|
loop.requestFrame();
|
|
5451
5597
|
};
|
|
@@ -5509,6 +5655,7 @@ var createRenderer = (opts) => {
|
|
|
5509
5655
|
},
|
|
5510
5656
|
stats: () => loop.stats(),
|
|
5511
5657
|
lastDrawCount: () => lastDrawn,
|
|
5658
|
+
getLastDrawPath: () => lastDrawPath,
|
|
5512
5659
|
getOverlaySet: () => [...overlaySet],
|
|
5513
5660
|
getAssetCache: () => assetCache,
|
|
5514
5661
|
dispose() {
|