canvu-react 0.4.67 → 0.4.69

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.d.cts CHANGED
@@ -2,9 +2,9 @@ import { C as Camera2D } from './shape-builders-DzhCOuzo.cjs';
2
2
  export { a as Camera2DOptions, D as DEFAULT_STROKE_STYLE, F as FreehandSvgPayload, S as StrokeStyle, b as applyStrokeToItem, c as buildArchitecturalCloudPathD, d as buildArchitecturalCloudSvg, e as buildArrowSvg, f as buildDrawDotSvg, g as buildEllipseSvg, h as buildFreehandPathSvg, i as buildLineSvg, j as buildRectSvg, k as computeFreehandSvgPayload, l as createArchitecturalCloudItem, m as createDrawDotItem, n as createEllipseItem, o as createFreehandStrokeItem, p as createImageFromVectorTrace, q as createImageItem, r as createLineItem, s as createRectangleItem, t as createShapeId, u as createTextItem, v as lineEndpointsToLocal, w as rebuildItemSvg, x as resolveStrokeStyle } from './shape-builders-DzhCOuzo.cjs';
3
3
  import { V as VectorSceneItem, A as ArrowEndpointBinding, C as CustomShapeResizeHandles, R as Rect } from './types-fJNwEnHf.cjs';
4
4
  export { a as ArrowBindings, b as ResizeHandleId, c as VectorPathPoint, n as normalizeRect, r as rectsIntersect } from './types-fJNwEnHf.cjs';
5
- export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-F6aM5C7x.cjs';
5
+ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-D2xaUoAT.cjs';
6
+ import { R as RasterImageCanvasRenderingOptions } from './raster-image-canvas-nK9kM9UJ.cjs';
6
7
  export { C as CanvuLinkData, D as DEFAULT_LINK_CARD_SIZE, L as LINK_PLUGIN_KEY, b as buildLinkCardSvg, c as createLinkItem, g as getLinkData, i as isLinkItem } from './link-item-BMV3VUCr.cjs';
7
- import './asset-store-35ysK28r.cjs';
8
8
 
9
9
  type EncodeCanvasToBlobOptions = {
10
10
  mimeType?: string;
@@ -180,6 +180,7 @@ type SvgVectorRendererOptions = {
180
180
  * (interactive selection / resize / placement).
181
181
  */
182
182
  pointerEventsNone?: boolean;
183
+ rasterImageCanvas?: RasterImageCanvasRenderingOptions | null;
183
184
  };
184
185
  type SvgVectorRendererInteractionState = {
185
186
  selectedIds?: readonly string[];
@@ -204,6 +205,7 @@ declare class SvgVectorRenderer {
204
205
  private hoveredItemId;
205
206
  private liveOverlay;
206
207
  private readonly resizeObserver;
208
+ private rasterImageCanvasRendering;
207
209
  constructor(options: SvgVectorRendererOptions);
208
210
  /**
209
211
  * Updates interaction attributes on item groups for CSS hooks.
@@ -213,6 +215,7 @@ declare class SvgVectorRenderer {
213
215
  * pointer events.
214
216
  */
215
217
  setInteractionState(state: SvgVectorRendererInteractionState): void;
218
+ setRasterImageCanvasRendering(options: RasterImageCanvasRenderingOptions | null | undefined): void;
216
219
  /**
217
220
  * Reads container size, culls items, and updates the SVG (incrementally when possible).
218
221
  */
@@ -228,6 +231,13 @@ declare class SvgVectorRenderer {
228
231
  renderLiveItem(item: VectorSceneItem | null): void;
229
232
  private keepLiveOverlayOnTop;
230
233
  private syncVisibleItems;
234
+ private syncRasterImageCanvas;
235
+ private ensureRasterImageCanvas;
236
+ private positionRasterImageCanvas;
237
+ private drawRasterImageCanvas;
238
+ private drawQueuedRasterImageCanvasTarget;
239
+ private clearRasterImageCanvasBitmap;
240
+ private releaseRasterImageCanvas;
231
241
  private applyInteractionAttributes;
232
242
  destroy(): void;
233
243
  /** Toggle whether the scene SVG receives pointer events (vs overlay handling them). */
package/dist/index.d.ts CHANGED
@@ -2,9 +2,9 @@ import { C as Camera2D } from './shape-builders-xG3A66sv.js';
2
2
  export { a as Camera2DOptions, D as DEFAULT_STROKE_STYLE, F as FreehandSvgPayload, S as StrokeStyle, b as applyStrokeToItem, c as buildArchitecturalCloudPathD, d as buildArchitecturalCloudSvg, e as buildArrowSvg, f as buildDrawDotSvg, g as buildEllipseSvg, h as buildFreehandPathSvg, i as buildLineSvg, j as buildRectSvg, k as computeFreehandSvgPayload, l as createArchitecturalCloudItem, m as createDrawDotItem, n as createEllipseItem, o as createFreehandStrokeItem, p as createImageFromVectorTrace, q as createImageItem, r as createLineItem, s as createRectangleItem, t as createShapeId, u as createTextItem, v as lineEndpointsToLocal, w as rebuildItemSvg, x as resolveStrokeStyle } from './shape-builders-xG3A66sv.js';
3
3
  import { V as VectorSceneItem, A as ArrowEndpointBinding, C as CustomShapeResizeHandles, R as Rect } from './types-fJNwEnHf.js';
4
4
  export { a as ArrowBindings, b as ResizeHandleId, c as VectorPathPoint, n as normalizeRect, r as rectsIntersect } from './types-fJNwEnHf.js';
5
- export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-BSjiek7Q.js';
5
+ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-D9eThWse.js';
6
+ import { R as RasterImageCanvasRenderingOptions } from './raster-image-canvas-CCOmB4NY.js';
6
7
  export { C as CanvuLinkData, D as DEFAULT_LINK_CARD_SIZE, L as LINK_PLUGIN_KEY, b as buildLinkCardSvg, c as createLinkItem, g as getLinkData, i as isLinkItem } from './link-item-COoNNvCu.js';
7
- import './asset-store-D_FjW_CN.js';
8
8
 
9
9
  type EncodeCanvasToBlobOptions = {
10
10
  mimeType?: string;
@@ -180,6 +180,7 @@ type SvgVectorRendererOptions = {
180
180
  * (interactive selection / resize / placement).
181
181
  */
182
182
  pointerEventsNone?: boolean;
183
+ rasterImageCanvas?: RasterImageCanvasRenderingOptions | null;
183
184
  };
184
185
  type SvgVectorRendererInteractionState = {
185
186
  selectedIds?: readonly string[];
@@ -204,6 +205,7 @@ declare class SvgVectorRenderer {
204
205
  private hoveredItemId;
205
206
  private liveOverlay;
206
207
  private readonly resizeObserver;
208
+ private rasterImageCanvasRendering;
207
209
  constructor(options: SvgVectorRendererOptions);
208
210
  /**
209
211
  * Updates interaction attributes on item groups for CSS hooks.
@@ -213,6 +215,7 @@ declare class SvgVectorRenderer {
213
215
  * pointer events.
214
216
  */
215
217
  setInteractionState(state: SvgVectorRendererInteractionState): void;
218
+ setRasterImageCanvasRendering(options: RasterImageCanvasRenderingOptions | null | undefined): void;
216
219
  /**
217
220
  * Reads container size, culls items, and updates the SVG (incrementally when possible).
218
221
  */
@@ -228,6 +231,13 @@ declare class SvgVectorRenderer {
228
231
  renderLiveItem(item: VectorSceneItem | null): void;
229
232
  private keepLiveOverlayOnTop;
230
233
  private syncVisibleItems;
234
+ private syncRasterImageCanvas;
235
+ private ensureRasterImageCanvas;
236
+ private positionRasterImageCanvas;
237
+ private drawRasterImageCanvas;
238
+ private drawQueuedRasterImageCanvasTarget;
239
+ private clearRasterImageCanvasBitmap;
240
+ private releaseRasterImageCanvas;
231
241
  private applyInteractionAttributes;
232
242
  destroy(): void;
233
243
  /** Toggle whether the scene SVG receives pointer events (vs overlay handling them). */
package/dist/index.js CHANGED
@@ -2570,6 +2570,176 @@ function cullItemsByViewport(items, visibleWorld) {
2570
2570
  return cullItemsByViewportSpatial(items, visibleWorld, SPATIAL_CELL_SIZE);
2571
2571
  }
2572
2572
 
2573
+ // src/renderer/raster-image-canvas.ts
2574
+ var DEFAULT_PIXEL_HEADROOM = 1.5;
2575
+ var DEFAULT_MAX_PIXEL_COUNT = 12e6;
2576
+ var DEFAULT_MAX_DIMENSION = 4096;
2577
+ var DEFAULT_UPSCALE_REDRAW_RATIO = 1.15;
2578
+ function resolveRasterImageCanvasRenderingOptions(options) {
2579
+ if (!options) return null;
2580
+ const fallbackDevicePixelRatio = typeof window === "undefined" ? 1 : window.devicePixelRatio;
2581
+ return {
2582
+ resolveSourceSize: options.resolveSourceSize,
2583
+ resolveRenderTarget: options.resolveRenderTarget,
2584
+ devicePixelRatio: toPositiveFiniteNumber(
2585
+ options.devicePixelRatio,
2586
+ fallbackDevicePixelRatio
2587
+ ),
2588
+ pixelHeadroom: toPositiveFiniteNumber(
2589
+ options.pixelHeadroom,
2590
+ DEFAULT_PIXEL_HEADROOM
2591
+ ),
2592
+ maxPixelCount: toPositiveFiniteNumber(
2593
+ options.maxPixelCount,
2594
+ DEFAULT_MAX_PIXEL_COUNT
2595
+ ),
2596
+ maxDimension: toPositiveFiniteNumber(
2597
+ options.maxDimension,
2598
+ DEFAULT_MAX_DIMENSION
2599
+ ),
2600
+ upscaleRedrawRatio: toPositiveFiniteNumber(
2601
+ options.upscaleRedrawRatio,
2602
+ DEFAULT_UPSCALE_REDRAW_RATIO
2603
+ )
2604
+ };
2605
+ }
2606
+ function getRasterImageContentRect(item) {
2607
+ if (item.toolKind !== "image" || !item.imageIntrinsicSize) return null;
2608
+ const bounds = normalizeRect(item.bounds);
2609
+ const intrinsicWidth = Math.max(1e-6, item.imageIntrinsicSize.width);
2610
+ const intrinsicHeight = Math.max(1e-6, item.imageIntrinsicSize.height);
2611
+ const boundsAspectRatio = bounds.width / Math.max(1e-9, bounds.height);
2612
+ const imageAspectRatio = intrinsicWidth / intrinsicHeight;
2613
+ if (Math.abs(boundsAspectRatio - imageAspectRatio) < 1e-3) {
2614
+ return { x: 0, y: 0, width: bounds.width, height: bounds.height };
2615
+ }
2616
+ if (boundsAspectRatio > imageAspectRatio) {
2617
+ const height2 = bounds.height;
2618
+ const width2 = height2 * imageAspectRatio;
2619
+ return { x: (bounds.width - width2) / 2, y: 0, width: width2, height: height2 };
2620
+ }
2621
+ const width = bounds.width;
2622
+ const height = width / imageAspectRatio;
2623
+ return { x: 0, y: (bounds.height - height) / 2, width, height };
2624
+ }
2625
+ function resolveRasterImageCanvasSourceSize({
2626
+ item,
2627
+ href,
2628
+ intrinsicSize,
2629
+ contentRect,
2630
+ viewportSize,
2631
+ cameraZoom,
2632
+ options
2633
+ }) {
2634
+ const resolved = options.resolveSourceSize?.({
2635
+ item,
2636
+ href,
2637
+ intrinsicSize,
2638
+ contentRect,
2639
+ viewportSize,
2640
+ cameraZoom,
2641
+ devicePixelRatio: options.devicePixelRatio
2642
+ });
2643
+ const width = toPositiveFiniteNumber(resolved?.width, intrinsicSize.width);
2644
+ const height = toPositiveFiniteNumber(resolved?.height, intrinsicSize.height);
2645
+ return { width, height };
2646
+ }
2647
+ function getRasterImageCanvasTargetSize({
2648
+ intrinsicSize,
2649
+ contentRect,
2650
+ cameraZoom,
2651
+ devicePixelRatio,
2652
+ pixelHeadroom,
2653
+ maxPixelCount,
2654
+ maxDimension
2655
+ }) {
2656
+ const intrinsicWidth = Math.max(1, Math.round(intrinsicSize.width));
2657
+ const intrinsicHeight = Math.max(1, Math.round(intrinsicSize.height));
2658
+ const targetCssWidth = Math.max(1, contentRect.width * cameraZoom);
2659
+ const targetCssHeight = Math.max(1, contentRect.height * cameraZoom);
2660
+ const desiredWidth = targetCssWidth * toPositiveFiniteNumber(devicePixelRatio, 1) * pixelHeadroom;
2661
+ const desiredHeight = targetCssHeight * toPositiveFiniteNumber(devicePixelRatio, 1) * pixelHeadroom;
2662
+ const dimensionScale = Math.min(
2663
+ 1,
2664
+ toPositiveFiniteNumber(maxDimension, intrinsicWidth) / Math.max(intrinsicWidth, intrinsicHeight)
2665
+ );
2666
+ const pixelScale = Math.min(
2667
+ 1,
2668
+ Math.sqrt(
2669
+ toPositiveFiniteNumber(maxPixelCount, intrinsicWidth * intrinsicHeight) / (intrinsicWidth * intrinsicHeight)
2670
+ )
2671
+ );
2672
+ const viewportScale = Math.min(
2673
+ 1,
2674
+ desiredWidth / intrinsicWidth,
2675
+ desiredHeight / intrinsicHeight
2676
+ );
2677
+ const scale = Math.min(dimensionScale, pixelScale, viewportScale);
2678
+ const width = Math.max(1, Math.round(intrinsicWidth * scale));
2679
+ const height = Math.max(1, Math.round(width * (intrinsicHeight / intrinsicWidth)));
2680
+ return { width, height };
2681
+ }
2682
+ function resolveRasterImageCanvasRenderTarget({
2683
+ item,
2684
+ href,
2685
+ intrinsicSize,
2686
+ sourceSize,
2687
+ contentRect,
2688
+ targetSize,
2689
+ viewportSize,
2690
+ cameraZoom,
2691
+ options
2692
+ }) {
2693
+ const request = {
2694
+ item,
2695
+ href,
2696
+ intrinsicSize,
2697
+ sourceSize,
2698
+ contentRect,
2699
+ targetSize,
2700
+ viewportSize,
2701
+ cameraZoom,
2702
+ devicePixelRatio: options.devicePixelRatio
2703
+ };
2704
+ const resolved = options.resolveRenderTarget?.(request);
2705
+ if (typeof resolved === "string") {
2706
+ return { href: resolved, sourceKey: resolved, targetSize, contentRect };
2707
+ }
2708
+ if (resolved?.href) {
2709
+ return {
2710
+ href: resolved.href,
2711
+ sourceKey: resolved.sourceKey ?? resolved.href,
2712
+ targetSize,
2713
+ contentRect
2714
+ };
2715
+ }
2716
+ return { href, sourceKey: href, targetSize, contentRect };
2717
+ }
2718
+ function shouldRedrawRasterImageCanvas({
2719
+ currentSourceKey,
2720
+ currentWidth,
2721
+ currentHeight,
2722
+ nextSourceKey,
2723
+ nextWidth,
2724
+ nextHeight,
2725
+ upscaleRedrawRatio
2726
+ }) {
2727
+ const safeCurrentWidth = Math.max(0, Math.round(currentWidth));
2728
+ const safeCurrentHeight = Math.max(0, Math.round(currentHeight));
2729
+ const safeNextWidth = Math.max(1, Math.round(nextWidth));
2730
+ const safeNextHeight = Math.max(1, Math.round(nextHeight));
2731
+ if (!currentSourceKey || safeCurrentWidth <= 1 || safeCurrentHeight <= 1) {
2732
+ return true;
2733
+ }
2734
+ if (currentSourceKey !== nextSourceKey && safeCurrentWidth === safeNextWidth && safeCurrentHeight === safeNextHeight) {
2735
+ return true;
2736
+ }
2737
+ return safeNextWidth > safeCurrentWidth * upscaleRedrawRatio || safeNextHeight > safeCurrentHeight * upscaleRedrawRatio;
2738
+ }
2739
+ function toPositiveFiniteNumber(value, fallback) {
2740
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
2741
+ }
2742
+
2573
2743
  // src/renderer/svg-vector-renderer.ts
2574
2744
  function formatCameraTransform(camera) {
2575
2745
  const z = camera.zoom;
@@ -2594,6 +2764,87 @@ function itemClassName(item) {
2594
2764
  }
2595
2765
  return classes.join(" ");
2596
2766
  }
2767
+ async function decodeRasterImage(href, width, height, signal) {
2768
+ if (typeof createImageBitmap === "function") {
2769
+ try {
2770
+ const response = await fetch(href, { signal, credentials: "same-origin" });
2771
+ if (!response.ok) {
2772
+ throw new Error(`Failed to fetch raster image: ${response.status}`);
2773
+ }
2774
+ const blob = await response.blob();
2775
+ if (signal.aborted) throw new DOMException("Aborted", "AbortError");
2776
+ const bitmap = await createImageBitmap(blob, {
2777
+ resizeWidth: width,
2778
+ resizeHeight: height,
2779
+ resizeQuality: "high"
2780
+ });
2781
+ return {
2782
+ width: bitmap.width,
2783
+ height: bitmap.height,
2784
+ draw: (context) => {
2785
+ context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height);
2786
+ },
2787
+ close: () => bitmap.close()
2788
+ };
2789
+ } catch (error) {
2790
+ if (signal.aborted) throw error;
2791
+ }
2792
+ }
2793
+ const image = await loadImageElement(href, signal);
2794
+ return {
2795
+ width,
2796
+ height,
2797
+ draw: (context) => {
2798
+ context.drawImage(image, 0, 0, width, height);
2799
+ },
2800
+ close: () => {
2801
+ }
2802
+ };
2803
+ }
2804
+ function loadImageElement(href, signal) {
2805
+ return new Promise((resolve, reject) => {
2806
+ if (signal.aborted) {
2807
+ reject(new DOMException("Aborted", "AbortError"));
2808
+ return;
2809
+ }
2810
+ const image = new Image();
2811
+ const cleanup = () => {
2812
+ signal.removeEventListener("abort", abort);
2813
+ image.onload = null;
2814
+ image.onerror = null;
2815
+ };
2816
+ const abort = () => {
2817
+ cleanup();
2818
+ image.removeAttribute("src");
2819
+ reject(new DOMException("Aborted", "AbortError"));
2820
+ };
2821
+ image.decoding = "async";
2822
+ image.onload = () => {
2823
+ const decodePromise = image.decode?.();
2824
+ if (!decodePromise) {
2825
+ cleanup();
2826
+ resolve(image);
2827
+ return;
2828
+ }
2829
+ decodePromise.then(
2830
+ () => {
2831
+ cleanup();
2832
+ resolve(image);
2833
+ },
2834
+ () => {
2835
+ cleanup();
2836
+ resolve(image);
2837
+ }
2838
+ );
2839
+ };
2840
+ image.onerror = () => {
2841
+ cleanup();
2842
+ reject(new Error("Failed to load raster image"));
2843
+ };
2844
+ signal.addEventListener("abort", abort, { once: true });
2845
+ image.src = href;
2846
+ });
2847
+ }
2597
2848
  var SvgVectorRenderer = class {
2598
2849
  container;
2599
2850
  scene;
@@ -2605,10 +2856,14 @@ var SvgVectorRenderer = class {
2605
2856
  hoveredItemId = null;
2606
2857
  liveOverlay = null;
2607
2858
  resizeObserver;
2859
+ rasterImageCanvasRendering;
2608
2860
  constructor(options) {
2609
2861
  this.container = options.container;
2610
2862
  this.scene = options.scene;
2611
2863
  this.camera = options.camera;
2864
+ this.rasterImageCanvasRendering = resolveRasterImageCanvasRenderingOptions(
2865
+ options.rasterImageCanvas
2866
+ );
2612
2867
  this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
2613
2868
  this.svg.setAttribute("width", "100%");
2614
2869
  this.svg.setAttribute("height", "100%");
@@ -2637,6 +2892,15 @@ var SvgVectorRenderer = class {
2637
2892
  this.applyInteractionAttributes(cached.g, id);
2638
2893
  }
2639
2894
  }
2895
+ setRasterImageCanvasRendering(options) {
2896
+ this.rasterImageCanvasRendering = resolveRasterImageCanvasRenderingOptions(options);
2897
+ if (!this.rasterImageCanvasRendering) {
2898
+ for (const cached of this.itemNodeCache.values()) {
2899
+ this.releaseRasterImageCanvas(cached);
2900
+ }
2901
+ }
2902
+ this.render();
2903
+ }
2640
2904
  /**
2641
2905
  * Reads container size, culls items, and updates the SVG (incrementally when possible).
2642
2906
  */
@@ -2710,6 +2974,7 @@ var SvgVectorRenderer = class {
2710
2974
  }
2711
2975
  for (const [id, cached] of this.itemNodeCache) {
2712
2976
  if (!visibleIds.has(id)) {
2977
+ this.releaseRasterImageCanvas(cached);
2713
2978
  cached.g.remove();
2714
2979
  }
2715
2980
  }
@@ -2742,6 +3007,7 @@ var SvgVectorRenderer = class {
2742
3007
  g.innerHTML = item.childrenSvg;
2743
3008
  cached.lastChildrenSvg = item.childrenSvg;
2744
3009
  }
3010
+ this.syncRasterImageCanvas(cached, item);
2745
3011
  const expectedPosition = previousNode ? previousNode.nextSibling : this.rootG.firstChild;
2746
3012
  if (expectedPosition !== g) {
2747
3013
  this.rootG.insertBefore(g, expectedPosition);
@@ -2749,6 +3015,238 @@ var SvgVectorRenderer = class {
2749
3015
  previousNode = g;
2750
3016
  }
2751
3017
  }
3018
+ syncRasterImageCanvas(cached, item) {
3019
+ const options = this.rasterImageCanvasRendering;
3020
+ if (!options || item.toolKind !== "image" || !item.imageRasterHref || !item.imageIntrinsicSize) {
3021
+ this.releaseRasterImageCanvas(cached);
3022
+ return;
3023
+ }
3024
+ const contentRect = getRasterImageContentRect(item);
3025
+ const viewportSize = {
3026
+ width: this.container.clientWidth,
3027
+ height: this.container.clientHeight
3028
+ };
3029
+ if (!contentRect || viewportSize.width <= 0 || viewportSize.height <= 0) {
3030
+ this.releaseRasterImageCanvas(cached);
3031
+ return;
3032
+ }
3033
+ const sourceSize = resolveRasterImageCanvasSourceSize({
3034
+ item,
3035
+ href: item.imageRasterHref,
3036
+ intrinsicSize: item.imageIntrinsicSize,
3037
+ contentRect,
3038
+ viewportSize,
3039
+ cameraZoom: this.camera.zoom,
3040
+ options
3041
+ });
3042
+ const targetSize = getRasterImageCanvasTargetSize({
3043
+ intrinsicSize: sourceSize,
3044
+ contentRect,
3045
+ cameraZoom: this.camera.zoom,
3046
+ devicePixelRatio: options.devicePixelRatio,
3047
+ pixelHeadroom: options.pixelHeadroom,
3048
+ maxPixelCount: options.maxPixelCount,
3049
+ maxDimension: options.maxDimension
3050
+ });
3051
+ const target = resolveRasterImageCanvasRenderTarget({
3052
+ item,
3053
+ href: item.imageRasterHref,
3054
+ intrinsicSize: item.imageIntrinsicSize,
3055
+ sourceSize,
3056
+ contentRect,
3057
+ targetSize,
3058
+ viewportSize,
3059
+ cameraZoom: this.camera.zoom,
3060
+ options
3061
+ });
3062
+ const rasterCanvas = this.ensureRasterImageCanvas(cached);
3063
+ this.positionRasterImageCanvas(rasterCanvas, target.contentRect);
3064
+ if (rasterCanvas.itemHref !== null && rasterCanvas.itemHref !== item.imageRasterHref) {
3065
+ this.clearRasterImageCanvasBitmap(rasterCanvas);
3066
+ }
3067
+ if (!shouldRedrawRasterImageCanvas({
3068
+ currentSourceKey: rasterCanvas.sourceKey,
3069
+ currentWidth: rasterCanvas.width,
3070
+ currentHeight: rasterCanvas.height,
3071
+ nextSourceKey: target.sourceKey,
3072
+ nextWidth: target.targetSize.width,
3073
+ nextHeight: target.targetSize.height,
3074
+ upscaleRedrawRatio: options.upscaleRedrawRatio
3075
+ })) {
3076
+ return;
3077
+ }
3078
+ const request = {
3079
+ itemHref: item.imageRasterHref,
3080
+ target
3081
+ };
3082
+ if (rasterCanvas.abortController) {
3083
+ if (rasterCanvas.loadingItemHref !== item.imageRasterHref) {
3084
+ rasterCanvas.abortController.abort();
3085
+ rasterCanvas.abortController = null;
3086
+ rasterCanvas.loadingItemHref = null;
3087
+ rasterCanvas.loadingSourceKey = null;
3088
+ rasterCanvas.loadingWidth = 0;
3089
+ rasterCanvas.loadingHeight = 0;
3090
+ rasterCanvas.queuedTarget = null;
3091
+ this.drawRasterImageCanvas(rasterCanvas, request);
3092
+ return;
3093
+ }
3094
+ if (rasterCanvas.loadingSourceKey === target.sourceKey && rasterCanvas.loadingWidth === target.targetSize.width && rasterCanvas.loadingHeight === target.targetSize.height) {
3095
+ return;
3096
+ }
3097
+ if (shouldRedrawRasterImageCanvas({
3098
+ currentSourceKey: rasterCanvas.loadingSourceKey,
3099
+ currentWidth: rasterCanvas.loadingWidth,
3100
+ currentHeight: rasterCanvas.loadingHeight,
3101
+ nextSourceKey: target.sourceKey,
3102
+ nextWidth: target.targetSize.width,
3103
+ nextHeight: target.targetSize.height,
3104
+ upscaleRedrawRatio: options.upscaleRedrawRatio
3105
+ })) {
3106
+ rasterCanvas.queuedTarget = request;
3107
+ }
3108
+ return;
3109
+ }
3110
+ this.drawRasterImageCanvas(rasterCanvas, request);
3111
+ }
3112
+ ensureRasterImageCanvas(cached) {
3113
+ if (cached.rasterCanvas) {
3114
+ if (!cached.rasterCanvas.foreignObject.isConnected) {
3115
+ cached.g.appendChild(cached.rasterCanvas.foreignObject);
3116
+ }
3117
+ return cached.rasterCanvas;
3118
+ }
3119
+ const foreignObject = document.createElementNS(
3120
+ "http://www.w3.org/2000/svg",
3121
+ "foreignObject"
3122
+ );
3123
+ foreignObject.setAttribute("data-canvu-raster-canvas", "true");
3124
+ foreignObject.style.pointerEvents = "none";
3125
+ const canvas = document.createElement("canvas");
3126
+ canvas.width = 1;
3127
+ canvas.height = 1;
3128
+ canvas.style.display = "block";
3129
+ canvas.style.width = "100%";
3130
+ canvas.style.height = "100%";
3131
+ foreignObject.appendChild(canvas);
3132
+ cached.g.appendChild(foreignObject);
3133
+ cached.rasterCanvas = {
3134
+ foreignObject,
3135
+ canvas,
3136
+ itemHref: null,
3137
+ sourceKey: null,
3138
+ width: 0,
3139
+ height: 0,
3140
+ loadSequence: 0,
3141
+ abortController: null,
3142
+ loadingItemHref: null,
3143
+ loadingSourceKey: null,
3144
+ loadingWidth: 0,
3145
+ loadingHeight: 0,
3146
+ queuedTarget: null
3147
+ };
3148
+ return cached.rasterCanvas;
3149
+ }
3150
+ positionRasterImageCanvas(rasterCanvas, contentRect) {
3151
+ rasterCanvas.foreignObject.setAttribute("x", String(contentRect.x));
3152
+ rasterCanvas.foreignObject.setAttribute("y", String(contentRect.y));
3153
+ rasterCanvas.foreignObject.setAttribute("width", String(contentRect.width));
3154
+ rasterCanvas.foreignObject.setAttribute("height", String(contentRect.height));
3155
+ }
3156
+ drawRasterImageCanvas(rasterCanvas, request) {
3157
+ const { target } = request;
3158
+ const width = Math.max(1, Math.round(target.targetSize.width));
3159
+ const height = Math.max(1, Math.round(target.targetSize.height));
3160
+ const sequence = rasterCanvas.loadSequence + 1;
3161
+ rasterCanvas.loadSequence = sequence;
3162
+ rasterCanvas.abortController?.abort();
3163
+ const abortController = new AbortController();
3164
+ rasterCanvas.abortController = abortController;
3165
+ rasterCanvas.loadingItemHref = request.itemHref;
3166
+ rasterCanvas.loadingSourceKey = target.sourceKey;
3167
+ rasterCanvas.loadingWidth = width;
3168
+ rasterCanvas.loadingHeight = height;
3169
+ rasterCanvas.queuedTarget = null;
3170
+ decodeRasterImage(target.href, width, height, abortController.signal).then((decoded) => {
3171
+ if (abortController.signal.aborted || rasterCanvas.loadSequence !== sequence) {
3172
+ decoded.close();
3173
+ return;
3174
+ }
3175
+ const context = rasterCanvas.canvas.getContext("2d");
3176
+ if (!context) {
3177
+ decoded.close();
3178
+ rasterCanvas.abortController = null;
3179
+ rasterCanvas.loadingItemHref = null;
3180
+ rasterCanvas.loadingSourceKey = null;
3181
+ rasterCanvas.loadingWidth = 0;
3182
+ rasterCanvas.loadingHeight = 0;
3183
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
3184
+ return;
3185
+ }
3186
+ rasterCanvas.canvas.width = decoded.width;
3187
+ rasterCanvas.canvas.height = decoded.height;
3188
+ context.clearRect(0, 0, decoded.width, decoded.height);
3189
+ decoded.draw(context);
3190
+ decoded.close();
3191
+ rasterCanvas.itemHref = request.itemHref;
3192
+ rasterCanvas.sourceKey = target.sourceKey;
3193
+ rasterCanvas.width = decoded.width;
3194
+ rasterCanvas.height = decoded.height;
3195
+ rasterCanvas.abortController = null;
3196
+ rasterCanvas.loadingItemHref = null;
3197
+ rasterCanvas.loadingSourceKey = null;
3198
+ rasterCanvas.loadingWidth = 0;
3199
+ rasterCanvas.loadingHeight = 0;
3200
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
3201
+ }).catch((error) => {
3202
+ if (abortController.signal.aborted) return;
3203
+ if (error instanceof Error && error.name === "AbortError") return;
3204
+ if (rasterCanvas.loadSequence === sequence) {
3205
+ rasterCanvas.abortController = null;
3206
+ rasterCanvas.loadingItemHref = null;
3207
+ rasterCanvas.loadingSourceKey = null;
3208
+ rasterCanvas.loadingWidth = 0;
3209
+ rasterCanvas.loadingHeight = 0;
3210
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
3211
+ }
3212
+ });
3213
+ }
3214
+ drawQueuedRasterImageCanvasTarget(rasterCanvas) {
3215
+ const queuedTarget = rasterCanvas.queuedTarget;
3216
+ if (!queuedTarget) return;
3217
+ rasterCanvas.queuedTarget = null;
3218
+ if (!shouldRedrawRasterImageCanvas({
3219
+ currentSourceKey: rasterCanvas.sourceKey,
3220
+ currentWidth: rasterCanvas.width,
3221
+ currentHeight: rasterCanvas.height,
3222
+ nextSourceKey: queuedTarget.target.sourceKey,
3223
+ nextWidth: queuedTarget.target.targetSize.width,
3224
+ nextHeight: queuedTarget.target.targetSize.height,
3225
+ upscaleRedrawRatio: this.rasterImageCanvasRendering?.upscaleRedrawRatio ?? 1
3226
+ })) {
3227
+ return;
3228
+ }
3229
+ this.drawRasterImageCanvas(rasterCanvas, queuedTarget);
3230
+ }
3231
+ clearRasterImageCanvasBitmap(rasterCanvas) {
3232
+ const context = rasterCanvas.canvas.getContext("2d");
3233
+ context?.clearRect(0, 0, rasterCanvas.canvas.width, rasterCanvas.canvas.height);
3234
+ rasterCanvas.canvas.width = 1;
3235
+ rasterCanvas.canvas.height = 1;
3236
+ rasterCanvas.itemHref = null;
3237
+ rasterCanvas.sourceKey = null;
3238
+ rasterCanvas.width = 0;
3239
+ rasterCanvas.height = 0;
3240
+ }
3241
+ releaseRasterImageCanvas(cached) {
3242
+ const rasterCanvas = cached.rasterCanvas;
3243
+ if (!rasterCanvas) return;
3244
+ rasterCanvas.abortController?.abort();
3245
+ rasterCanvas.loadSequence += 1;
3246
+ rasterCanvas.queuedTarget = null;
3247
+ rasterCanvas.foreignObject.remove();
3248
+ cached.rasterCanvas = void 0;
3249
+ }
2752
3250
  applyInteractionAttributes(g, itemId) {
2753
3251
  g.setAttribute(
2754
3252
  "data-canvu-selected",
@@ -2761,6 +3259,9 @@ var SvgVectorRenderer = class {
2761
3259
  }
2762
3260
  destroy() {
2763
3261
  this.resizeObserver.disconnect();
3262
+ for (const cached of this.itemNodeCache.values()) {
3263
+ this.releaseRasterImageCanvas(cached);
3264
+ }
2764
3265
  this.itemNodeCache.clear();
2765
3266
  this.liveOverlay = null;
2766
3267
  this.svg.remove();