@snowcone-app/canvas 0.1.10 → 0.1.13
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/{CanvasStateV1-BmE5V6me.cjs → CanvasStateV1-C4hC1MCe.cjs} +5 -5
- package/dist/{CanvasStateV1-BmE5V6me.cjs.map → CanvasStateV1-C4hC1MCe.cjs.map} +1 -1
- package/dist/{CanvasStateV1-CD3Q94F4.js → CanvasStateV1-CJU_xYW5.js} +3 -3
- package/dist/{CanvasStateV1-CD3Q94F4.js.map → CanvasStateV1-CJU_xYW5.js.map} +1 -1
- package/dist/{HybridHistoryManager-BV6XV0nD.js → HybridHistoryManager-jBBnVim8.js} +54 -54
- package/dist/{HybridHistoryManager-BV6XV0nD.js.map → HybridHistoryManager-jBBnVim8.js.map} +1 -1
- package/dist/{ElementFactory-Ckv6sSev.js → ImportManager-Oqu2yB54.js} +595 -378
- package/dist/ImportManager-Oqu2yB54.js.map +1 -0
- package/dist/{ElementFactory-DEjwp-Wg.cjs → ImportManager-W1eWhfyM.cjs} +5 -5
- package/dist/ImportManager-W1eWhfyM.cjs.map +1 -0
- package/dist/ThemeContext-BMNQKl1c.cjs +2 -0
- package/dist/{ThemeContext-4mJ_y0Me.cjs.map → ThemeContext-BMNQKl1c.cjs.map} +1 -1
- package/dist/ThemeContext-wj-wSO7J.js +1158 -0
- package/dist/{ThemeContext-H0Z-MqqR.js.map → ThemeContext-wj-wSO7J.js.map} +1 -1
- package/dist/advanced.js +5 -32
- package/dist/advanced.js.map +1 -1
- package/dist/advanced.mjs +588 -15069
- package/dist/advanced.mjs.map +1 -1
- package/dist/components/embed/KitLayout.d.ts +22 -0
- package/dist/components/embed/UndoRedoControls.d.ts +3 -0
- package/dist/compose-Dqh2f8tS.js +22222 -0
- package/dist/compose-Dqh2f8tS.js.map +1 -0
- package/dist/compose-HDJp4Z_d.cjs +60 -0
- package/dist/compose-HDJp4Z_d.cjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +600 -516
- package/dist/index.mjs.map +1 -1
- package/dist/internals.js +1 -1
- package/dist/internals.js.map +1 -1
- package/dist/internals.mjs +101 -102
- package/dist/internals.mjs.map +1 -1
- package/dist/style.css.d.ts +4 -0
- package/dist/testing.js +1 -1
- package/dist/testing.mjs +11 -11
- package/package.json +8 -4
- package/dist/ElementFactory-Ckv6sSev.js.map +0 -1
- package/dist/ElementFactory-DEjwp-Wg.cjs.map +0 -1
- package/dist/ImportManager-64OYjELO.js +0 -222
- package/dist/ImportManager-64OYjELO.js.map +0 -1
- package/dist/ImportManager-wSzrR-5a.cjs +0 -2
- package/dist/ImportManager-wSzrR-5a.cjs.map +0 -1
- package/dist/ThemeContext-4mJ_y0Me.cjs +0 -2
- package/dist/ThemeContext-H0Z-MqqR.js +0 -1077
- package/dist/compose-DHBRwi_A.cjs +0 -33
- package/dist/compose-DHBRwi_A.cjs.map +0 -1
- package/dist/compose-DIPiisIw.js +0 -7690
- package/dist/compose-DIPiisIw.js.map +0 -1
package/dist/internals.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./ImportManager-W1eWhfyM.cjs"),o=require("./HybridHistoryManager-BXD93pp8.cjs"),p=require("./CanvasStateV1-C4hC1MCe.cjs");function M(r,e,g){var t,s;r.save(),r.translate(e.x,e.y),e.rotation&&r.rotate(-e.rotation*Math.PI/180);let a=1,d=1;if(e.flipHorizontal&&(a=-1),e.flipVertical&&(d=-1),(a!==1||d!==1)&&r.scale(a,d),e.opacity!==void 0&&e.opacity!==1&&(r.globalAlpha=e.opacity),e.borderRadius&&e.borderRadius>0){const n=Math.min(e.borderRadius/100*Math.min(e.width,e.height),e.width/2,e.height/2);r.beginPath();const i=-e.width/2,h=-e.height/2,c=e.width,f=e.height;r.moveTo(i+n,h),r.lineTo(i+c-n,h),r.arcTo(i+c,h,i+c,h+n,n),r.lineTo(i+c,h+f-n),r.arcTo(i+c,h+f,i+c-n,h+f,n),r.lineTo(i+n,h+f),r.arcTo(i,h+f,i,h+f-n,n),r.lineTo(i,h+n),r.arcTo(i,h,i+n,h,n),r.closePath(),r.clip()}if(e.cropX!==void 0&&e.cropWidth!==void 0?r.drawImage(g,e.cropX,e.cropY||0,e.cropWidth,e.cropHeight||g.height,-e.width/2,-e.height/2,e.width,e.height):r.drawImage(g,-e.width/2,-e.height/2,e.width,e.height),r.restore(),(t=e.stroke)!=null&&t.enabled){const n=((s=e.knockoutParts)==null?void 0:s.stroke)===!0,i={x:e.x,y:e.y,rotation:e.rotation,stroke:e.stroke,knockoutParts:e.knockoutParts,transformData:{type:"image",width:e.width,height:e.height,borderRadius:e.borderRadius||0}};if(n){const h=r.canvas;let c;if(typeof OffscreenCanvas<"u")c=new OffscreenCanvas(h.width,h.height);else if(typeof document<"u")c=document.createElement("canvas"),c.width=h.width,c.height=h.height;else{o.renderImageStroke(r,i);return}const f=c.getContext("2d");if(!f){o.renderImageStroke(r,i);return}o.renderImageStroke(f,i,{isKnockout:!0}),r.save(),r.globalCompositeOperation="destination-out",r.drawImage(c,0,0),r.restore()}else o.renderImageStroke(r,i)}}function k(r,e){if(typeof OffscreenCanvas<"u")return new OffscreenCanvas(r,e);const g=document.createElement("canvas");return g.width=r,g.height=e,g}function y(r,e){var t;const g=e.opacity??1,a=!!((t=e.stroke)!=null&&t.enabled);g<1&&a?C(r,e,g):u(r,e,g)}function C(r,e,g){var f;const a=e.transformData,t=(((f=e.stroke)==null?void 0:f.width)||2)+2,s=Math.ceil(a.width+t*2),n=Math.ceil(a.height+t*2),i=k(s,n),h=i.getContext("2d");if(!h){u(r,e,g);return}const c={...e,x:s/2,y:n/2};u(h,c,1),r.save(),r.translate(e.x,e.y),e.rotation&&r.rotate(-e.rotation*Math.PI/180),r.globalAlpha=g,r.drawImage(i,-s/2,-n/2),r.restore()}function u(r,e,g){var t;const a=e.transformData,d=a.fillOpacity??1;if(r.save(),r.translate(e.x,e.y),e.rotation&&r.rotate(-e.rotation*Math.PI/180),r.globalAlpha=g*d,r.fillStyle=a.fillColor||"#3b82f6",r.beginPath(),S(r,a),r.fill(),r.restore(),(t=e.stroke)!=null&&t.enabled){r.save(),r.translate(e.x,e.y),e.rotation&&r.rotate(-e.rotation*Math.PI/180);const s=e.stroke;r.globalAlpha=g*(s.opacity??1),r.strokeStyle=s.color||"#000000",r.lineWidth=s.width||2,r.lineCap=s.lineCap||"round",r.lineJoin=s.lineJoin||"round",r.beginPath(),S(r,a),r.stroke(),r.restore()}}function S(r,e){const{shapeType:g,width:a,height:d}=e;switch(g){case"rectangle":{const t=e.borderRadius||0,s=-a/2,n=-d/2;if(t>0){const i=Math.min(t/100*Math.min(a,d),a/2,d/2);r.roundRect(s,n,a,d,i)}else r.rect(s,n,a,d);break}case"circle":{const t=Math.min(a,d)/2;r.arc(0,0,t,0,Math.PI*2);break}case"ellipse":{r.ellipse(0,0,a/2,d/2,0,0,Math.PI*2);break}case"triangle":{const t=a/2,s=d/2;r.moveTo(0,-s),r.lineTo(t,s),r.lineTo(-t,s),r.closePath();break}case"polygon":{const t=e.sides||5,s=Math.min(a,d)/2;for(let n=0;n<t;n++){const i=n*2*Math.PI/t-Math.PI/2,h=s*Math.cos(i),c=s*Math.sin(i);n===0?r.moveTo(h,c):r.lineTo(h,c)}r.closePath();break}case"star":{const t=e.points||5,s=Math.min(a,d)/2,n=s*(e.innerRadius||.4);for(let i=0;i<t*2;i++){const h=i*Math.PI/t-Math.PI/2,c=i%2===0?s:n,f=c*Math.cos(h),T=c*Math.sin(h);i===0?r.moveTo(f,T):r.lineTo(f,T)}r.closePath();break}case"line":{const t=a/2,s=d/2;r.rect(-t,-s,a,d);break}default:r.rect(-a/2,-d/2,a,d)}}exports.AlignmentSnapSystem=l.AlignmentSnapSystem;exports.ArtboardRenderer=l.ArtboardRenderer;exports.CanvasRenderer=l.CanvasRenderer;exports.DEFAULT_MAX_BITMAP_DIMENSION=l.DEFAULT_MAX_BITMAP_DIMENSION;exports.ExportManager=l.ExportManager;exports.ImportManager=l.ImportManager;exports.InteractionStateMachine=l.InteractionStateMachine;exports.ResizePipeline=l.ResizePipeline;exports.SpacingSystem=l.SpacingSystem;exports.TransformHandles=l.TransformHandles;exports.WorkerExportManager=l.WorkerExportManager;exports.clearImageBitmapCache=l.clearImageBitmapCache;exports.clearMaskCache=l.clearMaskCache;exports.clearRegisteredBitmapKeys=l.clearRegisteredBitmapKeys;exports.getSharedWorkerExportManager=l.getSharedWorkerExportManager;exports.invalidateMaskCache=l.invalidateMaskCache;exports.removeFromImageBitmapCache=l.removeFromImageBitmapCache;exports.renderWithKnockout=l.renderWithKnockout;exports.renderWithMasks=l.renderWithMasks;exports.terminateSharedWorkerExportManager=l.terminateSharedWorkerExportManager;exports.unregisterElementBitmaps=l.unregisterElementBitmaps;exports.ArchTransform=o.ArchTransform;exports.ArtboardManager=o.ArtboardManager;exports.AscendTransform=o.AscendTransform;exports.CircleTransform=o.CircleTransform;exports.CustomTransform=o.CustomTransform;exports.ElementStore=o.ElementStore;exports.FlagTransform=o.FlagTransform;exports.HybridHistoryManager=o.HybridHistoryManager;exports.LeanTransform=o.LeanTransform;exports.LogLevel=o.LogLevel;exports.WaveTransform=o.WaveTransform;exports.applySpaceLayoutRules=o.applySpaceLayoutRules;exports.applyStrokeStyle=o.applyStrokeStyle;exports.buildFontString=o.buildFontString;exports.calculateFixedCornerPosition=o.calculateFixedCornerPosition;exports.calculateResizeHandles=o.calculateResizeHandles;exports.calculateRotationHandlePosition=o.calculateRotationHandlePosition;exports.createCirclePath=o.createCirclePath;exports.createImagePath=o.createImagePath;exports.createLogger=o.createLogger;exports.createRectPath=o.createRectPath;exports.createTextPath=o.createTextPath;exports.getFontMetrics=o.getFontMetrics;exports.hitTestCircle=o.hitTestCircle;exports.hitTestRect=o.hitTestRect;exports.logger=o.logger;exports.measureTextWidth=o.measureTextWidth$1;exports.renderCustomTransform=o.renderCustomTransform;exports.renderImageStroke=o.renderImageStroke;exports.renderMultilineText=o.renderMultilineText;exports.renderPathStroke=o.renderPathStroke;exports.renderRichTextFillOnly=o.renderRichTextFillOnly;exports.renderTextElement=o.renderTextElement;exports.renderTextFillOnly=o.renderTextFillOnly;exports.renderTextStroke=o.renderTextStroke;exports.splitRichTextIntoLines=o.splitRichTextIntoLines;exports.wrapRichTextSpans=o.wrapRichTextSpans;exports.wrapText=o.wrapText$1;exports.AnyElementConfigSchema=p.AnyElementConfigSchema;exports.AnyTransformDataSchema=p.AnyTransformDataSchema;exports.CanvasStateV1Schema=p.CanvasStateV1Schema;exports.SerializedArtboardSchema=p.SerializedArtboardSchema;exports.renderImageElement=M;exports.renderShapeElement=y;
|
|
2
2
|
//# sourceMappingURL=internals.js.map
|
package/dist/internals.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internals.js","sources":["../src/rendering/image-renderer.ts","../src/rendering/shape-renderer.ts"],"sourcesContent":["/**\n * Image Renderer - Image element rendering with crop, flip, border radius, and stroke.\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n */\n\nimport type { ImageElementConfig } from '../types/index.js';\nimport { renderImageStroke } from './StrokeRenderer.js';\nimport type { RenderContext, SerializedImageElement } from './renderer-types.js';\n\n/**\n * Render an image element using ImageBitmap\n * Works in both main thread and worker\n */\nexport function renderImageElement(\n ctx: RenderContext,\n elementData: SerializedImageElement,\n imageBitmap: ImageBitmap\n): void {\n ctx.save();\n\n // Translate to element position\n ctx.translate(elementData.x, elementData.y);\n\n // Apply rotation (negative for clockwise)\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Apply flip transformations\n let scaleX = 1;\n let scaleY = 1;\n if (elementData.flipHorizontal) scaleX = -1;\n if (elementData.flipVertical) scaleY = -1;\n if (scaleX !== 1 || scaleY !== 1) {\n ctx.scale(scaleX, scaleY);\n }\n\n // Apply opacity if specified\n if (elementData.opacity !== undefined && elementData.opacity !== 1) {\n ctx.globalAlpha = elementData.opacity;\n }\n\n // Apply border radius if specified (borderRadius is stored as percentage 0-100)\n if (elementData.borderRadius && elementData.borderRadius > 0) {\n const radius = Math.min(\n (elementData.borderRadius / 100) * Math.min(elementData.width, elementData.height),\n elementData.width / 2,\n elementData.height / 2\n );\n\n // Create clipping path for rounded corners\n ctx.beginPath();\n const x = -elementData.width / 2;\n const y = -elementData.height / 2;\n const w = elementData.width;\n const h = elementData.height;\n\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n ctx.clip();\n }\n\n // Draw the image\n if (elementData.cropX !== undefined && elementData.cropWidth !== undefined) {\n // Draw with crop\n ctx.drawImage(\n imageBitmap,\n elementData.cropX,\n elementData.cropY || 0,\n elementData.cropWidth,\n elementData.cropHeight || imageBitmap.height,\n -elementData.width / 2,\n -elementData.height / 2,\n elementData.width,\n elementData.height\n );\n } else {\n // Draw without crop (centered)\n ctx.drawImage(imageBitmap, -elementData.width / 2, -elementData.height / 2, elementData.width, elementData.height);\n }\n\n ctx.restore();\n\n // Render stroke if enabled (after restore to apply fresh transforms)\n if (elementData.stroke?.enabled) {\n const hasKnockoutStroke = elementData.knockoutParts?.stroke === true;\n\n const imageConfig: ImageElementConfig = {\n transformType: 'image',\n x: elementData.x,\n y: elementData.y,\n rotation: elementData.rotation,\n stroke: elementData.stroke,\n knockoutParts: elementData.knockoutParts,\n transformData: {\n type: 'image',\n width: elementData.width,\n height: elementData.height,\n borderRadius: elementData.borderRadius || 0,\n },\n };\n\n if (hasKnockoutStroke) {\n // For knockout stroke, use offscreen canvas approach\n const canvas = ctx.canvas;\n let offscreen: HTMLCanvasElement | OffscreenCanvas;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n offscreen = new OffscreenCanvas(canvas.width, canvas.height);\n } else if (typeof document !== 'undefined') {\n offscreen = document.createElement('canvas');\n offscreen.width = canvas.width;\n offscreen.height = canvas.height;\n } else {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n // Render the stroke to the offscreen canvas with knockout flag\n renderImageStroke(offCtx, imageConfig, { isKnockout: true });\n\n // Composite with destination-out\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n ctx.drawImage(offscreen as CanvasImageSource, 0, 0);\n ctx.restore();\n } else {\n // Normal stroke\n renderImageStroke(ctx, imageConfig);\n }\n }\n}\n","/**\n * Shape Renderer - Shape element rendering (rectangle, circle, ellipse, triangle, etc.)\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n *\n * Opacity strategy: When a shape has both element-level opacity AND a stroke,\n * we render fill+stroke at full opacity on a temporary canvas, then composite\n * the result at the element's opacity. This prevents fill/stroke overlap from\n * compounding (e.g., 50% fill + 50% stroke overlap ≠ 75% opaque).\n */\n\nimport type { RenderContext, SerializedShapeElement } from './renderer-types.js';\n\ntype CanvasLike = HTMLCanvasElement | OffscreenCanvas;\n\nfunction createTempCanvas(width: number, height: number): CanvasLike {\n if (typeof OffscreenCanvas !== 'undefined') {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Render a shape element\n * Works in both main thread and worker\n */\nexport function renderShapeElement(ctx: RenderContext, elementData: SerializedShapeElement): void {\n const elementOpacity = elementData.opacity ?? 1;\n const hasStroke = !!elementData.stroke?.enabled;\n const needsOffscreen = elementOpacity < 1 && hasStroke;\n\n if (needsOffscreen) {\n // Render fill+stroke at full opacity on a temp canvas, then composite\n renderShapeWithOffscreen(ctx, elementData, elementOpacity);\n } else {\n // No compounding risk — render directly\n renderShapeDirect(ctx, elementData, elementOpacity);\n }\n}\n\n/**\n * Render shape via temporary canvas to avoid fill/stroke opacity compounding.\n */\nfunction renderShapeWithOffscreen(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const td = elementData.transformData;\n const strokeWidth = elementData.stroke?.width || 2;\n // Pad temp canvas to fit the stroke (strokes extend beyond the shape bounds)\n const padding = strokeWidth + 2;\n const offW = Math.ceil(td.width + padding * 2);\n const offH = Math.ceil(td.height + padding * 2);\n\n const offCanvas = createTempCanvas(offW, offH);\n const offCtx = offCanvas.getContext('2d') as RenderContext;\n if (!offCtx) {\n // Fallback to direct render\n renderShapeDirect(ctx, elementData, elementOpacity);\n return;\n }\n\n // Render at center of temp canvas with full opacity (elementOpacity = 1)\n const tempData: SerializedShapeElement = {\n ...elementData,\n x: offW / 2,\n y: offH / 2,\n opacity: 1,\n };\n renderShapeDirect(offCtx, tempData, 1);\n\n // Composite temp canvas onto main canvas at element opacity\n ctx.save();\n\n // Position: elementData.(x,y) is the shape center, temp canvas center is (offW/2, offH/2)\n // We need to account for rotation around the element center\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n ctx.globalAlpha = elementOpacity;\n ctx.drawImage(offCanvas, -offW / 2, -offH / 2);\n ctx.restore();\n}\n\n/**\n * Render shape directly onto ctx (no offscreen). Used when there's no\n * compounding risk, or as the inner render for the offscreen path.\n */\nfunction renderShapeDirect(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const transformData = elementData.transformData;\n const fillOpacity = transformData.fillOpacity ?? 1;\n\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Fill\n ctx.globalAlpha = elementOpacity * fillOpacity;\n ctx.fillStyle = transformData.fillColor || '#3b82f6';\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.fill();\n ctx.restore();\n\n // Stroke\n if (elementData.stroke?.enabled) {\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n const stroke = elementData.stroke;\n ctx.globalAlpha = elementOpacity * (stroke.opacity ?? 1);\n ctx.strokeStyle = stroke.color || '#000000';\n ctx.lineWidth = stroke.width || 2;\n ctx.lineCap = stroke.lineCap || 'round';\n ctx.lineJoin = stroke.lineJoin || 'round';\n\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.stroke();\n ctx.restore();\n }\n}\n\n/**\n * Trace the shape path (without fill/stroke) — reusable for both fill and stroke passes.\n */\nfunction traceShapePath(\n ctx: RenderContext,\n transformData: SerializedShapeElement['transformData']\n): void {\n const { shapeType, width, height } = transformData;\n\n switch (shapeType) {\n case 'rectangle': {\n const borderRadius = transformData.borderRadius || 0;\n const x = -width / 2;\n const y = -height / 2;\n\n if (borderRadius > 0) {\n const radius = Math.min((borderRadius / 100) * Math.min(width, height), width / 2, height / 2);\n ctx.roundRect(x, y, width, height, radius);\n } else {\n ctx.rect(x, y, width, height);\n }\n break;\n }\n\n case 'circle': {\n const radius = Math.min(width, height) / 2;\n ctx.arc(0, 0, radius, 0, Math.PI * 2);\n break;\n }\n\n case 'ellipse': {\n ctx.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n }\n\n case 'triangle': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.moveTo(0, -halfHeight);\n ctx.lineTo(halfWidth, halfHeight);\n ctx.lineTo(-halfWidth, halfHeight);\n ctx.closePath();\n break;\n }\n\n case 'polygon': {\n const sides = transformData.sides || 5;\n const radius = Math.min(width, height) / 2;\n for (let i = 0; i < sides; i++) {\n const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;\n const px = radius * Math.cos(angle);\n const py = radius * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'star': {\n const points = transformData.points || 5;\n const outerRadius = Math.min(width, height) / 2;\n const innerRadius = outerRadius * (transformData.innerRadius || 0.4);\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const px = r * Math.cos(angle);\n const py = r * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'line': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.rect(-halfWidth, -halfHeight, width, height);\n break;\n }\n\n default:\n ctx.rect(-width / 2, -height / 2, width, height);\n }\n}\n"],"names":["renderImageElement","ctx","elementData","imageBitmap","scaleX","scaleY","radius","x","y","w","h","_a","hasKnockoutStroke","_b","imageConfig","canvas","offscreen","renderImageStroke","offCtx","createTempCanvas","width","height","renderShapeElement","elementOpacity","hasStroke","renderShapeWithOffscreen","renderShapeDirect","td","padding","offW","offH","offCanvas","tempData","transformData","fillOpacity","traceShapePath","stroke","shapeType","borderRadius","halfWidth","halfHeight","sides","i","angle","px","py","points","outerRadius","innerRadius","r"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"internals.js","sources":["../src/rendering/image-renderer.ts","../src/rendering/shape-renderer.ts"],"sourcesContent":["/**\n * Image Renderer - Image element rendering with crop, flip, border radius, and stroke.\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n */\n\nimport type { ImageElementConfig } from '../types/index.js';\nimport { renderImageStroke } from './StrokeRenderer.js';\nimport type { RenderContext, SerializedImageElement } from './renderer-types.js';\n\n/**\n * Render an image element using ImageBitmap\n * Works in both main thread and worker\n */\nexport function renderImageElement(\n ctx: RenderContext,\n elementData: SerializedImageElement,\n imageBitmap: ImageBitmap\n): void {\n ctx.save();\n\n // Translate to element position\n ctx.translate(elementData.x, elementData.y);\n\n // Apply rotation (negative for clockwise)\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Apply flip transformations\n let scaleX = 1;\n let scaleY = 1;\n if (elementData.flipHorizontal) scaleX = -1;\n if (elementData.flipVertical) scaleY = -1;\n if (scaleX !== 1 || scaleY !== 1) {\n ctx.scale(scaleX, scaleY);\n }\n\n // Apply opacity if specified\n if (elementData.opacity !== undefined && elementData.opacity !== 1) {\n ctx.globalAlpha = elementData.opacity;\n }\n\n // Apply border radius if specified (borderRadius is stored as percentage 0-100)\n if (elementData.borderRadius && elementData.borderRadius > 0) {\n const radius = Math.min(\n (elementData.borderRadius / 100) * Math.min(elementData.width, elementData.height),\n elementData.width / 2,\n elementData.height / 2\n );\n\n // Create clipping path for rounded corners\n ctx.beginPath();\n const x = -elementData.width / 2;\n const y = -elementData.height / 2;\n const w = elementData.width;\n const h = elementData.height;\n\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n ctx.clip();\n }\n\n // Draw the image\n if (elementData.cropX !== undefined && elementData.cropWidth !== undefined) {\n // Draw with crop\n ctx.drawImage(\n imageBitmap,\n elementData.cropX,\n elementData.cropY || 0,\n elementData.cropWidth,\n elementData.cropHeight || imageBitmap.height,\n -elementData.width / 2,\n -elementData.height / 2,\n elementData.width,\n elementData.height\n );\n } else {\n // Draw without crop (centered)\n ctx.drawImage(imageBitmap, -elementData.width / 2, -elementData.height / 2, elementData.width, elementData.height);\n }\n\n ctx.restore();\n\n // Render stroke if enabled (after restore to apply fresh transforms)\n if (elementData.stroke?.enabled) {\n const hasKnockoutStroke = elementData.knockoutParts?.stroke === true;\n\n const imageConfig: ImageElementConfig = {\n transformType: 'image',\n x: elementData.x,\n y: elementData.y,\n rotation: elementData.rotation,\n stroke: elementData.stroke,\n knockoutParts: elementData.knockoutParts,\n transformData: {\n type: 'image',\n width: elementData.width,\n height: elementData.height,\n borderRadius: elementData.borderRadius || 0,\n },\n };\n\n if (hasKnockoutStroke) {\n // For knockout stroke, use offscreen canvas approach\n const canvas = ctx.canvas;\n let offscreen: HTMLCanvasElement | OffscreenCanvas;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n offscreen = new OffscreenCanvas(canvas.width, canvas.height);\n } else if (typeof document !== 'undefined') {\n offscreen = document.createElement('canvas');\n offscreen.width = canvas.width;\n offscreen.height = canvas.height;\n } else {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n // Render the stroke to the offscreen canvas with knockout flag\n renderImageStroke(offCtx, imageConfig, { isKnockout: true });\n\n // Composite with destination-out\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n ctx.drawImage(offscreen as CanvasImageSource, 0, 0);\n ctx.restore();\n } else {\n // Normal stroke\n renderImageStroke(ctx, imageConfig);\n }\n }\n}\n","/**\n * Shape Renderer - Shape element rendering (rectangle, circle, ellipse, triangle, etc.)\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n *\n * Opacity strategy: When a shape has both element-level opacity AND a stroke,\n * we render fill+stroke at full opacity on a temporary canvas, then composite\n * the result at the element's opacity. This prevents fill/stroke overlap from\n * compounding (e.g., 50% fill + 50% stroke overlap ≠ 75% opaque).\n */\n\nimport type { RenderContext, SerializedShapeElement } from './renderer-types.js';\n\ntype CanvasLike = HTMLCanvasElement | OffscreenCanvas;\n\nfunction createTempCanvas(width: number, height: number): CanvasLike {\n if (typeof OffscreenCanvas !== 'undefined') {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Render a shape element\n * Works in both main thread and worker\n */\nexport function renderShapeElement(ctx: RenderContext, elementData: SerializedShapeElement): void {\n const elementOpacity = elementData.opacity ?? 1;\n const hasStroke = !!elementData.stroke?.enabled;\n const needsOffscreen = elementOpacity < 1 && hasStroke;\n\n if (needsOffscreen) {\n // Render fill+stroke at full opacity on a temp canvas, then composite\n renderShapeWithOffscreen(ctx, elementData, elementOpacity);\n } else {\n // No compounding risk — render directly\n renderShapeDirect(ctx, elementData, elementOpacity);\n }\n}\n\n/**\n * Render shape via temporary canvas to avoid fill/stroke opacity compounding.\n */\nfunction renderShapeWithOffscreen(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const td = elementData.transformData;\n const strokeWidth = elementData.stroke?.width || 2;\n // Pad temp canvas to fit the stroke (strokes extend beyond the shape bounds)\n const padding = strokeWidth + 2;\n const offW = Math.ceil(td.width + padding * 2);\n const offH = Math.ceil(td.height + padding * 2);\n\n const offCanvas = createTempCanvas(offW, offH);\n const offCtx = offCanvas.getContext('2d') as RenderContext;\n if (!offCtx) {\n // Fallback to direct render\n renderShapeDirect(ctx, elementData, elementOpacity);\n return;\n }\n\n // Render at center of temp canvas with full opacity (elementOpacity = 1)\n const tempData: SerializedShapeElement = {\n ...elementData,\n x: offW / 2,\n y: offH / 2,\n opacity: 1,\n };\n renderShapeDirect(offCtx, tempData, 1);\n\n // Composite temp canvas onto main canvas at element opacity\n ctx.save();\n\n // Position: elementData.(x,y) is the shape center, temp canvas center is (offW/2, offH/2)\n // We need to account for rotation around the element center\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n ctx.globalAlpha = elementOpacity;\n ctx.drawImage(offCanvas, -offW / 2, -offH / 2);\n ctx.restore();\n}\n\n/**\n * Render shape directly onto ctx (no offscreen). Used when there's no\n * compounding risk, or as the inner render for the offscreen path.\n */\nfunction renderShapeDirect(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const transformData = elementData.transformData;\n const fillOpacity = transformData.fillOpacity ?? 1;\n\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Fill\n ctx.globalAlpha = elementOpacity * fillOpacity;\n ctx.fillStyle = transformData.fillColor || '#3b82f6';\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.fill();\n ctx.restore();\n\n // Stroke\n if (elementData.stroke?.enabled) {\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n const stroke = elementData.stroke;\n ctx.globalAlpha = elementOpacity * (stroke.opacity ?? 1);\n ctx.strokeStyle = stroke.color || '#000000';\n ctx.lineWidth = stroke.width || 2;\n ctx.lineCap = stroke.lineCap || 'round';\n ctx.lineJoin = stroke.lineJoin || 'round';\n\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.stroke();\n ctx.restore();\n }\n}\n\n/**\n * Trace the shape path (without fill/stroke) — reusable for both fill and stroke passes.\n */\nfunction traceShapePath(\n ctx: RenderContext,\n transformData: SerializedShapeElement['transformData']\n): void {\n const { shapeType, width, height } = transformData;\n\n switch (shapeType) {\n case 'rectangle': {\n const borderRadius = transformData.borderRadius || 0;\n const x = -width / 2;\n const y = -height / 2;\n\n if (borderRadius > 0) {\n const radius = Math.min((borderRadius / 100) * Math.min(width, height), width / 2, height / 2);\n ctx.roundRect(x, y, width, height, radius);\n } else {\n ctx.rect(x, y, width, height);\n }\n break;\n }\n\n case 'circle': {\n const radius = Math.min(width, height) / 2;\n ctx.arc(0, 0, radius, 0, Math.PI * 2);\n break;\n }\n\n case 'ellipse': {\n ctx.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n }\n\n case 'triangle': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.moveTo(0, -halfHeight);\n ctx.lineTo(halfWidth, halfHeight);\n ctx.lineTo(-halfWidth, halfHeight);\n ctx.closePath();\n break;\n }\n\n case 'polygon': {\n const sides = transformData.sides || 5;\n const radius = Math.min(width, height) / 2;\n for (let i = 0; i < sides; i++) {\n const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;\n const px = radius * Math.cos(angle);\n const py = radius * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'star': {\n const points = transformData.points || 5;\n const outerRadius = Math.min(width, height) / 2;\n const innerRadius = outerRadius * (transformData.innerRadius || 0.4);\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const px = r * Math.cos(angle);\n const py = r * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'line': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.rect(-halfWidth, -halfHeight, width, height);\n break;\n }\n\n default:\n ctx.rect(-width / 2, -height / 2, width, height);\n }\n}\n"],"names":["renderImageElement","ctx","elementData","imageBitmap","scaleX","scaleY","radius","x","y","w","h","_a","hasKnockoutStroke","_b","imageConfig","canvas","offscreen","renderImageStroke","offCtx","createTempCanvas","width","height","renderShapeElement","elementOpacity","hasStroke","renderShapeWithOffscreen","renderShapeDirect","td","padding","offW","offH","offCanvas","tempData","transformData","fillOpacity","traceShapePath","stroke","shapeType","borderRadius","halfWidth","halfHeight","sides","i","angle","px","py","points","outerRadius","innerRadius","r"],"mappings":"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"}
|
package/dist/internals.mjs
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ab as l } from "./HybridHistoryManager-
|
|
3
|
-
import { ac as V, ad as Y, ae as
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
function M(o, r, c) {
|
|
1
|
+
import { j as C, A as P, C as w, q as I, m as R, I as A, k as W, R as E, S as O, T as H, W as F, s as L, t as z, u as B, v as K, w as X, x as m, y as J, z as _, B as j, F as q } from "./ImportManager-Oqu2yB54.js";
|
|
2
|
+
import { ab as l } from "./HybridHistoryManager-jBBnVim8.js";
|
|
3
|
+
import { ac as V, ad as Y, ae as G, af as U, a0 as Q, ag as Z, ah as $, ai as x, aj as D, ak as ss, al as rs, am as os, an as as, ao as is, ap as es, aq as ns, ar as ts, as as hs, at as ds, c as cs, au as fs, av as ls, aw as ps, ax as gs, ay as us, az as ks, aA as Ts, aB as ys, aC as Ms, aD as Ss, aE as bs, aF as vs, aG as Cs, aH as Ps, aI as ws, aJ as Is, aK as Rs } from "./HybridHistoryManager-jBBnVim8.js";
|
|
4
|
+
import { A as Ws, a as Es, C as Os, S as Hs } from "./CanvasStateV1-CJU_xYW5.js";
|
|
5
|
+
function M(s, r, c) {
|
|
7
6
|
var e, n;
|
|
8
|
-
|
|
7
|
+
s.save(), s.translate(r.x, r.y), r.rotation && s.rotate(-r.rotation * Math.PI / 180);
|
|
9
8
|
let i = 1, h = 1;
|
|
10
|
-
if (r.flipHorizontal && (i = -1), r.flipVertical && (h = -1), (i !== 1 || h !== 1) &&
|
|
9
|
+
if (r.flipHorizontal && (i = -1), r.flipVertical && (h = -1), (i !== 1 || h !== 1) && s.scale(i, h), r.opacity !== void 0 && r.opacity !== 1 && (s.globalAlpha = r.opacity), r.borderRadius && r.borderRadius > 0) {
|
|
11
10
|
const a = Math.min(
|
|
12
11
|
r.borderRadius / 100 * Math.min(r.width, r.height),
|
|
13
12
|
r.width / 2,
|
|
14
13
|
r.height / 2
|
|
15
14
|
);
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
15
|
+
s.beginPath();
|
|
16
|
+
const o = -r.width / 2, t = -r.height / 2, d = r.width, f = r.height;
|
|
17
|
+
s.moveTo(o + a, t), s.lineTo(o + d - a, t), s.arcTo(o + d, t, o + d, t + a, a), s.lineTo(o + d, t + f - a), s.arcTo(o + d, t + f, o + d - a, t + f, a), s.lineTo(o + a, t + f), s.arcTo(o, t + f, o, t + f - a, a), s.lineTo(o, t + a), s.arcTo(o, t, o + a, t, a), s.closePath(), s.clip();
|
|
19
18
|
}
|
|
20
|
-
if (r.cropX !== void 0 && r.cropWidth !== void 0 ?
|
|
19
|
+
if (r.cropX !== void 0 && r.cropWidth !== void 0 ? s.drawImage(
|
|
21
20
|
c,
|
|
22
21
|
r.cropX,
|
|
23
22
|
r.cropY || 0,
|
|
@@ -27,8 +26,8 @@ function M(o, r, c) {
|
|
|
27
26
|
-r.height / 2,
|
|
28
27
|
r.width,
|
|
29
28
|
r.height
|
|
30
|
-
) :
|
|
31
|
-
const a = ((n = r.knockoutParts) == null ? void 0 : n.stroke) === !0,
|
|
29
|
+
) : s.drawImage(c, -r.width / 2, -r.height / 2, r.width, r.height), s.restore(), (e = r.stroke) != null && e.enabled) {
|
|
30
|
+
const a = ((n = r.knockoutParts) == null ? void 0 : n.stroke) === !0, o = {
|
|
32
31
|
x: r.x,
|
|
33
32
|
y: r.y,
|
|
34
33
|
rotation: r.rotation,
|
|
@@ -42,42 +41,42 @@ function M(o, r, c) {
|
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
43
|
if (a) {
|
|
45
|
-
const t =
|
|
44
|
+
const t = s.canvas;
|
|
46
45
|
let d;
|
|
47
46
|
if (typeof OffscreenCanvas < "u")
|
|
48
47
|
d = new OffscreenCanvas(t.width, t.height);
|
|
49
48
|
else if (typeof document < "u")
|
|
50
49
|
d = document.createElement("canvas"), d.width = t.width, d.height = t.height;
|
|
51
50
|
else {
|
|
52
|
-
l(
|
|
51
|
+
l(s, o);
|
|
53
52
|
return;
|
|
54
53
|
}
|
|
55
54
|
const f = d.getContext("2d");
|
|
56
55
|
if (!f) {
|
|
57
|
-
l(
|
|
56
|
+
l(s, o);
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
|
-
l(f,
|
|
59
|
+
l(f, o, { isKnockout: !0 }), s.save(), s.globalCompositeOperation = "destination-out", s.drawImage(d, 0, 0), s.restore();
|
|
61
60
|
} else
|
|
62
|
-
l(
|
|
61
|
+
l(s, o);
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
|
-
function k(
|
|
64
|
+
function k(s, r) {
|
|
66
65
|
if (typeof OffscreenCanvas < "u")
|
|
67
|
-
return new OffscreenCanvas(
|
|
66
|
+
return new OffscreenCanvas(s, r);
|
|
68
67
|
const c = document.createElement("canvas");
|
|
69
|
-
return c.width =
|
|
68
|
+
return c.width = s, c.height = r, c;
|
|
70
69
|
}
|
|
71
|
-
function
|
|
70
|
+
function S(s, r) {
|
|
72
71
|
var e;
|
|
73
72
|
const c = r.opacity ?? 1, i = !!((e = r.stroke) != null && e.enabled);
|
|
74
|
-
c < 1 && i ? T(
|
|
73
|
+
c < 1 && i ? T(s, r, c) : p(s, r, c);
|
|
75
74
|
}
|
|
76
|
-
function T(
|
|
75
|
+
function T(s, r, c) {
|
|
77
76
|
var f;
|
|
78
|
-
const i = r.transformData, e = (((f = r.stroke) == null ? void 0 : f.width) || 2) + 2, n = Math.ceil(i.width + e * 2), a = Math.ceil(i.height + e * 2),
|
|
77
|
+
const i = r.transformData, e = (((f = r.stroke) == null ? void 0 : f.width) || 2) + 2, n = Math.ceil(i.width + e * 2), a = Math.ceil(i.height + e * 2), o = k(n, a), t = o.getContext("2d");
|
|
79
78
|
if (!t) {
|
|
80
|
-
p(
|
|
79
|
+
p(s, r, c);
|
|
81
80
|
return;
|
|
82
81
|
}
|
|
83
82
|
const d = {
|
|
@@ -85,135 +84,135 @@ function T(o, r, c) {
|
|
|
85
84
|
x: n / 2,
|
|
86
85
|
y: a / 2
|
|
87
86
|
};
|
|
88
|
-
p(t, d, 1),
|
|
87
|
+
p(t, d, 1), s.save(), s.translate(r.x, r.y), r.rotation && s.rotate(-r.rotation * Math.PI / 180), s.globalAlpha = c, s.drawImage(o, -n / 2, -a / 2), s.restore();
|
|
89
88
|
}
|
|
90
|
-
function p(
|
|
89
|
+
function p(s, r, c) {
|
|
91
90
|
var e;
|
|
92
91
|
const i = r.transformData, h = i.fillOpacity ?? 1;
|
|
93
|
-
if (
|
|
94
|
-
|
|
92
|
+
if (s.save(), s.translate(r.x, r.y), r.rotation && s.rotate(-r.rotation * Math.PI / 180), s.globalAlpha = c * h, s.fillStyle = i.fillColor || "#3b82f6", s.beginPath(), u(s, i), s.fill(), s.restore(), (e = r.stroke) != null && e.enabled) {
|
|
93
|
+
s.save(), s.translate(r.x, r.y), r.rotation && s.rotate(-r.rotation * Math.PI / 180);
|
|
95
94
|
const n = r.stroke;
|
|
96
|
-
|
|
95
|
+
s.globalAlpha = c * (n.opacity ?? 1), s.strokeStyle = n.color || "#000000", s.lineWidth = n.width || 2, s.lineCap = n.lineCap || "round", s.lineJoin = n.lineJoin || "round", s.beginPath(), u(s, i), s.stroke(), s.restore();
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
|
-
function u(
|
|
98
|
+
function u(s, r) {
|
|
100
99
|
const { shapeType: c, width: i, height: h } = r;
|
|
101
100
|
switch (c) {
|
|
102
101
|
case "rectangle": {
|
|
103
102
|
const e = r.borderRadius || 0, n = -i / 2, a = -h / 2;
|
|
104
103
|
if (e > 0) {
|
|
105
|
-
const
|
|
106
|
-
|
|
104
|
+
const o = Math.min(e / 100 * Math.min(i, h), i / 2, h / 2);
|
|
105
|
+
s.roundRect(n, a, i, h, o);
|
|
107
106
|
} else
|
|
108
|
-
|
|
107
|
+
s.rect(n, a, i, h);
|
|
109
108
|
break;
|
|
110
109
|
}
|
|
111
110
|
case "circle": {
|
|
112
111
|
const e = Math.min(i, h) / 2;
|
|
113
|
-
|
|
112
|
+
s.arc(0, 0, e, 0, Math.PI * 2);
|
|
114
113
|
break;
|
|
115
114
|
}
|
|
116
115
|
case "ellipse": {
|
|
117
|
-
|
|
116
|
+
s.ellipse(0, 0, i / 2, h / 2, 0, 0, Math.PI * 2);
|
|
118
117
|
break;
|
|
119
118
|
}
|
|
120
119
|
case "triangle": {
|
|
121
120
|
const e = i / 2, n = h / 2;
|
|
122
|
-
|
|
121
|
+
s.moveTo(0, -n), s.lineTo(e, n), s.lineTo(-e, n), s.closePath();
|
|
123
122
|
break;
|
|
124
123
|
}
|
|
125
124
|
case "polygon": {
|
|
126
125
|
const e = r.sides || 5, n = Math.min(i, h) / 2;
|
|
127
126
|
for (let a = 0; a < e; a++) {
|
|
128
|
-
const
|
|
129
|
-
a === 0 ?
|
|
127
|
+
const o = a * 2 * Math.PI / e - Math.PI / 2, t = n * Math.cos(o), d = n * Math.sin(o);
|
|
128
|
+
a === 0 ? s.moveTo(t, d) : s.lineTo(t, d);
|
|
130
129
|
}
|
|
131
|
-
|
|
130
|
+
s.closePath();
|
|
132
131
|
break;
|
|
133
132
|
}
|
|
134
133
|
case "star": {
|
|
135
134
|
const e = r.points || 5, n = Math.min(i, h) / 2, a = n * (r.innerRadius || 0.4);
|
|
136
|
-
for (let
|
|
137
|
-
const t =
|
|
138
|
-
|
|
135
|
+
for (let o = 0; o < e * 2; o++) {
|
|
136
|
+
const t = o * Math.PI / e - Math.PI / 2, d = o % 2 === 0 ? n : a, f = d * Math.cos(t), g = d * Math.sin(t);
|
|
137
|
+
o === 0 ? s.moveTo(f, g) : s.lineTo(f, g);
|
|
139
138
|
}
|
|
140
|
-
|
|
139
|
+
s.closePath();
|
|
141
140
|
break;
|
|
142
141
|
}
|
|
143
142
|
case "line": {
|
|
144
143
|
const e = i / 2, n = h / 2;
|
|
145
|
-
|
|
144
|
+
s.rect(-e, -n, i, h);
|
|
146
145
|
break;
|
|
147
146
|
}
|
|
148
147
|
default:
|
|
149
|
-
|
|
148
|
+
s.rect(-i / 2, -h / 2, i, h);
|
|
150
149
|
}
|
|
151
150
|
}
|
|
152
151
|
export {
|
|
153
152
|
C as AlignmentSnapSystem,
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
Ws as AnyElementConfigSchema,
|
|
154
|
+
Es as AnyTransformDataSchema,
|
|
156
155
|
V as ArchTransform,
|
|
157
156
|
Y as ArtboardManager,
|
|
158
157
|
P as ArtboardRenderer,
|
|
159
|
-
|
|
158
|
+
G as AscendTransform,
|
|
160
159
|
w as CanvasRenderer,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
Os as CanvasStateV1Schema,
|
|
161
|
+
U as CircleTransform,
|
|
162
|
+
Q as CustomTransform,
|
|
164
163
|
I as DEFAULT_MAX_BITMAP_DIMENSION,
|
|
165
|
-
|
|
164
|
+
Z as ElementStore,
|
|
166
165
|
R as ExportManager,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
166
|
+
$ as FlagTransform,
|
|
167
|
+
x as HybridHistoryManager,
|
|
168
|
+
A as ImportManager,
|
|
169
|
+
W as InteractionStateMachine,
|
|
170
|
+
D as LeanTransform,
|
|
171
|
+
ss as LogLevel,
|
|
172
|
+
E as ResizePipeline,
|
|
173
|
+
Hs as SerializedArtboardSchema,
|
|
174
|
+
O as SpacingSystem,
|
|
175
|
+
H as TransformHandles,
|
|
176
|
+
rs as WaveTransform,
|
|
177
|
+
F as WorkerExportManager,
|
|
178
|
+
os as applySpaceLayoutRules,
|
|
179
|
+
as as applyStrokeStyle,
|
|
180
|
+
is as buildFontString,
|
|
181
|
+
es as calculateFixedCornerPosition,
|
|
182
|
+
ns as calculateResizeHandles,
|
|
183
|
+
ts as calculateRotationHandlePosition,
|
|
184
|
+
L as clearImageBitmapCache,
|
|
185
|
+
z as clearMaskCache,
|
|
186
|
+
B as clearRegisteredBitmapKeys,
|
|
187
|
+
hs as createCirclePath,
|
|
188
|
+
ds as createImagePath,
|
|
189
|
+
cs as createLogger,
|
|
190
|
+
fs as createRectPath,
|
|
191
|
+
ls as createTextPath,
|
|
192
|
+
ps as getFontMetrics,
|
|
193
|
+
K as getSharedWorkerExportManager,
|
|
194
|
+
gs as hitTestCircle,
|
|
195
|
+
us as hitTestRect,
|
|
196
|
+
X as invalidateMaskCache,
|
|
197
|
+
ks as logger,
|
|
198
|
+
Ts as measureTextWidth,
|
|
200
199
|
m as removeFromImageBitmapCache,
|
|
201
|
-
|
|
200
|
+
ys as renderCustomTransform,
|
|
202
201
|
M as renderImageElement,
|
|
203
202
|
l as renderImageStroke,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
203
|
+
Ms as renderMultilineText,
|
|
204
|
+
Ss as renderPathStroke,
|
|
205
|
+
bs as renderRichTextFillOnly,
|
|
206
|
+
S as renderShapeElement,
|
|
207
|
+
vs as renderTextElement,
|
|
208
|
+
Cs as renderTextFillOnly,
|
|
209
|
+
Ps as renderTextStroke,
|
|
210
|
+
J as renderWithKnockout,
|
|
211
|
+
_ as renderWithMasks,
|
|
212
|
+
ws as splitRichTextIntoLines,
|
|
213
|
+
j as terminateSharedWorkerExportManager,
|
|
215
214
|
q as unregisterElementBitmaps,
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
Is as wrapRichTextSpans,
|
|
216
|
+
Rs as wrapText
|
|
218
217
|
};
|
|
219
218
|
//# sourceMappingURL=internals.mjs.map
|
package/dist/internals.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internals.mjs","sources":["../src/rendering/image-renderer.ts","../src/rendering/shape-renderer.ts"],"sourcesContent":["/**\n * Image Renderer - Image element rendering with crop, flip, border radius, and stroke.\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n */\n\nimport type { ImageElementConfig } from '../types/index.js';\nimport { renderImageStroke } from './StrokeRenderer.js';\nimport type { RenderContext, SerializedImageElement } from './renderer-types.js';\n\n/**\n * Render an image element using ImageBitmap\n * Works in both main thread and worker\n */\nexport function renderImageElement(\n ctx: RenderContext,\n elementData: SerializedImageElement,\n imageBitmap: ImageBitmap\n): void {\n ctx.save();\n\n // Translate to element position\n ctx.translate(elementData.x, elementData.y);\n\n // Apply rotation (negative for clockwise)\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Apply flip transformations\n let scaleX = 1;\n let scaleY = 1;\n if (elementData.flipHorizontal) scaleX = -1;\n if (elementData.flipVertical) scaleY = -1;\n if (scaleX !== 1 || scaleY !== 1) {\n ctx.scale(scaleX, scaleY);\n }\n\n // Apply opacity if specified\n if (elementData.opacity !== undefined && elementData.opacity !== 1) {\n ctx.globalAlpha = elementData.opacity;\n }\n\n // Apply border radius if specified (borderRadius is stored as percentage 0-100)\n if (elementData.borderRadius && elementData.borderRadius > 0) {\n const radius = Math.min(\n (elementData.borderRadius / 100) * Math.min(elementData.width, elementData.height),\n elementData.width / 2,\n elementData.height / 2\n );\n\n // Create clipping path for rounded corners\n ctx.beginPath();\n const x = -elementData.width / 2;\n const y = -elementData.height / 2;\n const w = elementData.width;\n const h = elementData.height;\n\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n ctx.clip();\n }\n\n // Draw the image\n if (elementData.cropX !== undefined && elementData.cropWidth !== undefined) {\n // Draw with crop\n ctx.drawImage(\n imageBitmap,\n elementData.cropX,\n elementData.cropY || 0,\n elementData.cropWidth,\n elementData.cropHeight || imageBitmap.height,\n -elementData.width / 2,\n -elementData.height / 2,\n elementData.width,\n elementData.height\n );\n } else {\n // Draw without crop (centered)\n ctx.drawImage(imageBitmap, -elementData.width / 2, -elementData.height / 2, elementData.width, elementData.height);\n }\n\n ctx.restore();\n\n // Render stroke if enabled (after restore to apply fresh transforms)\n if (elementData.stroke?.enabled) {\n const hasKnockoutStroke = elementData.knockoutParts?.stroke === true;\n\n const imageConfig: ImageElementConfig = {\n transformType: 'image',\n x: elementData.x,\n y: elementData.y,\n rotation: elementData.rotation,\n stroke: elementData.stroke,\n knockoutParts: elementData.knockoutParts,\n transformData: {\n type: 'image',\n width: elementData.width,\n height: elementData.height,\n borderRadius: elementData.borderRadius || 0,\n },\n };\n\n if (hasKnockoutStroke) {\n // For knockout stroke, use offscreen canvas approach\n const canvas = ctx.canvas;\n let offscreen: HTMLCanvasElement | OffscreenCanvas;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n offscreen = new OffscreenCanvas(canvas.width, canvas.height);\n } else if (typeof document !== 'undefined') {\n offscreen = document.createElement('canvas');\n offscreen.width = canvas.width;\n offscreen.height = canvas.height;\n } else {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n // Render the stroke to the offscreen canvas with knockout flag\n renderImageStroke(offCtx, imageConfig, { isKnockout: true });\n\n // Composite with destination-out\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n ctx.drawImage(offscreen as CanvasImageSource, 0, 0);\n ctx.restore();\n } else {\n // Normal stroke\n renderImageStroke(ctx, imageConfig);\n }\n }\n}\n","/**\n * Shape Renderer - Shape element rendering (rectangle, circle, ellipse, triangle, etc.)\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n *\n * Opacity strategy: When a shape has both element-level opacity AND a stroke,\n * we render fill+stroke at full opacity on a temporary canvas, then composite\n * the result at the element's opacity. This prevents fill/stroke overlap from\n * compounding (e.g., 50% fill + 50% stroke overlap ≠ 75% opaque).\n */\n\nimport type { RenderContext, SerializedShapeElement } from './renderer-types.js';\n\ntype CanvasLike = HTMLCanvasElement | OffscreenCanvas;\n\nfunction createTempCanvas(width: number, height: number): CanvasLike {\n if (typeof OffscreenCanvas !== 'undefined') {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Render a shape element\n * Works in both main thread and worker\n */\nexport function renderShapeElement(ctx: RenderContext, elementData: SerializedShapeElement): void {\n const elementOpacity = elementData.opacity ?? 1;\n const hasStroke = !!elementData.stroke?.enabled;\n const needsOffscreen = elementOpacity < 1 && hasStroke;\n\n if (needsOffscreen) {\n // Render fill+stroke at full opacity on a temp canvas, then composite\n renderShapeWithOffscreen(ctx, elementData, elementOpacity);\n } else {\n // No compounding risk — render directly\n renderShapeDirect(ctx, elementData, elementOpacity);\n }\n}\n\n/**\n * Render shape via temporary canvas to avoid fill/stroke opacity compounding.\n */\nfunction renderShapeWithOffscreen(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const td = elementData.transformData;\n const strokeWidth = elementData.stroke?.width || 2;\n // Pad temp canvas to fit the stroke (strokes extend beyond the shape bounds)\n const padding = strokeWidth + 2;\n const offW = Math.ceil(td.width + padding * 2);\n const offH = Math.ceil(td.height + padding * 2);\n\n const offCanvas = createTempCanvas(offW, offH);\n const offCtx = offCanvas.getContext('2d') as RenderContext;\n if (!offCtx) {\n // Fallback to direct render\n renderShapeDirect(ctx, elementData, elementOpacity);\n return;\n }\n\n // Render at center of temp canvas with full opacity (elementOpacity = 1)\n const tempData: SerializedShapeElement = {\n ...elementData,\n x: offW / 2,\n y: offH / 2,\n opacity: 1,\n };\n renderShapeDirect(offCtx, tempData, 1);\n\n // Composite temp canvas onto main canvas at element opacity\n ctx.save();\n\n // Position: elementData.(x,y) is the shape center, temp canvas center is (offW/2, offH/2)\n // We need to account for rotation around the element center\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n ctx.globalAlpha = elementOpacity;\n ctx.drawImage(offCanvas, -offW / 2, -offH / 2);\n ctx.restore();\n}\n\n/**\n * Render shape directly onto ctx (no offscreen). Used when there's no\n * compounding risk, or as the inner render for the offscreen path.\n */\nfunction renderShapeDirect(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const transformData = elementData.transformData;\n const fillOpacity = transformData.fillOpacity ?? 1;\n\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Fill\n ctx.globalAlpha = elementOpacity * fillOpacity;\n ctx.fillStyle = transformData.fillColor || '#3b82f6';\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.fill();\n ctx.restore();\n\n // Stroke\n if (elementData.stroke?.enabled) {\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n const stroke = elementData.stroke;\n ctx.globalAlpha = elementOpacity * (stroke.opacity ?? 1);\n ctx.strokeStyle = stroke.color || '#000000';\n ctx.lineWidth = stroke.width || 2;\n ctx.lineCap = stroke.lineCap || 'round';\n ctx.lineJoin = stroke.lineJoin || 'round';\n\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.stroke();\n ctx.restore();\n }\n}\n\n/**\n * Trace the shape path (without fill/stroke) — reusable for both fill and stroke passes.\n */\nfunction traceShapePath(\n ctx: RenderContext,\n transformData: SerializedShapeElement['transformData']\n): void {\n const { shapeType, width, height } = transformData;\n\n switch (shapeType) {\n case 'rectangle': {\n const borderRadius = transformData.borderRadius || 0;\n const x = -width / 2;\n const y = -height / 2;\n\n if (borderRadius > 0) {\n const radius = Math.min((borderRadius / 100) * Math.min(width, height), width / 2, height / 2);\n ctx.roundRect(x, y, width, height, radius);\n } else {\n ctx.rect(x, y, width, height);\n }\n break;\n }\n\n case 'circle': {\n const radius = Math.min(width, height) / 2;\n ctx.arc(0, 0, radius, 0, Math.PI * 2);\n break;\n }\n\n case 'ellipse': {\n ctx.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n }\n\n case 'triangle': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.moveTo(0, -halfHeight);\n ctx.lineTo(halfWidth, halfHeight);\n ctx.lineTo(-halfWidth, halfHeight);\n ctx.closePath();\n break;\n }\n\n case 'polygon': {\n const sides = transformData.sides || 5;\n const radius = Math.min(width, height) / 2;\n for (let i = 0; i < sides; i++) {\n const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;\n const px = radius * Math.cos(angle);\n const py = radius * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'star': {\n const points = transformData.points || 5;\n const outerRadius = Math.min(width, height) / 2;\n const innerRadius = outerRadius * (transformData.innerRadius || 0.4);\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const px = r * Math.cos(angle);\n const py = r * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'line': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.rect(-halfWidth, -halfHeight, width, height);\n break;\n }\n\n default:\n ctx.rect(-width / 2, -height / 2, width, height);\n }\n}\n"],"names":["renderImageElement","ctx","elementData","imageBitmap","scaleX","scaleY","radius","x","y","w","h","_a","hasKnockoutStroke","_b","imageConfig","canvas","offscreen","renderImageStroke","offCtx","createTempCanvas","width","height","renderShapeElement","elementOpacity","hasStroke","renderShapeWithOffscreen","renderShapeDirect","td","padding","offW","offH","offCanvas","tempData","transformData","fillOpacity","traceShapePath","stroke","shapeType","borderRadius","halfWidth","halfHeight","sides","i","angle","px","py","points","outerRadius","innerRadius","r"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"internals.mjs","sources":["../src/rendering/image-renderer.ts","../src/rendering/shape-renderer.ts"],"sourcesContent":["/**\n * Image Renderer - Image element rendering with crop, flip, border radius, and stroke.\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n */\n\nimport type { ImageElementConfig } from '../types/index.js';\nimport { renderImageStroke } from './StrokeRenderer.js';\nimport type { RenderContext, SerializedImageElement } from './renderer-types.js';\n\n/**\n * Render an image element using ImageBitmap\n * Works in both main thread and worker\n */\nexport function renderImageElement(\n ctx: RenderContext,\n elementData: SerializedImageElement,\n imageBitmap: ImageBitmap\n): void {\n ctx.save();\n\n // Translate to element position\n ctx.translate(elementData.x, elementData.y);\n\n // Apply rotation (negative for clockwise)\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Apply flip transformations\n let scaleX = 1;\n let scaleY = 1;\n if (elementData.flipHorizontal) scaleX = -1;\n if (elementData.flipVertical) scaleY = -1;\n if (scaleX !== 1 || scaleY !== 1) {\n ctx.scale(scaleX, scaleY);\n }\n\n // Apply opacity if specified\n if (elementData.opacity !== undefined && elementData.opacity !== 1) {\n ctx.globalAlpha = elementData.opacity;\n }\n\n // Apply border radius if specified (borderRadius is stored as percentage 0-100)\n if (elementData.borderRadius && elementData.borderRadius > 0) {\n const radius = Math.min(\n (elementData.borderRadius / 100) * Math.min(elementData.width, elementData.height),\n elementData.width / 2,\n elementData.height / 2\n );\n\n // Create clipping path for rounded corners\n ctx.beginPath();\n const x = -elementData.width / 2;\n const y = -elementData.height / 2;\n const w = elementData.width;\n const h = elementData.height;\n\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n ctx.clip();\n }\n\n // Draw the image\n if (elementData.cropX !== undefined && elementData.cropWidth !== undefined) {\n // Draw with crop\n ctx.drawImage(\n imageBitmap,\n elementData.cropX,\n elementData.cropY || 0,\n elementData.cropWidth,\n elementData.cropHeight || imageBitmap.height,\n -elementData.width / 2,\n -elementData.height / 2,\n elementData.width,\n elementData.height\n );\n } else {\n // Draw without crop (centered)\n ctx.drawImage(imageBitmap, -elementData.width / 2, -elementData.height / 2, elementData.width, elementData.height);\n }\n\n ctx.restore();\n\n // Render stroke if enabled (after restore to apply fresh transforms)\n if (elementData.stroke?.enabled) {\n const hasKnockoutStroke = elementData.knockoutParts?.stroke === true;\n\n const imageConfig: ImageElementConfig = {\n transformType: 'image',\n x: elementData.x,\n y: elementData.y,\n rotation: elementData.rotation,\n stroke: elementData.stroke,\n knockoutParts: elementData.knockoutParts,\n transformData: {\n type: 'image',\n width: elementData.width,\n height: elementData.height,\n borderRadius: elementData.borderRadius || 0,\n },\n };\n\n if (hasKnockoutStroke) {\n // For knockout stroke, use offscreen canvas approach\n const canvas = ctx.canvas;\n let offscreen: HTMLCanvasElement | OffscreenCanvas;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n offscreen = new OffscreenCanvas(canvas.width, canvas.height);\n } else if (typeof document !== 'undefined') {\n offscreen = document.createElement('canvas');\n offscreen.width = canvas.width;\n offscreen.height = canvas.height;\n } else {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n // Render the stroke to the offscreen canvas with knockout flag\n renderImageStroke(offCtx, imageConfig, { isKnockout: true });\n\n // Composite with destination-out\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n ctx.drawImage(offscreen as CanvasImageSource, 0, 0);\n ctx.restore();\n } else {\n // Normal stroke\n renderImageStroke(ctx, imageConfig);\n }\n }\n}\n","/**\n * Shape Renderer - Shape element rendering (rectangle, circle, ellipse, triangle, etc.)\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n *\n * Opacity strategy: When a shape has both element-level opacity AND a stroke,\n * we render fill+stroke at full opacity on a temporary canvas, then composite\n * the result at the element's opacity. This prevents fill/stroke overlap from\n * compounding (e.g., 50% fill + 50% stroke overlap ≠ 75% opaque).\n */\n\nimport type { RenderContext, SerializedShapeElement } from './renderer-types.js';\n\ntype CanvasLike = HTMLCanvasElement | OffscreenCanvas;\n\nfunction createTempCanvas(width: number, height: number): CanvasLike {\n if (typeof OffscreenCanvas !== 'undefined') {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Render a shape element\n * Works in both main thread and worker\n */\nexport function renderShapeElement(ctx: RenderContext, elementData: SerializedShapeElement): void {\n const elementOpacity = elementData.opacity ?? 1;\n const hasStroke = !!elementData.stroke?.enabled;\n const needsOffscreen = elementOpacity < 1 && hasStroke;\n\n if (needsOffscreen) {\n // Render fill+stroke at full opacity on a temp canvas, then composite\n renderShapeWithOffscreen(ctx, elementData, elementOpacity);\n } else {\n // No compounding risk — render directly\n renderShapeDirect(ctx, elementData, elementOpacity);\n }\n}\n\n/**\n * Render shape via temporary canvas to avoid fill/stroke opacity compounding.\n */\nfunction renderShapeWithOffscreen(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const td = elementData.transformData;\n const strokeWidth = elementData.stroke?.width || 2;\n // Pad temp canvas to fit the stroke (strokes extend beyond the shape bounds)\n const padding = strokeWidth + 2;\n const offW = Math.ceil(td.width + padding * 2);\n const offH = Math.ceil(td.height + padding * 2);\n\n const offCanvas = createTempCanvas(offW, offH);\n const offCtx = offCanvas.getContext('2d') as RenderContext;\n if (!offCtx) {\n // Fallback to direct render\n renderShapeDirect(ctx, elementData, elementOpacity);\n return;\n }\n\n // Render at center of temp canvas with full opacity (elementOpacity = 1)\n const tempData: SerializedShapeElement = {\n ...elementData,\n x: offW / 2,\n y: offH / 2,\n opacity: 1,\n };\n renderShapeDirect(offCtx, tempData, 1);\n\n // Composite temp canvas onto main canvas at element opacity\n ctx.save();\n\n // Position: elementData.(x,y) is the shape center, temp canvas center is (offW/2, offH/2)\n // We need to account for rotation around the element center\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n ctx.globalAlpha = elementOpacity;\n ctx.drawImage(offCanvas, -offW / 2, -offH / 2);\n ctx.restore();\n}\n\n/**\n * Render shape directly onto ctx (no offscreen). Used when there's no\n * compounding risk, or as the inner render for the offscreen path.\n */\nfunction renderShapeDirect(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const transformData = elementData.transformData;\n const fillOpacity = transformData.fillOpacity ?? 1;\n\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Fill\n ctx.globalAlpha = elementOpacity * fillOpacity;\n ctx.fillStyle = transformData.fillColor || '#3b82f6';\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.fill();\n ctx.restore();\n\n // Stroke\n if (elementData.stroke?.enabled) {\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n const stroke = elementData.stroke;\n ctx.globalAlpha = elementOpacity * (stroke.opacity ?? 1);\n ctx.strokeStyle = stroke.color || '#000000';\n ctx.lineWidth = stroke.width || 2;\n ctx.lineCap = stroke.lineCap || 'round';\n ctx.lineJoin = stroke.lineJoin || 'round';\n\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.stroke();\n ctx.restore();\n }\n}\n\n/**\n * Trace the shape path (without fill/stroke) — reusable for both fill and stroke passes.\n */\nfunction traceShapePath(\n ctx: RenderContext,\n transformData: SerializedShapeElement['transformData']\n): void {\n const { shapeType, width, height } = transformData;\n\n switch (shapeType) {\n case 'rectangle': {\n const borderRadius = transformData.borderRadius || 0;\n const x = -width / 2;\n const y = -height / 2;\n\n if (borderRadius > 0) {\n const radius = Math.min((borderRadius / 100) * Math.min(width, height), width / 2, height / 2);\n ctx.roundRect(x, y, width, height, radius);\n } else {\n ctx.rect(x, y, width, height);\n }\n break;\n }\n\n case 'circle': {\n const radius = Math.min(width, height) / 2;\n ctx.arc(0, 0, radius, 0, Math.PI * 2);\n break;\n }\n\n case 'ellipse': {\n ctx.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n }\n\n case 'triangle': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.moveTo(0, -halfHeight);\n ctx.lineTo(halfWidth, halfHeight);\n ctx.lineTo(-halfWidth, halfHeight);\n ctx.closePath();\n break;\n }\n\n case 'polygon': {\n const sides = transformData.sides || 5;\n const radius = Math.min(width, height) / 2;\n for (let i = 0; i < sides; i++) {\n const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;\n const px = radius * Math.cos(angle);\n const py = radius * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'star': {\n const points = transformData.points || 5;\n const outerRadius = Math.min(width, height) / 2;\n const innerRadius = outerRadius * (transformData.innerRadius || 0.4);\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const px = r * Math.cos(angle);\n const py = r * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'line': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.rect(-halfWidth, -halfHeight, width, height);\n break;\n }\n\n default:\n ctx.rect(-width / 2, -height / 2, width, height);\n }\n}\n"],"names":["renderImageElement","ctx","elementData","imageBitmap","scaleX","scaleY","radius","x","y","w","h","_a","hasKnockoutStroke","_b","imageConfig","canvas","offscreen","renderImageStroke","offCtx","createTempCanvas","width","height","renderShapeElement","elementOpacity","hasStroke","renderShapeWithOffscreen","renderShapeDirect","td","padding","offW","offH","offCanvas","tempData","transformData","fillOpacity","traceShapePath","stroke","shapeType","borderRadius","halfWidth","halfHeight","sides","i","angle","px","py","points","outerRadius","innerRadius","r"],"mappings":"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"}
|
package/dist/testing.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),u=require("react"),c=require("./ThemeContext-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),u=require("react"),c=require("./ThemeContext-BMNQKl1c.cjs"),l=require("./HybridHistoryManager-BXD93pp8.cjs"),h=({children:t,initialElements:e=[],initialArtboards:n,initialSelection:r=null,initialMultiSelection:o=[],initialArtboardConfig:d={}})=>{const[F]=u.useState(()=>{const s=new l.ArtboardManager;return n&&n.length>0?n.forEach(i=>{s.createArtboard({name:i.name,width:i.width,height:i.height,backgroundColor:i.backgroundColor})}):s.createArtboard({name:"Test Artboard",width:1200,height:1200,backgroundColor:"#FFFFFF",...d}),s});return a.jsx(c.ThemeProvider,{children:a.jsx(c.EditorProvider,{initialArtboardConfig:d,children:t})})},g=({children:t,initialElements:e=[],initialSelection:n=null,initialMultiSelection:r=[],initialArtboardConfig:o={}})=>a.jsx(c.ThemeProvider,{children:a.jsx(c.EditorProvider,{initialArtboardConfig:o,children:t})});function E(t="custom",e={}){const n=l.getTransformById(t);if(!n||!n.Component)throw new Error(`Transform type "${t}" not found in registry`);return new n.Component({transformType:t,text:"Test Text",fontSize:32,color:"#000000",fontFamily:"Arial",x:100,y:100,rotation:0,...e})}function A(t={}){return new l.ImageElement({imageUrl:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",imageAspectRatio:1,x:100,y:100,rotation:0,...t})}function w(t={}){return new l.ArtboardElement({name:"Test Artboard",width:1200,height:1200,x:0,y:0,backgroundColor:"#FFFFFF",...t})}async function m(t,e=5e3,n=100){const r=Date.now();for(;!t();){if(Date.now()-r>e)throw new Error(`Timeout waiting for condition after ${e}ms`);await new Promise(o=>setTimeout(o,n))}}async function f(t,e=5e3){let n=null;return await m(()=>!1,e),n}function b(t,e={}){const n=new KeyboardEvent("keydown",{key:t,ctrlKey:e.ctrl,shiftKey:e.shift,altKey:e.alt,metaKey:e.meta,bubbles:!0,cancelable:!0});document.dispatchEvent(n)}function M(t=800,e=600){const n=document.createElement("canvas");return n.width=t,n.height=e,n}function y(t,e){Object.entries(e).forEach(([n,r])=>{if(t[n]!==r)throw new Error(`Expected element.${n} to be ${r}, got ${t[n]}`)})}function x(t){const e=t.getBoundingBox();return{x:e.x,y:e.y,width:e.width,height:e.height}}exports.MockEditorProvider=h;exports.MockEditorProviderWithState=g;exports.assertElementProperties=y;exports.createMockArtboard=w;exports.createMockCanvas=M;exports.createMockElement=E;exports.createMockImageElement=A;exports.getElementBounds=x;exports.simulateKeyPress=b;exports.waitFor=m;exports.waitForExport=f;
|
|
2
2
|
//# sourceMappingURL=testing.js.map
|