@twick/canvas 0.0.1 → 0.14.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/helpers/browser.ts","../src/helpers/canvas.util.ts","../src/helpers/constants.ts","../src/components/element-controls.tsx","../../media-utils/dist/index.mjs","../src/components/elements.tsx","../src/hooks/use-twick-canvas.ts"],"sourcesContent":["export const isBrowser = typeof window !== 'undefined';\r\n\r\nexport const isCanvasSupported = isBrowser && !!window.HTMLCanvasElement;\r\n\r\nexport const isVideoSupported = isBrowser && !!window.HTMLVideoElement;\r\n\r\nexport function assertBrowser() {\r\n if (!isBrowser) {\r\n throw new Error('This code can only run in a browser environment');\r\n }\r\n}\r\n\r\nexport function assertCanvasSupport() {\r\n if (!isCanvasSupported) {\r\n throw new Error('Canvas is not supported in this environment');\r\n }\r\n}\r\n\r\nexport function assertVideoSupport() {\r\n if (!isVideoSupported) {\r\n throw new Error('Video is not supported in this environment');\r\n }\r\n} ","import {\r\n Canvas as FabricCanvas,\r\n} from \"fabric\";\r\nimport { CanvasMetadata, CanvasProps } from \"../types\";\r\nimport { Dimensions, Position } from \"@twick/media-utils\";\r\nimport { assertBrowser, assertCanvasSupport } from \"./browser\";\r\n\r\n/**\r\n * Creates and initializes a Fabric.js canvas with specified configurations.\r\n *\r\n * @param videoSize - The dimensions of the video.\r\n * @param canvasSize - The dimensions of the canvas.\r\n * @param canvasContainer - The HTML container for the canvas.\r\n * @param backgroundColor - Background color of the canvas (default: black).\r\n * @param selectionBorderColor - Border color for selected objects (default: blue).\r\n * @param selectionLineWidth - Width of the selection border (default: 2).\r\n * @param uniScaleTransform - Ensures uniform scaling of objects (default: true).\r\n * @param enableRetinaScaling - Enables retina scaling for higher DPI (default: true).\r\n * @param touchZoomThreshold - Threshold for touch zoom interactions (default: 10).\r\n * @returns An object containing the initialized canvas and its metadata.\r\n */\r\nexport function createCanvas({\r\n videoSize,\r\n canvasSize,\r\n canvasRef,\r\n backgroundColor = \"#000000\",\r\n selectionBorderColor = \"#2563eb\",\r\n selectionLineWidth = 2,\r\n uniScaleTransform = true,\r\n enableRetinaScaling = true,\r\n touchZoomThreshold = 10,\r\n}: CanvasProps): { canvas: FabricCanvas; canvasMetadata: CanvasMetadata } {\r\n assertBrowser();\r\n assertCanvasSupport();\r\n\r\n // Metadata for scaling and positioning on the canvas\r\n const canvasMetadata = {\r\n width: canvasSize.width,\r\n height: canvasSize.height,\r\n aspectRatio: canvasSize.width / canvasSize.height,\r\n scaleX: canvasSize.width / videoSize.width,\r\n scaleY: canvasSize.height / videoSize.height,\r\n };\r\n\r\n // Create and configure the Fabric.js canvas\r\n const canvas = new FabricCanvas(canvasRef, {\r\n backgroundColor,\r\n width: canvasSize.width,\r\n height: canvasSize.height,\r\n preserveObjectStacking: true,\r\n enableRetinaScaling,\r\n selectionBorderColor,\r\n selectionLineWidth,\r\n uniScaleTransform,\r\n touchZoomThreshold,\r\n renderOnAddRemove: false,\r\n stateful: false,\r\n selection: true,\r\n skipTargetFind: false,\r\n controlsAboveOverlay: true,\r\n });\r\n\r\n // Set dimensions and render canvas\r\n if (canvasRef) {\r\n canvas.setDimensions({\r\n width: canvasMetadata.width,\r\n height: canvasMetadata.height,\r\n });\r\n canvas.renderAll();\r\n }\r\n\r\n return {\r\n canvas,\r\n canvasMetadata,\r\n };\r\n}\r\n\r\n/**\r\n * Reorders elements on the canvas based on their zIndex property.\r\n *\r\n * @param canvas - The Fabric.js canvas instance.\r\n */\r\nexport function reorderElementsByZIndex(canvas: FabricCanvas) {\r\n if (!canvas) return;\r\n let backgroundColor = canvas.backgroundColor;\r\n\r\n const objects = canvas.getObjects();\r\n // Sort objects by zIndex and re-add to the canvas in order\r\n objects.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));\r\n\r\n canvas.clear();\r\n canvas.backgroundColor = backgroundColor;\r\n\r\n objects.forEach((obj) => canvas.add(obj));\r\n canvas.renderAll();\r\n}\r\n\r\n/**\r\n * Clears all elements from the canvas and re-renders it.\r\n *\r\n * @param canvas - The Fabric.js canvas instance.\r\n */\r\nexport function clearCanvas(canvas: FabricCanvas) {\r\n if (!canvas) return;\r\n canvas.clear();\r\n canvas.renderAll();\r\n}\r\n\r\n/**\r\n * Converts a position from the video coordinate space to the canvas coordinate space.\r\n *\r\n * @param x - X-coordinate in video space.\r\n * @param y - Y-coordinate in video space.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @returns The corresponding position in canvas space.\r\n */\r\nexport function convertToCanvasPosition(\r\n x: number,\r\n y: number,\r\n canvasMetadata: CanvasMetadata\r\n): Position {\r\n return {\r\n x: x * canvasMetadata.scaleX + canvasMetadata.width / 2,\r\n y: y * canvasMetadata.scaleY + canvasMetadata.height / 2,\r\n };\r\n}\r\n\r\n/**\r\n * Converts a position from the canvas coordinate space to the video coordinate space.\r\n *\r\n * @param x - X-coordinate in canvas space.\r\n * @param y - Y-coordinate in canvas space.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @param videoSize - Dimensions of the video.\r\n * @returns The corresponding position in video space.\r\n */\r\nexport function convertToVideoPosition(\r\n x: number,\r\n y: number,\r\n canvasMetadata: CanvasMetadata,\r\n videoSize: Dimensions\r\n): Position {\r\n return {\r\n x: x / canvasMetadata.scaleX - videoSize.width / 2,\r\n y: y / canvasMetadata.scaleY - videoSize.height / 2,\r\n };\r\n}\r\n\r\n/**\r\n * Retrieves the current frame effect for a given seek time.\r\n *\r\n * @param item - The item containing frame effects.\r\n * @param seekTime - The current time to match against frame effects.\r\n * @returns The current frame effect active at the given seek time, if any.\r\n */\r\nexport function getCurrentFrameEffect(item: any, seekTime: number) {\r\n let currentFrameEffect;\r\n for (let i = 0; i < item?.frameEffects?.length; i++) {\r\n if (\r\n item.frameEffects[i].s <= seekTime &&\r\n item.frameEffects[i].e >= seekTime\r\n ) {\r\n currentFrameEffect = item.frameEffects[i];\r\n break;\r\n }\r\n }\r\n return currentFrameEffect;\r\n}\r\n","export const DEFAULT_TEXT_PROPS = {\r\n family: \"Poppins\",\r\n size: 48,\r\n fill: \"#FFFFFF\",\r\n stroke: \"#000000\",\r\n lineWidth: 0,\r\n }\r\n \r\nexport const DEFAULT_CAPTION_PROPS = {\r\n family: \"Poppins\",\r\n size: 48,\r\n fill: \"#FFFFFF\",\r\n fontWeight: 600,\r\n color: {\r\n text: \"#FFFFFF\",\r\n background: \"#000000\",\r\n highlight: \"#FFFFFF\",\r\n },\r\n stroke: \"#000000\",\r\n lineWidth: 0.2,\r\n shadowColor: \"#000000\",\r\n shadowBlur: 2,\r\n shadowOffset: [0, 0],\r\n}\r\n\r\nexport const CANVAS_OPERATIONS = {\r\n ITEM_SELECTED: \"ITEM_SELECTED\",\r\n ITEM_UPDATED: \"ITEM_UPDATED\",\r\n ITEM_DELETED: \"ITEM_DELETED\",\r\n ITEM_ADDED: \"ITEM_ADDED\",\r\n ITEM_GROUPED: \"ITEM_GROUPED\",\r\n ITEM_UNGROUPED: \"ITEM_UNGROUPED\",\r\n}\r\n\r\nexport const ELEMENT_TYPES = {\r\n TEXT: \"text\",\r\n CAPTION: \"caption\",\r\n IMAGE: \"image\",\r\n VIDEO: \"video\",\r\n RECT: \"rect\",\r\n BACKGROUND_COLOR: \"backgroundColor\",\r\n}\r\n","import { Control, controlsUtils } from \"fabric\";\r\n\r\nexport const disabledControl = new Control({\r\n x: 0,\r\n y: -0.5,\r\n offsetY: 0,\r\n cursorStyle: \"pointer\",\r\n actionHandler: () => {\r\n return true;\r\n },\r\n actionName: \"scale\",\r\n render: function (ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number) {\r\n const size = 0;\r\n ctx.save();\r\n ctx.translate(left, top);\r\n ctx.fillStyle = \"#red\";\r\n ctx.fillRect(-size / 2, -size / 2, size, size);\r\n ctx.restore();\r\n },\r\n });\r\n\r\nexport const rotateControl = new Control({\r\n x: 0,\r\n y: -0.5,\r\n offsetY: -25,\r\n cursorStyle: \"crosshair\",\r\n actionHandler: controlsUtils.rotationWithSnapping,\r\n actionName: \"rotate\",\r\n withConnection: true,\r\n });","const imageDimensionsCache = {};\nconst videoMetaCache = {};\nconst audioDurationCache = {};\n\nconst getAudioDuration = (audioSrc) => {\n if (audioDurationCache[audioSrc]) {\n return Promise.resolve(audioDurationCache[audioSrc]);\n }\n return new Promise((resolve, reject) => {\n const audio = document.createElement(\"audio\");\n audio.preload = \"metadata\";\n audio.src = audioSrc;\n audio.onloadedmetadata = () => {\n const duration = audio.duration;\n audioDurationCache[audioSrc] = duration;\n resolve(duration);\n };\n audio.onerror = () => {\n reject(new Error(\"Failed to load audio metadata\"));\n };\n });\n};\n\nconst concurrencyLimit = 5;\nlet activeCount = 0;\nconst queue = [];\nfunction runNext() {\n if (queue.length === 0 || activeCount >= concurrencyLimit) return;\n const next = queue.shift();\n if (next) {\n activeCount++;\n next();\n }\n}\nfunction limit(fn) {\n return new Promise((resolve, reject) => {\n const task = () => {\n fn().then(resolve).catch(reject).finally(() => {\n activeCount--;\n runNext();\n });\n };\n if (activeCount < concurrencyLimit) {\n activeCount++;\n task();\n } else {\n queue.push(task);\n }\n });\n}\n\nfunction loadImageDimensions(url) {\n return new Promise((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"getImageDimensions() is only available in the browser.\"));\n return;\n }\n const img = new Image();\n img.onload = () => {\n resolve({ width: img.naturalWidth, height: img.naturalHeight });\n };\n img.onerror = reject;\n img.src = url;\n });\n}\nfunction getImageDimensions(url) {\n if (imageDimensionsCache[url]) {\n return Promise.resolve(imageDimensionsCache[url]);\n }\n return limit(() => loadImageDimensions(url)).then((dimensions) => {\n imageDimensionsCache[url] = dimensions;\n return dimensions;\n });\n}\n\nconst getVideoMeta = (videoSrc) => {\n if (videoMetaCache[videoSrc]) {\n return Promise.resolve(videoMetaCache[videoSrc]);\n }\n return new Promise((resolve, reject) => {\n const video = document.createElement(\"video\");\n video.preload = \"metadata\";\n video.src = videoSrc;\n video.onloadedmetadata = () => {\n const meta = {\n width: video.videoWidth,\n height: video.videoHeight,\n duration: video.duration\n };\n videoMetaCache[videoSrc] = meta;\n resolve(meta);\n };\n video.onerror = () => reject(new Error(\"Failed to load video metadata\"));\n });\n};\n\nasync function getThumbnail(videoUrl, seekTime = 0.1, playbackRate = 1) {\n return new Promise((resolve, reject) => {\n const video = document.createElement(\"video\");\n video.crossOrigin = \"anonymous\";\n video.muted = true;\n video.playsInline = true;\n video.autoplay = false;\n video.preload = \"auto\";\n video.playbackRate = playbackRate;\n let timeoutId;\n const cleanup = () => {\n if (video.parentNode) video.remove();\n if (timeoutId) clearTimeout(timeoutId);\n };\n const handleError = () => {\n cleanup();\n reject(new Error(`Failed to load video: ${video.error?.message || \"Unknown error\"}`));\n };\n const handleSeeked = () => {\n try {\n video.pause();\n const canvas = document.createElement(\"canvas\");\n const width = video.videoWidth || 640;\n const height = video.videoHeight || 360;\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n cleanup();\n reject(new Error(\"Failed to get canvas context\"));\n return;\n }\n ctx.drawImage(video, 0, 0, width, height);\n try {\n const dataUrl = canvas.toDataURL(\"image/jpeg\", 0.8);\n cleanup();\n resolve(dataUrl);\n } catch {\n canvas.toBlob((blob) => {\n if (!blob) {\n cleanup();\n reject(new Error(\"Failed to create Blob\"));\n return;\n }\n const blobUrl = URL.createObjectURL(blob);\n cleanup();\n resolve(blobUrl);\n }, \"image/jpeg\", 0.8);\n }\n } catch (err) {\n cleanup();\n reject(new Error(`Error creating thumbnail: ${err}`));\n }\n };\n video.addEventListener(\"error\", handleError, { once: true });\n video.addEventListener(\"seeked\", handleSeeked, { once: true });\n video.addEventListener(\"loadedmetadata\", () => {\n const playPromise = video.play();\n if (playPromise !== void 0) {\n playPromise.then(() => {\n video.currentTime = seekTime;\n }).catch(() => {\n video.currentTime = seekTime;\n });\n } else {\n video.currentTime = seekTime;\n }\n }, { once: true });\n timeoutId = window.setTimeout(() => {\n cleanup();\n reject(new Error(\"Video loading timed out\"));\n }, 5e3);\n video.src = videoUrl;\n document.body.appendChild(video);\n });\n}\n\nfunction getScaledDimensions(width, height, maxWidth, maxHeight) {\n if (width <= maxWidth && height <= maxHeight) {\n return {\n width: width % 2 === 0 ? width : width - 1,\n height: height % 2 === 0 ? height : height - 1\n };\n }\n const widthRatio = maxWidth / width;\n const heightRatio = maxHeight / height;\n const scale = Math.min(widthRatio, heightRatio);\n let scaledWidth = Math.round(width * scale);\n let scaledHeight = Math.round(height * scale);\n if (scaledWidth % 2 !== 0) {\n scaledWidth -= 1;\n }\n if (scaledHeight % 2 !== 0) {\n scaledHeight -= 1;\n }\n return {\n width: Math.min(scaledWidth, maxWidth),\n height: Math.min(scaledHeight, maxHeight)\n };\n}\nfunction getObjectFitSize(objectFit, elementSize, containerSize) {\n const elementAspectRatio = elementSize.width / elementSize.height;\n const containerAspectRatio = containerSize.width / containerSize.height;\n switch (objectFit) {\n case \"contain\":\n if (elementAspectRatio > containerAspectRatio) {\n return {\n width: containerSize.width,\n height: containerSize.width / elementAspectRatio\n };\n } else {\n return {\n width: containerSize.height * elementAspectRatio,\n height: containerSize.height\n };\n }\n case \"cover\":\n if (elementAspectRatio > containerAspectRatio) {\n return {\n width: containerSize.height * elementAspectRatio,\n height: containerSize.height\n };\n } else {\n return {\n width: containerSize.width,\n height: containerSize.width / elementAspectRatio\n };\n }\n case \"fill\":\n return {\n width: containerSize.width,\n height: containerSize.height\n };\n default:\n return {\n width: elementSize.width,\n height: elementSize.height\n };\n }\n}\n\nasync function blobUrlToFile(blobUrl, fileName) {\n const response = await fetch(blobUrl);\n const blob = await response.blob();\n return new File([blob], fileName, { type: blob.type });\n}\nfunction saveAsFile(content, type, name) {\n const blob = typeof content === \"string\" ? new Blob([content], { type }) : content;\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = name;\n a.click();\n URL.revokeObjectURL(url);\n}\nasync function downloadFile(url, filename) {\n try {\n const response = await fetch(url);\n const blob = await response.blob();\n const downloadUrl = window.URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = downloadUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n window.URL.revokeObjectURL(downloadUrl);\n } catch (error) {\n console.error(\"Error downloading file:\", error);\n throw error;\n }\n}\n\nasync function detectMediaTypeFromUrl(url) {\n try {\n const response = await fetch(url, { method: \"HEAD\" });\n const contentType = response.headers.get(\"Content-Type\");\n if (!contentType) return null;\n if (contentType.startsWith(\"image/\")) return \"image\";\n if (contentType.startsWith(\"video/\")) return \"video\";\n if (contentType.startsWith(\"audio/\")) return \"audio\";\n return null;\n } catch (error) {\n console.error(\"Fetch failed:\", error);\n return null;\n }\n}\n\nexport { blobUrlToFile, detectMediaTypeFromUrl, downloadFile, getAudioDuration, getImageDimensions, getObjectFitSize, getScaledDimensions, getThumbnail, getVideoMeta, limit, saveAsFile };\n//# sourceMappingURL=index.mjs.map\n","import {\r\n Canvas as FabricCanvas,\r\n FabricText,\r\n Group,\r\n FabricImage,\r\n Rect,\r\n Shadow,\r\n} from \"fabric\";\r\nimport { convertToCanvasPosition } from \"../helpers/canvas.util\";\r\nimport {\r\n CanvasElement,\r\n CanvasMetadata,\r\n CaptionProps,\r\n FrameEffect,\r\n} from \"../types\";\r\nimport {\r\n DEFAULT_CAPTION_PROPS,\r\n DEFAULT_TEXT_PROPS,\r\n} from \"../helpers/constants\";\r\nimport { disabledControl, rotateControl } from \"./element-controls\";\r\nimport { getObjectFitSize, getThumbnail } from \"@twick/media-utils\";\r\n\r\n/**\r\n * Add a text element for the canvas.\r\n *\r\n * @param {Object} params - The parameters for creating the text element.\r\n * @param {CanvasElement} params.element - The canvas element configuration.\r\n * @param {number} params.index - The z-index of the element.\r\n * @param {CanvasMetadata} params.canvasMetadata - Metadata about the canvas, including scale and dimensions.\r\n * @returns {FabricText} The configured Fabric.js text object.\r\n */\r\nexport const addTextElement = ({\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.x || 0,\r\n element.props?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n const text = new FabricText(element.props?.text || \"\", {\r\n left: x,\r\n top: y,\r\n originX: \"center\",\r\n originY: \"center\",\r\n angle: element.props?.rotation || 0,\r\n fontSize: Math.round(\r\n (element.props?.fontSize || DEFAULT_TEXT_PROPS.size) *\r\n canvasMetadata.scaleX\r\n ),\r\n fontFamily: element.props?.fontFamily || DEFAULT_TEXT_PROPS.family,\r\n fontStyle: element.props?.fontStyle || \"normal\",\r\n fontWeight: element.props?.fontWeight || \"normal\",\r\n fill: element.props?.fill || DEFAULT_TEXT_PROPS.fill,\r\n stroke: element.props?.stroke || DEFAULT_TEXT_PROPS.stroke,\r\n strokeWidth: element.props?.lineWidth || DEFAULT_TEXT_PROPS.lineWidth,\r\n shadow: element.props?.shadowColor\r\n ? new Shadow({\r\n offsetX:\r\n element.props?.shadowOffset?.length &&\r\n element.props?.shadowOffset?.length > 1\r\n ? element.props.shadowOffset[0] / 2\r\n : 1,\r\n offsetY:\r\n element.props?.shadowOffset?.length &&\r\n element.props?.shadowOffset.length > 1\r\n ? element.props.shadowOffset[1] / 2\r\n : 1,\r\n blur: (element.props?.shadowBlur || 2) / 2,\r\n color: element.props?.shadowColor,\r\n })\r\n : undefined,\r\n });\r\n\r\n // Assign metadata and custom controls\r\n text.set(\"id\", element.id);\r\n text.set(\"zIndex\", index);\r\n\r\n // Disable unwanted control points\r\n text.controls.mt = disabledControl;\r\n text.controls.mb = disabledControl;\r\n text.controls.ml = disabledControl;\r\n text.controls.mr = disabledControl;\r\n text.controls.bl = disabledControl;\r\n text.controls.br = disabledControl;\r\n text.controls.tl = disabledControl;\r\n text.controls.tr = disabledControl;\r\n text.controls.mtr = rotateControl;\r\n\r\n canvas.add(text);\r\n return text;\r\n};\r\n\r\nconst setImageProps = ({\r\n img,\r\n element,\r\n index,\r\n canvasMetadata,\r\n}: {\r\n img: FabricImage;\r\n element: CanvasElement;\r\n index: number;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const width =\r\n (element.props?.width || 0) * canvasMetadata.scaleX || canvasMetadata.width;\r\n const height =\r\n (element.props?.height || 0) * canvasMetadata.scaleY ||\r\n canvasMetadata.height;\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.x || 0,\r\n element.props?.y || 0,\r\n canvasMetadata\r\n );\r\n console.log(width, height, x, y);\r\n img.set(\"id\", element.id);\r\n img.set(\"zIndex\", index);\r\n img.set(\"width\", width);\r\n img.set(\"height\", height);\r\n img.set(\"left\", x);\r\n img.set(\"top\", y);\r\n img.set(\"selectable\", true);\r\n img.set(\"hasControls\", true);\r\n img.set(\"touchAction\", \"all\");\r\n};\r\n\r\n/**\r\n * Add a caption element for the canvas based on provided props.\r\n *\r\n * @param {Object} params - Parameters for creating the caption.\r\n * @param {CanvasElement} params.element - The canvas element configuration.\r\n * @param {FabricCanvas} params.canvas - The Fabric.js canvas instance.\r\n * @param {number} params.index - The z-index of the element.\r\n * @param {CaptionProps} params.captionProps - Default and user-defined caption properties.\r\n * @param {CanvasMetadata} params.canvasMetadata - Metadata about the canvas, including scale and dimensions.\r\n * @returns {FabricText} The configured Fabric.js caption object.\r\n */\r\nexport const addCaptionElement = ({\r\n element,\r\n index,\r\n canvas,\r\n captionProps,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n captionProps: CaptionProps;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.pos?.x || captionProps?.pos?.x || 0,\r\n element.props?.pos?.y || captionProps?.pos?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n const caption = new FabricText(element.props?.text || \"\", {\r\n left: x,\r\n top: y,\r\n originX: \"center\",\r\n originY: \"center\",\r\n angle: element.props?.rotation || 0,\r\n fontSize: Math.round(\r\n (element.props?.font?.size ||\r\n captionProps.font?.size ||\r\n DEFAULT_CAPTION_PROPS.size) * canvasMetadata.scaleX\r\n ),\r\n fontFamily:\r\n element.props?.font?.family ||\r\n captionProps.font?.family ||\r\n DEFAULT_CAPTION_PROPS.family,\r\n fill:\r\n element.props?.fill ||\r\n captionProps.color?.text ||\r\n DEFAULT_CAPTION_PROPS.fill,\r\n fontWeight: DEFAULT_CAPTION_PROPS.fontWeight,\r\n stroke: element.props?.stroke || DEFAULT_CAPTION_PROPS.stroke,\r\n shadow: new Shadow({\r\n offsetX:\r\n element.props?.shadowOffset?.[0] ||\r\n DEFAULT_CAPTION_PROPS.shadowOffset?.[0],\r\n offsetY:\r\n element.props?.shadowOffset?.[1] ||\r\n DEFAULT_CAPTION_PROPS.shadowOffset?.[1],\r\n blur: element.props?.shadowBlur || DEFAULT_CAPTION_PROPS.shadowBlur,\r\n color: element.props?.shadowColor || DEFAULT_CAPTION_PROPS.shadowColor,\r\n }),\r\n strokeWidth: element.props?.lineWidth || DEFAULT_CAPTION_PROPS.lineWidth,\r\n });\r\n\r\n // Assign metadata and custom controls\r\n caption.set(\"id\", element.id);\r\n caption.set(\"zIndex\", index);\r\n\r\n // Disable unwanted control points\r\n caption.controls.mt = disabledControl;\r\n caption.controls.mb = disabledControl;\r\n caption.controls.ml = disabledControl;\r\n caption.controls.mr = disabledControl;\r\n caption.controls.bl = disabledControl;\r\n caption.controls.br = disabledControl;\r\n caption.controls.tl = disabledControl;\r\n caption.controls.tr = disabledControl;\r\n caption.controls.mtr = disabledControl;\r\n\r\n canvas.add(caption);\r\n return caption;\r\n};\r\n\r\n/**\r\n * Add a video frame as an image and returns it as a canvas element.\r\n *\r\n * @param {Object} params - Parameters for creating the video element.\r\n * @param {CanvasElement} params.element - The canvas element configuration.\r\n * @param {FabricCanvas} params.canvas - The Fabric.js canvas instance.\r\n * @param {number} params.index - The z-index of the element.\r\n * @param {number} params.seekTime - The seek time for extracting the video frame.\r\n * @param {CanvasMetadata} params.canvasMetadata - Metadata about the canvas, including scale and dimensions.\r\n * @param {FrameEffect} [params.currentFrameEffect] - Optional frame effect to apply to the video.\r\n * @returns {Promise<FabricImage | Group | undefined>} A Fabric.js image or group object for the video frame.\r\n */\r\nexport const addVideoElement = async ({\r\n element,\r\n index,\r\n canvas,\r\n snapTime,\r\n canvasMetadata,\r\n currentFrameEffect,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n snapTime: number;\r\n canvasMetadata: CanvasMetadata;\r\n currentFrameEffect?: FrameEffect;\r\n}) => {\r\n try {\r\n const thumbnailUrl = await getThumbnail(\r\n element?.props?.src || \"\",\r\n snapTime\r\n );\r\n if (!thumbnailUrl) {\r\n console.error(\"Failed to get thumbnail\");\r\n return;\r\n }\r\n\r\n return addImageElement({\r\n imageUrl: thumbnailUrl,\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect,\r\n });\r\n } catch (error) {\r\n console.error(\"Error loading image:\", error);\r\n }\r\n};\r\n\r\n/**\r\n * Add an image element into a Fabric.js image object and optionally groups it with a frame.\r\n *\r\n * @param element - The image element containing properties like source and frame information.\r\n * @param index - The z-index for ordering the element on the canvas.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata of the canvas, including dimensions and scale factors.\r\n * @param currentFrameEffect - Optional frame effect to apply to the image.\r\n * @param imageUrl - Optional The url of the image to be added to the canvas.\r\n * @returns A Fabric.js image object or a group with an image and frame.\r\n */\r\nexport const addImageElement = async ({\r\n imageUrl,\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect\r\n}: {\r\n imageUrl?: string;\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n currentFrameEffect?: FrameEffect;\r\n}) => {\r\n try {\r\n // Load the image from the provided source URL\r\n const img = await FabricImage.fromURL(imageUrl ||element.props.src || \"\");\r\n img.set({\r\n originX: \"center\",\r\n originY: \"center\",\r\n lockMovementX: false,\r\n lockMovementY: false,\r\n lockUniScaling: true,\r\n hasControls: false,\r\n selectable: false,\r\n });\r\n\r\n // Return the group if a frame is defined, otherwise return the image\r\n if (element.frame) {\r\n return addMediaGroup({\r\n element,\r\n img,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect\r\n });\r\n } else {\r\n setImageProps({ img, element, index, canvasMetadata });\r\n canvas.add(img);\r\n return img;\r\n }\r\n } catch (error) {\r\n console.error(\"Error loading image:\", error);\r\n }\r\n};\r\n\r\n/**\r\n * Add a Fabric.js group combining an image and its associated frame,\r\n * applying styling, positioning, and scaling based on the given properties.\r\n *\r\n * @param element - The image element containing properties like frame, position, and styling.\r\n * @param img - The Fabric.js image object to be included in the group.\r\n * @param index - The z-index for ordering the group on the canvas.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata of the canvas, including dimensions and scale factors.\r\n * @param currentFrameEffect - Optional current frame effect to override default frame properties.\r\n * @returns A Fabric.js group containing the image and frame with configured properties.\r\n */\r\nconst addMediaGroup = ({\r\n element,\r\n img,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect,\r\n}: {\r\n element: CanvasElement;\r\n img: FabricImage;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n currentFrameEffect?: FrameEffect;\r\n}) => {\r\n let frameSize;\r\n let angle;\r\n let framePosition;\r\n let frameRadius = 0;\r\n if (currentFrameEffect) {\r\n frameSize = {\r\n width:\r\n (currentFrameEffect.props.frameSize?.[0] || 0) *\r\n canvasMetadata.scaleX || canvasMetadata.width,\r\n height:\r\n (currentFrameEffect.props.frameSize?.[1] || 0) *\r\n canvasMetadata.scaleY || canvasMetadata.height,\r\n };\r\n angle = currentFrameEffect.props.rotation || 0;\r\n framePosition = currentFrameEffect.props.framePosition;\r\n if (currentFrameEffect.props.shape === \"circle\") {\r\n frameRadius = frameSize.width / 2;\r\n } else {\r\n frameRadius = currentFrameEffect?.props?.radius || 0;\r\n }\r\n } else {\r\n frameRadius = element?.frame?.radius || 0;\r\n frameSize = {\r\n width:\r\n (element?.frame?.size?.[0] || 0) * canvasMetadata.scaleX ||\r\n canvasMetadata.width,\r\n height:\r\n (element?.frame?.size?.[1] || 0) * canvasMetadata.scaleY ||\r\n canvasMetadata.height,\r\n };\r\n angle = element?.frame?.rotation || 0;\r\n framePosition = {\r\n x: element?.frame?.x || 0,\r\n y: element?.frame?.y || 0,\r\n };\r\n }\r\n\r\n const newSize = getObjectFitSize(\r\n element.objectFit,\r\n { width: img.width!, height: img.height! },\r\n frameSize\r\n );\r\n\r\n const frameRect = new Rect({\r\n originX: \"center\",\r\n originY: \"center\",\r\n lockMovementX: false,\r\n lockMovementY: false,\r\n lockUniScaling: true,\r\n hasControls: false,\r\n selectable: false,\r\n width: frameSize.width,\r\n height: frameSize.height,\r\n stroke: element?.frame?.stroke || \"#ffffff\",\r\n strokeWidth: element?.frame?.lineWidth || 0,\r\n hasRotatingPoint: true,\r\n rx: frameRadius || 0,\r\n ry: frameRadius || 0,\r\n });\r\n\r\n img.set({\r\n lockUniScaling: true,\r\n originX: \"center\",\r\n originY: \"center\",\r\n width: newSize.width,\r\n height: newSize.height,\r\n });\r\n\r\n\r\n const { x, y } = convertToCanvasPosition(\r\n framePosition?.x || 0,\r\n framePosition?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n const groupProps = {\r\n left: x,\r\n top: y,\r\n width: frameSize.width,\r\n height: frameSize.height,\r\n angle: angle,\r\n };\r\n\r\n // Customize the control points for the group\r\n // Change only the top control to a different style, keep others as circles\r\n\r\n const group = new Group([frameRect, img], {\r\n ...groupProps,\r\n originX: \"center\",\r\n originY: \"center\",\r\n angle: groupProps.angle,\r\n selectable: true,\r\n hasControls: true,\r\n hasBorders: true,\r\n clipPath: frameRect,\r\n });\r\n\r\n group.controls.mt = disabledControl;\r\n group.controls.mb = disabledControl;\r\n group.controls.ml = disabledControl;\r\n group.controls.mr = disabledControl;\r\n group.controls.mtr = rotateControl;\r\n\r\n group.set(\"id\", element.id);\r\n group.set(\"zIndex\", index);\r\n canvas.add(group);\r\n return group;\r\n};\r\n\r\n/**\r\n * Add a rectangular Fabric.js element based on the provided canvas element data.\r\n *\r\n * @param element - The canvas element containing properties for the rectangle.\r\n * @param index - The zIndex value used to determine the rendering order.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @returns A Fabric.js Rect object configured with the specified properties.\r\n */\r\nexport const addRectElement = ({\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n // Convert element's position to canvas coordinates\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.x || 0,\r\n element.props?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n // Create a new rectangular Fabric.js object\r\n const rect = new Rect({\r\n left: x, // X-coordinate on the canvas\r\n top: y, // Y-coordinate on the canvas\r\n originX: \"center\", // Center the rectangle based on its position\r\n originY: \"center\", // Center the rectangle based on its position\r\n angle: element.props?.rotation || 0, // Rotation angle\r\n rx: (element.props?.radius || 0) * canvasMetadata.scaleX, // Horizontal radius for rounded corners\r\n ry: (element.props?.radius || 0) * canvasMetadata.scaleY, // Vertical radius for rounded corners\r\n stroke: element.props?.stroke || \"#000000\", // Stroke color\r\n strokeWidth: (element.props?.lineWidth || 0) * canvasMetadata.scaleX, // Scaled stroke width\r\n fill: element.props?.fill || \"#000000\", // Fill color\r\n opacity: element.props?.opacity || 1, // Opacity level\r\n width: (element.props?.width || 0) * canvasMetadata.scaleX, // Scaled width\r\n height: (element.props?.height || 0) * canvasMetadata.scaleY, // Scaled height\r\n });\r\n\r\n // Set custom properties for the rectangle\r\n rect.set(\"id\", element.id); // Unique identifier for the rectangle\r\n rect.set(\"zIndex\", index); // zIndex determines rendering order\r\n\r\n // Set custom control for rotation\r\n rect.controls.mtr = rotateControl;\r\n\r\n canvas.add(rect);\r\n return rect;\r\n};\r\n\r\n/**\r\n * Add a background color to the canvas.\r\n *\r\n * @param element - The canvas element containing properties for the background.\r\n * @param index - The zIndex value used to determine the rendering order.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @returns A Fabric.js Rect object configured with the specified properties.\r\n */\r\nexport const addBackgroundColor = ({\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const bgRect = new Rect({\r\n width: canvasMetadata.width,\r\n height: canvasMetadata.height,\r\n left: canvasMetadata.width / 2,\r\n top: canvasMetadata.height / 2,\r\n fill: element.backgoundColor ?? \"#000000\",\r\n originX: \"center\",\r\n originY: \"center\",\r\n hasControls: false,\r\n hasBorders: false,\r\n selectable: false,\r\n });\r\n\r\n bgRect.controls.mt = disabledControl;\r\n bgRect.controls.mb = disabledControl;\r\n bgRect.controls.ml = disabledControl;\r\n bgRect.controls.mr = disabledControl;\r\n bgRect.controls.bl = disabledControl;\r\n bgRect.controls.br = disabledControl;\r\n bgRect.controls.tl = disabledControl;\r\n bgRect.controls.tr = disabledControl;\r\n bgRect.controls.mtr = disabledControl;\r\n bgRect.set(\"zIndex\", index - 0.5);\r\n\r\n canvas.add(bgRect);\r\n return bgRect;\r\n};\r\n","import { useRef, useState } from \"react\";\r\nimport { Canvas as FabricCanvas, FabricObject } from \"fabric\";\r\nimport { Dimensions } from \"@twick/media-utils\";\r\nimport { CanvasMetadata, CanvasProps, CanvasElement } from \"../types\";\r\nimport {\r\n clearCanvas,\r\n convertToVideoPosition,\r\n createCanvas,\r\n getCurrentFrameEffect,\r\n reorderElementsByZIndex,\r\n} from \"../helpers/canvas.util\";\r\nimport { CANVAS_OPERATIONS, ELEMENT_TYPES } from \"../helpers/constants\";\r\nimport {\r\n addImageElement,\r\n addVideoElement,\r\n addRectElement,\r\n addTextElement,\r\n addCaptionElement,\r\n addBackgroundColor,\r\n} from \"../components/elements\";\r\n\r\n/**\r\n * Custom hook to manage a Fabric.js canvas and associated operations.\r\n *\r\n * @param onCanvasReady - Callback executed when the canvas is ready.\r\n * @param onCanvasOperation - Callback executed on canvas operations such as item selection or updates.\r\n * @returns Canvas-related functions and state.\r\n */\r\nexport const useTwickCanvas = ({\r\n onCanvasReady,\r\n onCanvasOperation,\r\n}: {\r\n onCanvasReady?: (canvas: FabricCanvas) => void;\r\n onCanvasOperation?: (operation: string, data: any) => void;\r\n}) => {\r\n const [twickCanvas, setTwickCanvas] = useState<FabricCanvas | null>(null); // Canvas instance\r\n const elementMap = useRef<Record<string, any>>({}); // Maps element IDs to their data\r\n const elementFrameMap = useRef<Record<string, any>>({}); // Maps element IDs to their frame effects\r\n const twickCanvasRef = useRef<FabricCanvas | null>(null);\r\n const videoSizeRef = useRef<Dimensions>({ width: 1, height: 1 }); // Stores the video dimensions\r\n const canvasMetadataRef = useRef<CanvasMetadata>({\r\n width: 0,\r\n height: 0,\r\n aspectRatio: 0,\r\n scaleX: 1,\r\n scaleY: 1,\r\n }); // Metadata for the canvas\r\n\r\n /**\r\n * Updates canvas metadata when the video size changes.\r\n *\r\n * @param videoSize - New video dimensions.\r\n */\r\n const onVideoSizeChange = (videoSize: Dimensions) => {\r\n if (videoSize) {\r\n videoSizeRef.current = videoSize;\r\n canvasMetadataRef.current.scaleX =\r\n canvasMetadataRef.current.width / videoSize.width;\r\n canvasMetadataRef.current.scaleY =\r\n canvasMetadataRef.current.height / videoSize.height;\r\n }\r\n };\r\n\r\n /**\r\n * Initializes the Fabric.js canvas with the provided configuration.\r\n *\r\n * @param props - Canvas configuration properties.\r\n */\r\n const buildCanvas = ({\r\n videoSize,\r\n canvasSize,\r\n canvasRef,\r\n backgroundColor = \"#000000\",\r\n selectionBorderColor = \"#2563eb\",\r\n selectionLineWidth = 2,\r\n uniScaleTransform = true,\r\n enableRetinaScaling = true,\r\n touchZoomThreshold = 10,\r\n }: CanvasProps) => {\r\n if (!canvasRef) return;\r\n\r\n // Dispose of the old canvas if it exists\r\n if (twickCanvasRef.current) {\r\n console.log(\"Destroying twickCanvas\");\r\n twickCanvasRef.current.off(\"mouse:up\", handleMouseUp);\r\n twickCanvasRef.current.dispose();\r\n }\r\n\r\n // Create a new canvas and update metadata\r\n const { canvas, canvasMetadata } = createCanvas({\r\n videoSize,\r\n canvasSize,\r\n canvasRef,\r\n backgroundColor,\r\n selectionBorderColor,\r\n selectionLineWidth,\r\n uniScaleTransform,\r\n enableRetinaScaling,\r\n touchZoomThreshold,\r\n });\r\n canvasMetadataRef.current = canvasMetadata;\r\n videoSizeRef.current = videoSize;\r\n // Attach event listeners\r\n canvas?.on(\"mouse:up\", handleMouseUp);\r\n setTwickCanvas(canvas);\r\n twickCanvasRef.current = canvas;\r\n // Notify when canvas is ready\r\n if (onCanvasReady) {\r\n onCanvasReady(canvas);\r\n }\r\n };\r\n\r\n /**\r\n * Handles mouse up events on the canvas.\r\n *\r\n * @param event - Event object.\r\n */\r\n const handleMouseUp = (event: any) => {\r\n if (event.target) {\r\n const object: FabricObject = event.target;\r\n const elementId = object.get(\"id\");\r\n if (event.transform?.action === \"drag\") {\r\n const original = event.transform.original;\r\n if (object.left === original.left && object.top === original.top) {\r\n onCanvasOperation?.(\r\n CANVAS_OPERATIONS.ITEM_SELECTED,\r\n elementMap.current[elementId]\r\n );\r\n return;\r\n }\r\n }\r\n switch (event.transform?.action) {\r\n case \"drag\":\r\n case \"scale\":\r\n case \"scaleX\":\r\n case \"scaleY\":\r\n case \"rotate\":\r\n const { x, y } = convertToVideoPosition(\r\n object.left,\r\n object.top,\r\n canvasMetadataRef.current,\r\n videoSizeRef.current\r\n );\r\n if (elementMap.current[elementId].type === \"caption\") {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n props: {\r\n ...elementMap.current[elementId].props,\r\n pos: {\r\n x,\r\n y,\r\n },\r\n },\r\n };\r\n onCanvasOperation?.(\r\n CANVAS_OPERATIONS.ITEM_UPDATED,\r\n elementMap.current[elementId]\r\n );\r\n } else {\r\n if (object?.type === \"group\") {\r\n const currentFrameEffect = elementFrameMap.current[elementId];\r\n let updatedFrameSize;\r\n if (currentFrameEffect) {\r\n updatedFrameSize = [\r\n currentFrameEffect.props.frameSize[0] * object.scaleX,\r\n currentFrameEffect.props.frameSize[1] * object.scaleY,\r\n ];\r\n } else {\r\n updatedFrameSize = [\r\n elementMap.current[elementId].frame.size[0] * object.scaleX,\r\n elementMap.current[elementId].frame.size[1] * object.scaleY,\r\n ];\r\n }\r\n\r\n if (currentFrameEffect) {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n frameEffects: (\r\n elementMap.current[elementId].frameEffects || []\r\n ).map((frameEffect: any) =>\r\n frameEffect.id === currentFrameEffect?.id\r\n ? {\r\n ...frameEffect,\r\n props: {\r\n ...frameEffect.props,\r\n framePosition: {\r\n x,\r\n y,\r\n },\r\n frameSize: updatedFrameSize,\r\n },\r\n }\r\n : frameEffect\r\n ),\r\n };\r\n elementFrameMap.current[elementId] = {\r\n ...elementFrameMap.current[elementId],\r\n framePosition: {\r\n x,\r\n y,\r\n },\r\n frameSize: updatedFrameSize,\r\n };\r\n } else {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n frame: {\r\n ...elementMap.current[elementId].frame,\r\n rotation: object.angle,\r\n size: updatedFrameSize,\r\n x,\r\n y,\r\n },\r\n };\r\n }\r\n } else {\r\n if (object?.type === \"text\") {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n props: {\r\n ...elementMap.current[elementId].props,\r\n rotation: object.angle,\r\n x,\r\n y,\r\n },\r\n };\r\n } else {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n props: {\r\n ...elementMap.current[elementId].props,\r\n rotation: object.angle,\r\n width:\r\n elementMap.current[elementId].props.width * object.scaleX,\r\n height:\r\n elementMap.current[elementId].props.height *\r\n object.scaleY,\r\n x,\r\n y,\r\n },\r\n };\r\n }\r\n }\r\n onCanvasOperation?.(\r\n CANVAS_OPERATIONS.ITEM_UPDATED,\r\n elementMap.current[elementId]\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n };\r\n\r\n /**\r\n * Sets elements to the canvas.\r\n *\r\n * @param options - Object containing elements, seek time, and additional options.\r\n */\r\n const setCanvasElements = async ({\r\n elements,\r\n seekTime = 0,\r\n captionProps,\r\n cleanAndAdd = false,\r\n }: {\r\n elements: CanvasElement[];\r\n seekTime?: number;\r\n captionProps?: any;\r\n cleanAndAdd?: boolean;\r\n }) => {\r\n if (!twickCanvas) {\r\n console.warn(\"Canvas not initialized\");\r\n return;\r\n }\r\n\r\n try {\r\n if (cleanAndAdd) {\r\n // Clear canvas before adding new elements\r\n clearCanvas(twickCanvas);\r\n }\r\n\r\n await Promise.all(\r\n elements.map(async (element, index) => {\r\n try {\r\n if (!element) {\r\n console.warn(\"Element not found\");\r\n return;\r\n }\r\n await addElementToCanvas({\r\n element,\r\n index,\r\n reorder: false,\r\n seekTime,\r\n captionProps,\r\n });\r\n } catch (error) {\r\n console.error(`Error adding element ${element.id}:`, error);\r\n }\r\n })\r\n );\r\n reorderElementsByZIndex(twickCanvas);\r\n } catch (error) {\r\n console.error(\"Error in setCanvasElements:\", error);\r\n }\r\n };\r\n\r\n /**\r\n * Add element to the canvas.\r\n *\r\n * @param options - Object containing elements, seek time, and additional options.\r\n */\r\n const addElementToCanvas = async ({\r\n element,\r\n index,\r\n reorder = true,\r\n seekTime,\r\n captionProps,\r\n }: {\r\n element: CanvasElement;\r\n index: number;\r\n reorder: boolean;\r\n seekTime?: number;\r\n captionProps?: any;\r\n }) => {\r\n if (!twickCanvas) {\r\n console.warn(\"Canvas not initialized\");\r\n return;\r\n }\r\n // Add element based on type\r\n switch (element.type) {\r\n case ELEMENT_TYPES.VIDEO:\r\n const currentFrameEffect = getCurrentFrameEffect(element, seekTime || 0);\r\n elementFrameMap.current[element.id] = currentFrameEffect;\r\n const snapTime =\r\n ((seekTime || 0) - (element?.s || 0)) *\r\n (element?.props?.playbackRate || 1) +\r\n (element?.props?.time || 0);\r\n await addVideoElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n currentFrameEffect,\r\n snapTime,\r\n });\r\n if (element.timelineType === \"scene\") {\r\n await addBackgroundColor({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n }\r\n break;\r\n case ELEMENT_TYPES.IMAGE:\r\n await addImageElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n if (element.timelineType === \"scene\") {\r\n await addBackgroundColor({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n }\r\n break;\r\n case ELEMENT_TYPES.RECT:\r\n await addRectElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n break;\r\n case ELEMENT_TYPES.TEXT:\r\n await addTextElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n break;\r\n case ELEMENT_TYPES.CAPTION:\r\n await addCaptionElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n captionProps,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n break;\r\n default:\r\n break;\r\n }\r\n elementMap.current[element.id] = element;\r\n if (reorder) {\r\n reorderElementsByZIndex(twickCanvas);\r\n }\r\n };\r\n\r\n return {\r\n twickCanvas,\r\n buildCanvas,\r\n onVideoSizeChange,\r\n addElementToCanvas,\r\n setCanvasElements,\r\n };\r\n};\r\n"],"names":["FabricCanvas"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/helpers/constants.ts","../src/helpers/browser.ts","../src/helpers/canvas.util.ts","../src/components/element-controls.tsx","../../media-utils/dist/index.mjs","../src/components/elements.tsx","../src/hooks/use-twick-canvas.ts"],"sourcesContent":["export const DEFAULT_TEXT_PROPS = {\r\n family: \"Poppins\",\r\n size: 48,\r\n fill: \"#FFFFFF\",\r\n stroke: \"#000000\",\r\n lineWidth: 0,\r\n }\r\n \r\nexport const DEFAULT_CAPTION_PROPS = {\r\n family: \"Poppins\",\r\n size: 48,\r\n fill: \"#FFFFFF\",\r\n fontWeight: 600,\r\n color: {\r\n text: \"#FFFFFF\",\r\n background: \"#000000\",\r\n highlight: \"#FFFFFF\",\r\n },\r\n stroke: \"#000000\",\r\n lineWidth: 0.2,\r\n shadowColor: \"#000000\",\r\n shadowBlur: 2,\r\n shadowOffset: [0, 0],\r\n}\r\n\r\nexport const CANVAS_OPERATIONS = {\r\n ITEM_SELECTED: \"ITEM_SELECTED\",\r\n ITEM_UPDATED: \"ITEM_UPDATED\",\r\n ITEM_DELETED: \"ITEM_DELETED\",\r\n ITEM_ADDED: \"ITEM_ADDED\",\r\n ITEM_GROUPED: \"ITEM_GROUPED\",\r\n ITEM_UNGROUPED: \"ITEM_UNGROUPED\",\r\n}\r\n\r\nexport const ELEMENT_TYPES = {\r\n TEXT: \"text\",\r\n CAPTION: \"caption\",\r\n IMAGE: \"image\",\r\n VIDEO: \"video\",\r\n RECT: \"rect\",\r\n BACKGROUND_COLOR: \"backgroundColor\",\r\n}\r\n","export const isBrowser = typeof window !== 'undefined';\r\n\r\nexport const isCanvasSupported = isBrowser && !!window.HTMLCanvasElement;\r\n\r\nexport const isVideoSupported = isBrowser && !!window.HTMLVideoElement;\r\n\r\nexport function assertBrowser() {\r\n if (!isBrowser) {\r\n throw new Error('This code can only run in a browser environment');\r\n }\r\n}\r\n\r\nexport function assertCanvasSupport() {\r\n if (!isCanvasSupported) {\r\n throw new Error('Canvas is not supported in this environment');\r\n }\r\n}\r\n\r\nexport function assertVideoSupport() {\r\n if (!isVideoSupported) {\r\n throw new Error('Video is not supported in this environment');\r\n }\r\n} ","import {\r\n Canvas as FabricCanvas,\r\n} from \"fabric\";\r\nimport { CanvasMetadata, CanvasProps } from \"../types\";\r\nimport { Dimensions, Position } from \"@twick/media-utils\";\r\nimport { assertBrowser, assertCanvasSupport } from \"./browser\";\r\n\r\n/**\r\n * Creates and initializes a Fabric.js canvas with specified configurations.\r\n *\r\n * @param videoSize - The dimensions of the video.\r\n * @param canvasSize - The dimensions of the canvas.\r\n * @param canvasContainer - The HTML container for the canvas.\r\n * @param backgroundColor - Background color of the canvas (default: black).\r\n * @param selectionBorderColor - Border color for selected objects (default: blue).\r\n * @param selectionLineWidth - Width of the selection border (default: 2).\r\n * @param uniScaleTransform - Ensures uniform scaling of objects (default: true).\r\n * @param enableRetinaScaling - Enables retina scaling for higher DPI (default: true).\r\n * @param touchZoomThreshold - Threshold for touch zoom interactions (default: 10).\r\n * @returns An object containing the initialized canvas and its metadata.\r\n */\r\nexport const createCanvas = ({\r\n videoSize,\r\n canvasSize,\r\n canvasRef,\r\n backgroundColor = \"#000000\",\r\n selectionBorderColor = \"#2563eb\",\r\n selectionLineWidth = 2,\r\n uniScaleTransform = true,\r\n enableRetinaScaling = true,\r\n touchZoomThreshold = 10,\r\n}: CanvasProps): { canvas: FabricCanvas; canvasMetadata: CanvasMetadata } => {\r\n assertBrowser();\r\n assertCanvasSupport();\r\n\r\n // Metadata for scaling and positioning on the canvas\r\n const canvasMetadata = {\r\n width: canvasSize.width,\r\n height: canvasSize.height,\r\n aspectRatio: canvasSize.width / canvasSize.height,\r\n scaleX: canvasSize.width / videoSize.width,\r\n scaleY: canvasSize.height / videoSize.height,\r\n };\r\n\r\n // Create and configure the Fabric.js canvas\r\n const canvas = new FabricCanvas(canvasRef, {\r\n backgroundColor,\r\n width: canvasSize.width,\r\n height: canvasSize.height,\r\n preserveObjectStacking: true,\r\n enableRetinaScaling,\r\n selectionBorderColor,\r\n selectionLineWidth,\r\n uniScaleTransform,\r\n touchZoomThreshold,\r\n renderOnAddRemove: false,\r\n stateful: false,\r\n selection: true,\r\n skipTargetFind: false,\r\n controlsAboveOverlay: true,\r\n });\r\n\r\n // Set dimensions and render canvas\r\n if (canvasRef) {\r\n canvas.setDimensions({\r\n width: canvasMetadata.width,\r\n height: canvasMetadata.height,\r\n });\r\n canvas.renderAll();\r\n }\r\n\r\n return {\r\n canvas,\r\n canvasMetadata,\r\n };\r\n};\r\n\r\n/**\r\n * Reorders elements on the canvas based on their zIndex property.\r\n *\r\n * @param canvas - The Fabric.js canvas instance.\r\n */\r\nexport const reorderElementsByZIndex = (canvas: FabricCanvas) => {\r\n if (!canvas) return;\r\n const backgroundColor = canvas.backgroundColor;\r\n\r\n const objects = canvas.getObjects();\r\n console.log(\"objects\", objects);\r\n // Sort objects by zIndex and re-add to the canvas in order\r\n objects.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));\r\n\r\n canvas.clear();\r\n canvas.backgroundColor = backgroundColor;\r\n\r\n objects.forEach((obj) => canvas.add(obj));\r\n canvas.renderAll();\r\n};\r\n\r\n/**\r\n * Clears all elements from the canvas and re-renders it.\r\n *\r\n * @param canvas - The Fabric.js canvas instance.\r\n */\r\nexport const clearCanvas = (canvas: FabricCanvas) => {\r\n if (!canvas) return;\r\n canvas.clear();\r\n canvas.renderAll();\r\n};\r\n\r\n/**\r\n * Converts a position from the video coordinate space to the canvas coordinate space.\r\n *\r\n * @param x - X-coordinate in video space.\r\n * @param y - Y-coordinate in video space.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @returns The corresponding position in canvas space.\r\n */\r\nexport const convertToCanvasPosition = (\r\n x: number,\r\n y: number,\r\n canvasMetadata: CanvasMetadata\r\n): Position => {\r\n return {\r\n x: x * canvasMetadata.scaleX + canvasMetadata.width / 2,\r\n y: y * canvasMetadata.scaleY + canvasMetadata.height / 2,\r\n };\r\n};\r\n\r\n/**\r\n * Converts a position from the canvas coordinate space to the video coordinate space.\r\n *\r\n * @param x - X-coordinate in canvas space.\r\n * @param y - Y-coordinate in canvas space.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @param videoSize - Dimensions of the video.\r\n * @returns The corresponding position in video space.\r\n */\r\nexport const convertToVideoPosition = (\r\n x: number,\r\n y: number,\r\n canvasMetadata: CanvasMetadata,\r\n videoSize: Dimensions\r\n): Position => {\r\n return {\r\n x: x / canvasMetadata.scaleX - videoSize.width / 2,\r\n y: y / canvasMetadata.scaleY - videoSize.height / 2,\r\n };\r\n};\r\n\r\n/**\r\n * Retrieves the current frame effect for a given seek time.\r\n *\r\n * @param item - The item containing frame effects.\r\n * @param seekTime - The current time to match against frame effects.\r\n * @returns The current frame effect active at the given seek time, if any.\r\n */\r\nexport const getCurrentFrameEffect = (item: any, seekTime: number) => {\r\n let currentFrameEffect;\r\n for (let i = 0; i < item?.frameEffects?.length; i++) {\r\n if (\r\n item.frameEffects[i].s <= seekTime &&\r\n item.frameEffects[i].e >= seekTime\r\n ) {\r\n currentFrameEffect = item.frameEffects[i];\r\n break;\r\n }\r\n }\r\n return currentFrameEffect;\r\n};\r\n","import { Control, controlsUtils } from \"fabric\";\r\n\r\nexport const disabledControl = new Control({\r\n x: 0,\r\n y: -0.5,\r\n offsetY: 0,\r\n cursorStyle: \"pointer\",\r\n actionHandler: () => {\r\n return true;\r\n },\r\n actionName: \"scale\",\r\n render: function (ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number) {\r\n const size = 0;\r\n ctx.save();\r\n ctx.translate(left, top);\r\n ctx.fillStyle = \"#red\";\r\n ctx.fillRect(-size / 2, -size / 2, size, size);\r\n ctx.restore();\r\n },\r\n });\r\n\r\nexport const rotateControl = new Control({\r\n x: 0,\r\n y: -0.5,\r\n offsetY: -25,\r\n cursorStyle: \"crosshair\",\r\n actionHandler: controlsUtils.rotationWithSnapping,\r\n actionName: \"rotate\",\r\n withConnection: true,\r\n });","const imageDimensionsCache = {};\nconst videoMetaCache = {};\nconst audioDurationCache = {};\n\nconst getAudioDuration = (audioSrc) => {\n if (audioDurationCache[audioSrc]) {\n return Promise.resolve(audioDurationCache[audioSrc]);\n }\n return new Promise((resolve, reject) => {\n const audio = document.createElement(\"audio\");\n audio.preload = \"metadata\";\n const isSafeUrl = /^(https?:|blob:|data:audio\\/)/i.test(audioSrc);\n if (!isSafeUrl) {\n throw new Error(\"Unsafe audio source URL\");\n }\n audio.src = audioSrc;\n audio.onloadedmetadata = () => {\n const duration = audio.duration;\n audioDurationCache[audioSrc] = duration;\n resolve(duration);\n };\n audio.onerror = () => {\n reject(new Error(\"Failed to load audio metadata\"));\n };\n });\n};\n\nconst concurrencyLimit = 5;\nlet activeCount = 0;\nconst queue = [];\nfunction runNext() {\n if (queue.length === 0 || activeCount >= concurrencyLimit) return;\n const next = queue.shift();\n if (next) {\n activeCount++;\n next();\n }\n}\nfunction limit(fn) {\n return new Promise((resolve, reject) => {\n const task = () => {\n fn().then(resolve).catch(reject).finally(() => {\n activeCount--;\n runNext();\n });\n };\n if (activeCount < concurrencyLimit) {\n activeCount++;\n task();\n } else {\n queue.push(task);\n }\n });\n}\n\nconst loadImageDimensions = (url) => {\n return new Promise((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"getImageDimensions() is only available in the browser.\"));\n return;\n }\n const img = new Image();\n img.onload = () => {\n resolve({ width: img.naturalWidth, height: img.naturalHeight });\n };\n img.onerror = reject;\n img.src = url;\n });\n};\nconst getImageDimensions = (url) => {\n if (imageDimensionsCache[url]) {\n return Promise.resolve(imageDimensionsCache[url]);\n }\n return limit(() => loadImageDimensions(url)).then((dimensions) => {\n imageDimensionsCache[url] = dimensions;\n return dimensions;\n });\n};\n\nconst getVideoMeta = (videoSrc) => {\n if (videoMetaCache[videoSrc]) {\n return Promise.resolve(videoMetaCache[videoSrc]);\n }\n return new Promise((resolve, reject) => {\n const video = document.createElement(\"video\");\n video.preload = \"metadata\";\n const isSafeUrl = /^(https?:|blob:|data:video\\/)/i.test(videoSrc);\n if (!isSafeUrl) {\n reject(new Error(\"Unsafe video source URL\"));\n return;\n }\n video.src = videoSrc;\n video.onloadedmetadata = () => {\n const meta = {\n width: video.videoWidth,\n height: video.videoHeight,\n duration: video.duration\n };\n videoMetaCache[videoSrc] = meta;\n resolve(meta);\n };\n video.onerror = () => reject(new Error(\"Failed to load video metadata\"));\n });\n};\n\nconst getThumbnail = async (videoUrl, seekTime = 0.1, playbackRate = 1) => {\n return new Promise((resolve, reject) => {\n const video = document.createElement(\"video\");\n video.crossOrigin = \"anonymous\";\n video.muted = true;\n video.playsInline = true;\n video.autoplay = false;\n video.preload = \"auto\";\n video.playbackRate = playbackRate;\n video.style.position = \"absolute\";\n video.style.left = \"-9999px\";\n video.style.top = \"-9999px\";\n video.style.width = \"1px\";\n video.style.height = \"1px\";\n video.style.opacity = \"0\";\n video.style.pointerEvents = \"none\";\n video.style.zIndex = \"-1\";\n let timeoutId;\n const cleanup = () => {\n if (video.parentNode) video.remove();\n if (timeoutId) clearTimeout(timeoutId);\n };\n const handleError = () => {\n cleanup();\n reject(new Error(`Failed to load video: ${video.error?.message || \"Unknown error\"}`));\n };\n const handleSeeked = () => {\n try {\n video.pause();\n const canvas = document.createElement(\"canvas\");\n const width = video.videoWidth || 640;\n const height = video.videoHeight || 360;\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n cleanup();\n reject(new Error(\"Failed to get canvas context\"));\n return;\n }\n ctx.drawImage(video, 0, 0, width, height);\n try {\n const dataUrl = canvas.toDataURL(\"image/jpeg\", 0.8);\n cleanup();\n resolve(dataUrl);\n } catch {\n canvas.toBlob((blob) => {\n if (!blob) {\n cleanup();\n reject(new Error(\"Failed to create Blob\"));\n return;\n }\n const blobUrl = URL.createObjectURL(blob);\n cleanup();\n resolve(blobUrl);\n }, \"image/jpeg\", 0.8);\n }\n } catch (err) {\n cleanup();\n reject(new Error(`Error creating thumbnail: ${err}`));\n }\n };\n video.addEventListener(\"error\", handleError, { once: true });\n video.addEventListener(\"seeked\", handleSeeked, { once: true });\n video.addEventListener(\"loadedmetadata\", () => {\n const playPromise = video.play();\n if (playPromise !== void 0) {\n playPromise.then(() => {\n video.currentTime = seekTime;\n }).catch(() => {\n video.currentTime = seekTime;\n });\n } else {\n video.currentTime = seekTime;\n }\n }, { once: true });\n timeoutId = window.setTimeout(() => {\n cleanup();\n reject(new Error(\"Video loading timed out\"));\n }, 5e3);\n video.src = videoUrl;\n document.body.appendChild(video);\n });\n};\n\nconst getScaledDimensions = (width, height, maxWidth, maxHeight) => {\n if (width <= maxWidth && height <= maxHeight) {\n return {\n width: width % 2 === 0 ? width : width - 1,\n height: height % 2 === 0 ? height : height - 1\n };\n }\n const widthRatio = maxWidth / width;\n const heightRatio = maxHeight / height;\n const scale = Math.min(widthRatio, heightRatio);\n let scaledWidth = Math.round(width * scale);\n let scaledHeight = Math.round(height * scale);\n if (scaledWidth % 2 !== 0) {\n scaledWidth -= 1;\n }\n if (scaledHeight % 2 !== 0) {\n scaledHeight -= 1;\n }\n return {\n width: Math.min(scaledWidth, maxWidth),\n height: Math.min(scaledHeight, maxHeight)\n };\n};\nconst getObjectFitSize = (objectFit, elementSize, containerSize) => {\n const elementAspectRatio = elementSize.width / elementSize.height;\n const containerAspectRatio = containerSize.width / containerSize.height;\n switch (objectFit) {\n case \"contain\":\n if (elementAspectRatio > containerAspectRatio) {\n return {\n width: containerSize.width,\n height: containerSize.width / elementAspectRatio\n };\n } else {\n return {\n width: containerSize.height * elementAspectRatio,\n height: containerSize.height\n };\n }\n case \"cover\":\n if (elementAspectRatio > containerAspectRatio) {\n return {\n width: containerSize.height * elementAspectRatio,\n height: containerSize.height\n };\n } else {\n return {\n width: containerSize.width,\n height: containerSize.width / elementAspectRatio\n };\n }\n case \"fill\":\n return {\n width: containerSize.width,\n height: containerSize.height\n };\n default:\n return {\n width: elementSize.width,\n height: elementSize.height\n };\n }\n};\n\nconst blobUrlToFile = async (blobUrl, fileName) => {\n const response = await fetch(blobUrl);\n const blob = await response.blob();\n return new File([blob], fileName, { type: blob.type });\n};\nconst saveAsFile = (content, type, name) => {\n const blob = typeof content === \"string\" ? new Blob([content], { type }) : content;\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = name;\n a.click();\n URL.revokeObjectURL(url);\n};\nconst downloadFile = async (url, filename) => {\n try {\n const response = await fetch(url);\n const blob = await response.blob();\n const downloadUrl = window.URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = downloadUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n window.URL.revokeObjectURL(downloadUrl);\n } catch (error) {\n console.error(\"Error downloading file:\", error);\n throw error;\n }\n};\n\nconst detectMediaTypeFromUrl = async (url) => {\n try {\n const response = await fetch(url, { method: \"HEAD\" });\n const contentType = response.headers.get(\"Content-Type\");\n if (!contentType) return null;\n if (contentType.startsWith(\"image/\")) return \"image\";\n if (contentType.startsWith(\"video/\")) return \"video\";\n if (contentType.startsWith(\"audio/\")) return \"audio\";\n return null;\n } catch (error) {\n console.error(\"Fetch failed:\", error);\n return null;\n }\n};\n\nexport { blobUrlToFile, detectMediaTypeFromUrl, downloadFile, getAudioDuration, getImageDimensions, getObjectFitSize, getScaledDimensions, getThumbnail, getVideoMeta, limit, saveAsFile };\n//# sourceMappingURL=index.mjs.map\n","import {\r\n Canvas as FabricCanvas,\r\n FabricText,\r\n Group,\r\n FabricImage,\r\n Rect,\r\n Shadow,\r\n} from \"fabric\";\r\nimport { convertToCanvasPosition } from \"../helpers/canvas.util\";\r\nimport {\r\n CanvasElement,\r\n CanvasMetadata,\r\n CaptionProps,\r\n FrameEffect,\r\n} from \"../types\";\r\nimport {\r\n DEFAULT_CAPTION_PROPS,\r\n DEFAULT_TEXT_PROPS,\r\n} from \"../helpers/constants\";\r\nimport { disabledControl, rotateControl } from \"./element-controls\";\r\nimport { getObjectFitSize, getThumbnail } from \"@twick/media-utils\";\r\n\r\n/**\r\n * Add a text element for the canvas.\r\n *\r\n * @param {Object} params - The parameters for creating the text element.\r\n * @param {CanvasElement} params.element - The canvas element configuration.\r\n * @param {number} params.index - The z-index of the element.\r\n * @param {CanvasMetadata} params.canvasMetadata - Metadata about the canvas, including scale and dimensions.\r\n * @returns {FabricText} The configured Fabric.js text object.\r\n */\r\nexport const addTextElement = ({\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.x || 0,\r\n element.props?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n const text = new FabricText(element.props?.text || element.t || \"\", {\r\n left: x,\r\n top: y,\r\n originX: \"center\",\r\n originY: \"center\",\r\n angle: element.props?.rotation || 0,\r\n fontSize: Math.round(\r\n (element.props?.fontSize || DEFAULT_TEXT_PROPS.size) *\r\n canvasMetadata.scaleX\r\n ),\r\n fontFamily: element.props?.fontFamily || DEFAULT_TEXT_PROPS.family,\r\n fontStyle: element.props?.fontStyle || \"normal\",\r\n fontWeight: element.props?.fontWeight || \"normal\",\r\n fill: element.props?.fill || DEFAULT_TEXT_PROPS.fill,\r\n skipWrapping: false,\r\n textAlign: element.props?.textAlign || \"center\",\r\n stroke: element.props?.stroke || DEFAULT_TEXT_PROPS.stroke,\r\n strokeWidth: element.props?.lineWidth || DEFAULT_TEXT_PROPS.lineWidth,\r\n shadow: element.props?.shadowColor\r\n ? new Shadow({\r\n offsetX:\r\n element.props?.shadowOffset?.length &&\r\n element.props?.shadowOffset?.length > 1\r\n ? element.props.shadowOffset[0] / 2\r\n : 1,\r\n offsetY:\r\n element.props?.shadowOffset?.length &&\r\n element.props?.shadowOffset.length > 1\r\n ? element.props.shadowOffset[1] / 2\r\n : 1,\r\n blur: (element.props?.shadowBlur || 2) / 2,\r\n color: element.props?.shadowColor,\r\n })\r\n : undefined,\r\n });\r\n\r\n // Assign metadata and custom controls\r\n text.set(\"id\", element.id);\r\n text.set(\"zIndex\", index);\r\n\r\n // Disable unwanted control points\r\n text.controls.mt = disabledControl;\r\n text.controls.mb = disabledControl;\r\n text.controls.ml = disabledControl;\r\n text.controls.mr = disabledControl;\r\n text.controls.bl = disabledControl;\r\n text.controls.br = disabledControl;\r\n text.controls.tl = disabledControl;\r\n text.controls.tr = disabledControl;\r\n text.controls.mtr = rotateControl;\r\n\r\n canvas.add(text);\r\n return text;\r\n};\r\n\r\nconst setImageProps = ({\r\n img,\r\n element,\r\n index,\r\n canvasMetadata,\r\n}: {\r\n img: FabricImage;\r\n element: CanvasElement;\r\n index: number;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const width =\r\n (element.props?.width || 0) * canvasMetadata.scaleX || canvasMetadata.width;\r\n const height =\r\n (element.props?.height || 0) * canvasMetadata.scaleY ||\r\n canvasMetadata.height;\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.x || 0,\r\n element.props?.y || 0,\r\n canvasMetadata\r\n );\r\n console.log(width, height, x, y);\r\n img.set(\"id\", element.id);\r\n img.set(\"zIndex\", index);\r\n img.set(\"width\", width);\r\n img.set(\"height\", height);\r\n img.set(\"left\", x);\r\n img.set(\"top\", y);\r\n img.set(\"selectable\", true);\r\n img.set(\"hasControls\", true);\r\n img.set(\"touchAction\", \"all\");\r\n};\r\n\r\n/**\r\n * Add a caption element for the canvas based on provided props.\r\n *\r\n * @param {Object} params - Parameters for creating the caption.\r\n * @param {CanvasElement} params.element - The canvas element configuration.\r\n * @param {FabricCanvas} params.canvas - The Fabric.js canvas instance.\r\n * @param {number} params.index - The z-index of the element.\r\n * @param {CaptionProps} params.captionProps - Default and user-defined caption properties.\r\n * @param {CanvasMetadata} params.canvasMetadata - Metadata about the canvas, including scale and dimensions.\r\n * @returns {FabricText} The configured Fabric.js caption object.\r\n */\r\nexport const addCaptionElement = ({\r\n element,\r\n index,\r\n canvas,\r\n captionProps,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n captionProps: CaptionProps;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.pos?.x || captionProps?.pos?.x || 0,\r\n element.props?.pos?.y || captionProps?.pos?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n const caption = new FabricText(element.props?.text || element.t ||\"\", {\r\n left: x,\r\n top: y,\r\n originX: \"center\",\r\n originY: \"center\",\r\n angle: element.props?.rotation || 0,\r\n fontSize: Math.round(\r\n (element.props?.font?.size ||\r\n captionProps.font?.size ||\r\n DEFAULT_CAPTION_PROPS.size) * canvasMetadata.scaleX\r\n ),\r\n fontFamily:\r\n element.props?.font?.family ||\r\n captionProps.font?.family ||\r\n DEFAULT_CAPTION_PROPS.family,\r\n fill:\r\n element.props?.fill ||\r\n captionProps.color?.text ||\r\n DEFAULT_CAPTION_PROPS.fill,\r\n fontWeight: DEFAULT_CAPTION_PROPS.fontWeight,\r\n stroke: element.props?.stroke || DEFAULT_CAPTION_PROPS.stroke,\r\n shadow: new Shadow({\r\n offsetX:\r\n element.props?.shadowOffset?.[0] ||\r\n DEFAULT_CAPTION_PROPS.shadowOffset?.[0],\r\n offsetY:\r\n element.props?.shadowOffset?.[1] ||\r\n DEFAULT_CAPTION_PROPS.shadowOffset?.[1],\r\n blur: element.props?.shadowBlur || DEFAULT_CAPTION_PROPS.shadowBlur,\r\n color: element.props?.shadowColor || DEFAULT_CAPTION_PROPS.shadowColor,\r\n }),\r\n strokeWidth: element.props?.lineWidth || DEFAULT_CAPTION_PROPS.lineWidth,\r\n });\r\n\r\n // Assign metadata and custom controls\r\n caption.set(\"id\", element.id);\r\n caption.set(\"zIndex\", index);\r\n\r\n // Disable unwanted control points\r\n caption.controls.mt = disabledControl;\r\n caption.controls.mb = disabledControl;\r\n caption.controls.ml = disabledControl;\r\n caption.controls.mr = disabledControl;\r\n caption.controls.bl = disabledControl;\r\n caption.controls.br = disabledControl;\r\n caption.controls.tl = disabledControl;\r\n caption.controls.tr = disabledControl;\r\n caption.controls.mtr = disabledControl;\r\n\r\n canvas.add(caption);\r\n return caption;\r\n};\r\n\r\n/* Add a video frame as element into a Fabric.js image object and optionally groups it with a frame.\r\n*\r\n* @param element - The video element containing properties like source and frame information.\r\n* @param index - The z-index for ordering the element on the canvas.\r\n* @param canvas - The Fabric.js canvas instance.\r\n* @param canvasMetadata - Metadata of the canvas, including dimensions and scale factors.\r\n* @param currentFrameEffect - Optional frame effect to apply to the image.\r\n* @param snapTime - The time to snap the video frame with respect to full video duration.\r\n* @returns A Fabric.js image object or a group with an image and frame.\r\n*/\r\nexport const addVideoElement = async ({\r\n element,\r\n index,\r\n canvas,\r\n snapTime,\r\n canvasMetadata,\r\n currentFrameEffect,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n snapTime: number;\r\n canvasMetadata: CanvasMetadata;\r\n currentFrameEffect?: FrameEffect;\r\n}) => {\r\n try {\r\n const thumbnailUrl = await getThumbnail(\r\n element?.props?.src || \"\",\r\n snapTime\r\n );\r\n if (!thumbnailUrl) {\r\n console.error(\"Failed to get thumbnail\");\r\n return;\r\n }\r\n\r\n return addImageElement({\r\n imageUrl: thumbnailUrl,\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect,\r\n });\r\n } catch (error) {\r\n console.error(\"Error loading image:\", error);\r\n }\r\n};\r\n\r\n/**\r\n * Add an image element into a Fabric.js image object and optionally groups it with a frame.\r\n *\r\n * @param element - The image element containing properties like source and frame information.\r\n * @param index - The z-index for ordering the element on the canvas.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata of the canvas, including dimensions and scale factors.\r\n * @param currentFrameEffect - Optional frame effect to apply to the image.\r\n * @param imageUrl - Optional The url of the image to be added to the canvas.\r\n * @returns A Fabric.js image object or a group with an image and frame.\r\n */\r\nexport const addImageElement = async ({\r\n imageUrl,\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect\r\n}: {\r\n imageUrl?: string;\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n currentFrameEffect?: FrameEffect;\r\n}) => {\r\n try {\r\n // Load the image from the provided source URL\r\n const img = await FabricImage.fromURL(imageUrl ||element.props.src || \"\");\r\n img.set({\r\n originX: \"center\",\r\n originY: \"center\",\r\n lockMovementX: false,\r\n lockMovementY: false,\r\n lockUniScaling: true,\r\n hasControls: false,\r\n selectable: false,\r\n });\r\n\r\n // Return the group if a frame is defined, otherwise return the image\r\n if (element.frame) {\r\n return addMediaGroup({\r\n element,\r\n img,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect\r\n });\r\n } else {\r\n setImageProps({ img, element, index, canvasMetadata });\r\n canvas.add(img);\r\n return img;\r\n }\r\n } catch (error) {\r\n console.error(\"Error loading image:\", error);\r\n }\r\n};\r\n\r\n/**\r\n * Add a Fabric.js group combining an image and its associated frame,\r\n * applying styling, positioning, and scaling based on the given properties.\r\n *\r\n * @param element - The image element containing properties like frame, position, and styling.\r\n * @param img - The Fabric.js image object to be included in the group.\r\n * @param index - The z-index for ordering the group on the canvas.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata of the canvas, including dimensions and scale factors.\r\n * @param currentFrameEffect - Optional current frame effect to override default frame properties.\r\n * @returns A Fabric.js group containing the image and frame with configured properties.\r\n */\r\nconst addMediaGroup = ({\r\n element,\r\n img,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n currentFrameEffect,\r\n}: {\r\n element: CanvasElement;\r\n img: FabricImage;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n currentFrameEffect?: FrameEffect;\r\n}) => {\r\n let frameSize;\r\n let angle;\r\n let framePosition;\r\n let frameRadius = 0;\r\n if (currentFrameEffect) {\r\n frameSize = {\r\n width:\r\n (currentFrameEffect.props.frameSize?.[0] || 0) *\r\n canvasMetadata.scaleX || canvasMetadata.width,\r\n height:\r\n (currentFrameEffect.props.frameSize?.[1] || 0) *\r\n canvasMetadata.scaleY || canvasMetadata.height,\r\n };\r\n angle = currentFrameEffect.props.rotation || 0;\r\n framePosition = currentFrameEffect.props.framePosition;\r\n if (currentFrameEffect.props.shape === \"circle\") {\r\n frameRadius = frameSize.width / 2;\r\n } else {\r\n frameRadius = currentFrameEffect?.props?.radius || 0;\r\n }\r\n } else {\r\n frameRadius = element?.frame?.radius || 0;\r\n frameSize = {\r\n width:\r\n (element?.frame?.size?.[0] || 0) * canvasMetadata.scaleX ||\r\n canvasMetadata.width,\r\n height:\r\n (element?.frame?.size?.[1] || 0) * canvasMetadata.scaleY ||\r\n canvasMetadata.height,\r\n };\r\n angle = element?.frame?.rotation || 0;\r\n framePosition = {\r\n x: element?.frame?.x || 0,\r\n y: element?.frame?.y || 0,\r\n };\r\n }\r\n\r\n const newSize = getObjectFitSize(\r\n element.objectFit,\r\n { width: img.width!, height: img.height! },\r\n frameSize\r\n );\r\n\r\n const frameRect = new Rect({\r\n originX: \"center\",\r\n originY: \"center\",\r\n lockMovementX: false,\r\n lockMovementY: false,\r\n lockUniScaling: true,\r\n hasControls: false,\r\n selectable: false,\r\n width: frameSize.width,\r\n height: frameSize.height,\r\n stroke: element?.frame?.stroke || \"#ffffff\",\r\n strokeWidth: element?.frame?.lineWidth || 0,\r\n hasRotatingPoint: true,\r\n rx: frameRadius || 0,\r\n ry: frameRadius || 0,\r\n });\r\n\r\n img.set({\r\n lockUniScaling: true,\r\n originX: \"center\",\r\n originY: \"center\",\r\n scaleX: newSize.width / img.width,\r\n scaleY: newSize.height / img.height,\r\n });\r\n\r\n\r\n const { x, y } = convertToCanvasPosition(\r\n framePosition?.x || 0,\r\n framePosition?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n const groupProps = {\r\n left: x,\r\n top: y,\r\n width: frameSize.width,\r\n height: frameSize.height,\r\n angle: angle,\r\n };\r\n\r\n // Customize the control points for the group\r\n // Change only the top control to a different style, keep others as circles\r\n\r\n const group = new Group([frameRect, img], {\r\n ...groupProps,\r\n originX: \"center\",\r\n originY: \"center\",\r\n angle: groupProps.angle,\r\n selectable: true,\r\n hasControls: true,\r\n hasBorders: true,\r\n clipPath: frameRect,\r\n });\r\n\r\n group.controls.mt = disabledControl;\r\n group.controls.mb = disabledControl;\r\n group.controls.ml = disabledControl;\r\n group.controls.mr = disabledControl;\r\n group.controls.mtr = rotateControl;\r\n\r\n group.set(\"id\", element.id);\r\n group.set(\"zIndex\", index);\r\n canvas.add(group);\r\n return group;\r\n};\r\n\r\n/**\r\n * Add a rectangular Fabric.js element based on the provided canvas element data.\r\n *\r\n * @param element - The canvas element containing properties for the rectangle.\r\n * @param index - The zIndex value used to determine the rendering order.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @returns A Fabric.js Rect object configured with the specified properties.\r\n */\r\nexport const addRectElement = ({\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n // Convert element's position to canvas coordinates\r\n const { x, y } = convertToCanvasPosition(\r\n element.props?.x || 0,\r\n element.props?.y || 0,\r\n canvasMetadata\r\n );\r\n\r\n // Create a new rectangular Fabric.js object\r\n const rect = new Rect({\r\n left: x, // X-coordinate on the canvas\r\n top: y, // Y-coordinate on the canvas\r\n originX: \"center\", // Center the rectangle based on its position\r\n originY: \"center\", // Center the rectangle based on its position\r\n angle: element.props?.rotation || 0, // Rotation angle\r\n rx: (element.props?.radius || 0) * canvasMetadata.scaleX, // Horizontal radius for rounded corners\r\n ry: (element.props?.radius || 0) * canvasMetadata.scaleY, // Vertical radius for rounded corners\r\n stroke: element.props?.stroke || \"#000000\", // Stroke color\r\n strokeWidth: (element.props?.lineWidth || 0) * canvasMetadata.scaleX, // Scaled stroke width\r\n fill: element.props?.fill || \"#000000\", // Fill color\r\n opacity: element.props?.opacity || 1, // Opacity level\r\n width: (element.props?.width || 0) * canvasMetadata.scaleX, // Scaled width\r\n height: (element.props?.height || 0) * canvasMetadata.scaleY, // Scaled height\r\n });\r\n\r\n // Set custom properties for the rectangle\r\n rect.set(\"id\", element.id); // Unique identifier for the rectangle\r\n rect.set(\"zIndex\", index); // zIndex determines rendering order\r\n\r\n // Set custom control for rotation\r\n rect.controls.mtr = rotateControl;\r\n\r\n canvas.add(rect);\r\n return rect;\r\n};\r\n\r\n/**\r\n * Add a background color to the canvas.\r\n *\r\n * @param element - The canvas element containing properties for the background.\r\n * @param index - The zIndex value used to determine the rendering order.\r\n * @param canvas - The Fabric.js canvas instance.\r\n * @param canvasMetadata - Metadata containing canvas scaling and dimensions.\r\n * @returns A Fabric.js Rect object configured with the specified properties.\r\n */\r\nexport const addBackgroundColor = ({\r\n element,\r\n index,\r\n canvas,\r\n canvasMetadata,\r\n}: {\r\n element: CanvasElement;\r\n index: number;\r\n canvas: FabricCanvas;\r\n canvasMetadata: CanvasMetadata;\r\n}) => {\r\n const bgRect = new Rect({\r\n width: canvasMetadata.width,\r\n height: canvasMetadata.height,\r\n left: canvasMetadata.width / 2,\r\n top: canvasMetadata.height / 2,\r\n fill: element.backgoundColor ?? \"#000000\",\r\n originX: \"center\",\r\n originY: \"center\",\r\n hasControls: false,\r\n hasBorders: false,\r\n selectable: false,\r\n });\r\n\r\n bgRect.controls.mt = disabledControl;\r\n bgRect.controls.mb = disabledControl;\r\n bgRect.controls.ml = disabledControl;\r\n bgRect.controls.mr = disabledControl;\r\n bgRect.controls.bl = disabledControl;\r\n bgRect.controls.br = disabledControl;\r\n bgRect.controls.tl = disabledControl;\r\n bgRect.controls.tr = disabledControl;\r\n bgRect.controls.mtr = disabledControl;\r\n bgRect.set(\"zIndex\", index - 0.5);\r\n\r\n canvas.add(bgRect);\r\n return bgRect;\r\n};\r\n","import { useRef, useState } from \"react\";\r\nimport { Canvas as FabricCanvas, FabricObject } from \"fabric\";\r\nimport { Dimensions } from \"@twick/media-utils\";\r\nimport { CanvasMetadata, CanvasProps, CanvasElement } from \"../types\";\r\nimport {\r\n clearCanvas,\r\n convertToVideoPosition,\r\n createCanvas,\r\n getCurrentFrameEffect,\r\n reorderElementsByZIndex,\r\n} from \"../helpers/canvas.util\";\r\nimport { CANVAS_OPERATIONS, ELEMENT_TYPES } from \"../helpers/constants\";\r\nimport {\r\n addImageElement,\r\n addVideoElement,\r\n addRectElement,\r\n addTextElement,\r\n addCaptionElement,\r\n addBackgroundColor,\r\n} from \"../components/elements\";\r\n\r\n/**\r\n * Custom hook to manage a Fabric.js canvas and associated operations.\r\n *\r\n * @param onCanvasReady - Callback executed when the canvas is ready.\r\n * @param onCanvasOperation - Callback executed on canvas operations such as item selection or updates.\r\n * @returns Canvas-related functions and state.\r\n */\r\nexport const useTwickCanvas = ({\r\n onCanvasReady,\r\n onCanvasOperation,\r\n}: {\r\n onCanvasReady?: (canvas: FabricCanvas) => void;\r\n onCanvasOperation?: (operation: string, data: any) => void;\r\n}) => {\r\n const [twickCanvas, setTwickCanvas] = useState<FabricCanvas | null>(null); // Canvas instance\r\n const elementMap = useRef<Record<string, any>>({}); // Maps element IDs to their data\r\n const elementFrameMap = useRef<Record<string, any>>({}); // Maps element IDs to their frame effects\r\n const twickCanvasRef = useRef<FabricCanvas | null>(null);\r\n const videoSizeRef = useRef<Dimensions>({ width: 1, height: 1 }); // Stores the video dimensions\r\n const canvasMetadataRef = useRef<CanvasMetadata>({\r\n width: 0,\r\n height: 0,\r\n aspectRatio: 0,\r\n scaleX: 1,\r\n scaleY: 1,\r\n }); // Metadata for the canvas\r\n\r\n /**\r\n * Updates canvas metadata when the video size changes.\r\n *\r\n * @param videoSize - New video dimensions.\r\n */\r\n const onVideoSizeChange = (videoSize: Dimensions) => {\r\n if (videoSize) {\r\n videoSizeRef.current = videoSize;\r\n canvasMetadataRef.current.scaleX =\r\n canvasMetadataRef.current.width / videoSize.width;\r\n canvasMetadataRef.current.scaleY =\r\n canvasMetadataRef.current.height / videoSize.height;\r\n }\r\n };\r\n\r\n /**\r\n * Initializes the Fabric.js canvas with the provided configuration.\r\n *\r\n * @param props - Canvas configuration properties.\r\n */\r\n const buildCanvas = ({\r\n videoSize,\r\n canvasSize,\r\n canvasRef,\r\n backgroundColor = \"#000000\",\r\n selectionBorderColor = \"#2563eb\",\r\n selectionLineWidth = 2,\r\n uniScaleTransform = true,\r\n enableRetinaScaling = true,\r\n touchZoomThreshold = 10,\r\n }: CanvasProps) => {\r\n if (!canvasRef) return;\r\n\r\n // Dispose of the old canvas if it exists\r\n if (twickCanvasRef.current) {\r\n console.log(\"Destroying twickCanvas\");\r\n twickCanvasRef.current.off(\"mouse:up\", handleMouseUp);\r\n twickCanvasRef.current.dispose();\r\n }\r\n\r\n // Create a new canvas and update metadata\r\n const { canvas, canvasMetadata } = createCanvas({\r\n videoSize,\r\n canvasSize,\r\n canvasRef,\r\n backgroundColor,\r\n selectionBorderColor,\r\n selectionLineWidth,\r\n uniScaleTransform,\r\n enableRetinaScaling,\r\n touchZoomThreshold,\r\n });\r\n canvasMetadataRef.current = canvasMetadata;\r\n videoSizeRef.current = videoSize;\r\n // Attach event listeners\r\n canvas?.on(\"mouse:up\", handleMouseUp);\r\n setTwickCanvas(canvas);\r\n twickCanvasRef.current = canvas;\r\n // Notify when canvas is ready\r\n if (onCanvasReady) {\r\n onCanvasReady(canvas);\r\n }\r\n };\r\n\r\n /**\r\n * Handles mouse up events on the canvas.\r\n *\r\n * @param event - Event object.\r\n */\r\n const handleMouseUp = (event: any) => {\r\n if (event.target) {\r\n const object: FabricObject = event.target;\r\n const elementId = object.get(\"id\");\r\n if (event.transform?.action === \"drag\") {\r\n const original = event.transform.original;\r\n if (object.left === original.left && object.top === original.top) {\r\n onCanvasOperation?.(\r\n CANVAS_OPERATIONS.ITEM_SELECTED,\r\n elementMap.current[elementId]\r\n );\r\n return;\r\n }\r\n }\r\n switch (event.transform?.action) {\r\n case \"drag\":\r\n case \"scale\":\r\n case \"scaleX\":\r\n case \"scaleY\":\r\n case \"rotate\":\r\n const { x, y } = convertToVideoPosition(\r\n object.left,\r\n object.top,\r\n canvasMetadataRef.current,\r\n videoSizeRef.current\r\n );\r\n if (elementMap.current[elementId].type === \"caption\") {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n props: {\r\n ...elementMap.current[elementId].props,\r\n pos: {\r\n x,\r\n y,\r\n },\r\n },\r\n };\r\n onCanvasOperation?.(\r\n CANVAS_OPERATIONS.ITEM_UPDATED,\r\n elementMap.current[elementId]\r\n );\r\n } else {\r\n if (object?.type === \"group\") {\r\n const currentFrameEffect = elementFrameMap.current[elementId];\r\n let updatedFrameSize;\r\n if (currentFrameEffect) {\r\n updatedFrameSize = [\r\n currentFrameEffect.props.frameSize[0] * object.scaleX,\r\n currentFrameEffect.props.frameSize[1] * object.scaleY,\r\n ];\r\n } else {\r\n updatedFrameSize = [\r\n elementMap.current[elementId].frame.size[0] * object.scaleX,\r\n elementMap.current[elementId].frame.size[1] * object.scaleY,\r\n ];\r\n }\r\n\r\n if (currentFrameEffect) {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n frameEffects: (\r\n elementMap.current[elementId].frameEffects || []\r\n ).map((frameEffect: any) =>\r\n frameEffect.id === currentFrameEffect?.id\r\n ? {\r\n ...frameEffect,\r\n props: {\r\n ...frameEffect.props,\r\n framePosition: {\r\n x,\r\n y,\r\n },\r\n frameSize: updatedFrameSize,\r\n },\r\n }\r\n : frameEffect\r\n ),\r\n };\r\n elementFrameMap.current[elementId] = {\r\n ...elementFrameMap.current[elementId],\r\n framePosition: {\r\n x,\r\n y,\r\n },\r\n frameSize: updatedFrameSize,\r\n };\r\n } else {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n frame: {\r\n ...elementMap.current[elementId].frame,\r\n rotation: object.angle,\r\n size: updatedFrameSize,\r\n x,\r\n y,\r\n },\r\n };\r\n }\r\n } else {\r\n if (object?.type === \"text\") {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n props: {\r\n ...elementMap.current[elementId].props,\r\n rotation: object.angle,\r\n x,\r\n y,\r\n },\r\n };\r\n } else {\r\n elementMap.current[elementId] = {\r\n ...elementMap.current[elementId],\r\n props: {\r\n ...elementMap.current[elementId].props,\r\n rotation: object.angle,\r\n width:\r\n elementMap.current[elementId].props.width * object.scaleX,\r\n height:\r\n elementMap.current[elementId].props.height *\r\n object.scaleY,\r\n x,\r\n y,\r\n },\r\n };\r\n }\r\n }\r\n onCanvasOperation?.(\r\n CANVAS_OPERATIONS.ITEM_UPDATED,\r\n elementMap.current[elementId]\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n };\r\n\r\n /**\r\n * Sets elements to the canvas.\r\n *\r\n * @param options - Object containing elements, seek time, and additional options.\r\n */\r\n const setCanvasElements = async ({\r\n elements,\r\n seekTime = 0,\r\n captionProps,\r\n cleanAndAdd = false,\r\n }: {\r\n elements: CanvasElement[];\r\n seekTime?: number;\r\n captionProps?: any;\r\n cleanAndAdd?: boolean;\r\n }) => {\r\n if (!twickCanvas) {\r\n console.warn(\"Canvas not initialized\");\r\n return;\r\n }\r\n\r\n try {\r\n if (cleanAndAdd) {\r\n // Clear canvas before adding new elements\r\n clearCanvas(twickCanvas);\r\n }\r\n\r\n await Promise.all(\r\n elements.map(async (element, index) => {\r\n try {\r\n if (!element) {\r\n console.warn(\"Element not found\");\r\n return;\r\n }\r\n await addElementToCanvas({\r\n element,\r\n index,\r\n reorder: false,\r\n seekTime,\r\n captionProps,\r\n });\r\n } catch (error) {\r\n console.error(`Error adding element ${element.id}:`, error);\r\n }\r\n })\r\n );\r\n reorderElementsByZIndex(twickCanvas);\r\n } catch (error) {\r\n console.error(\"Error in setCanvasElements:\", error);\r\n }\r\n };\r\n\r\n /**\r\n * Add element to the canvas.\r\n *\r\n * @param options - Object containing elements, seek time, and additional options.\r\n */\r\n const addElementToCanvas = async ({\r\n element,\r\n index,\r\n reorder = true,\r\n seekTime,\r\n captionProps,\r\n }: {\r\n element: CanvasElement;\r\n index: number;\r\n reorder: boolean;\r\n seekTime?: number;\r\n captionProps?: any;\r\n }) => {\r\n if (!twickCanvas) {\r\n console.warn(\"Canvas not initialized\");\r\n return;\r\n }\r\n // Add element based on type\r\n switch (element.type) {\r\n case ELEMENT_TYPES.VIDEO:\r\n const currentFrameEffect = getCurrentFrameEffect(element, seekTime || 0);\r\n elementFrameMap.current[element.id] = currentFrameEffect;\r\n const snapTime =\r\n ((seekTime || 0) - (element?.s || 0)) *\r\n (element?.props?.playbackRate || 1) +\r\n (element?.props?.time || 0);\r\n await addVideoElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n currentFrameEffect,\r\n snapTime,\r\n });\r\n if (element.timelineType === \"scene\") {\r\n await addBackgroundColor({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n }\r\n break;\r\n case ELEMENT_TYPES.IMAGE:\r\n await addImageElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n if (element.timelineType === \"scene\") {\r\n await addBackgroundColor({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n }\r\n break;\r\n case ELEMENT_TYPES.RECT:\r\n await addRectElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n break;\r\n case ELEMENT_TYPES.TEXT:\r\n await addTextElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n break;\r\n case ELEMENT_TYPES.CAPTION:\r\n await addCaptionElement({\r\n element,\r\n index,\r\n canvas: twickCanvas,\r\n captionProps,\r\n canvasMetadata: canvasMetadataRef.current,\r\n });\r\n break;\r\n default:\r\n break;\r\n }\r\n elementMap.current[element.id] = element;\r\n if (reorder) {\r\n reorderElementsByZIndex(twickCanvas);\r\n }\r\n };\r\n\r\n return {\r\n twickCanvas,\r\n buildCanvas,\r\n onVideoSizeChange,\r\n addElementToCanvas,\r\n setCanvasElements,\r\n };\r\n};\r\n"],"names":["FabricCanvas"],"mappings":"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"}
package/package.json CHANGED
@@ -1,36 +1,40 @@
1
- {
2
- "name": "@twick/canvas",
3
- "version": "0.0.1",
4
- "main": "./dist/index.js",
5
- "module": "./dist/index.mjs",
6
- "types": "./dist/index.d.ts",
7
- "sideEffects": false,
8
- "license": "Apache-2.0",
9
- "files": [
10
- "dist"
11
- ],
12
- "scripts": {
13
- "build": "vite build",
14
- "dev": "vite build --watch",
15
- "lint": "eslint src/",
16
- "clean": "rimraf .turbo node_modules dist",
17
- "docs": "typedoc --plugin typedoc-plugin-markdown --out docs src/index.ts"
18
- },
19
- "dependencies": {
20
- "@twick/media-utils": "0.0.1",
21
- "fabric": "^6.6.2",
22
- "react": "^18.2.0"
23
- },
24
- "devDependencies": {
25
- "@types/fabric": "^5.3.7",
26
- "@types/node": "^20.11.24",
27
- "@types/react": "^18.2.55",
28
- "@types/react-dom": "^18.2.19",
29
- "typescript": "^5.4.2",
30
- "typedoc": "^0.25.8",
31
- "typedoc-plugin-markdown": "^3.17.1",
32
- "vite": "^5.1.4",
33
- "vite-plugin-dts": "^3.7.3",
34
- "rimraf": "^5.0.5"
35
- }
36
- }
1
+ {
2
+ "name": "@twick/canvas",
3
+ "version": "0.14.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "sideEffects": false,
9
+ "license": "Apache-2.0",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "dependencies": {
17
+ "@twick/media-utils": "0.14.0",
18
+ "fabric": "^6.6.2",
19
+ "react": "^18.2.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/fabric": "^5.3.7",
23
+ "@types/node": "^20.11.24",
24
+ "@types/react": "^18.2.55",
25
+ "@types/react-dom": "^18.2.19",
26
+ "typescript": "^5.4.2",
27
+ "typedoc": "^0.25.8",
28
+ "typedoc-plugin-markdown": "^3.17.1",
29
+ "vite": "^5.1.4",
30
+ "vite-plugin-dts": "^3.7.3",
31
+ "rimraf": "^5.0.5"
32
+ },
33
+ "scripts": {
34
+ "build": "vite build",
35
+ "dev": "vite build --watch",
36
+ "lint": "eslint src/",
37
+ "clean": "rimraf .turbo node_modules dist",
38
+ "docs": "typedoc --plugin typedoc-plugin-markdown --out docs src/index.ts"
39
+ }
40
+ }