web-annotation-renderer 0.1.2 → 0.1.4

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/index14.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const P=require("react/jsx-runtime"),n=require("react"),j=require("./index2.cjs");function m({pdfUrl:l,page:u=1,scale:i=1.5,annotations:A=[],currentTime:o=0,onLoad:f,onError:t,onPageChange:a,className:F,style:R,canvasStyle:p}){const d=n.useRef(null),y=n.useRef(null),r=n.useRef(null),v=n.useRef(Promise.resolve()),c=n.useCallback(e=>{v.current=v.current.then(e).catch(h=>{console.error("AnnotPdf: Queued operation failed:",h)})},[]);n.useEffect(()=>{if(!(!d.current||!y.current)){try{r.current=new j.AnnotationRenderer({canvasElement:d.current,container:y.current})}catch(e){console.error("AnnotPdf: Failed to initialize renderer:",e),t&&t(e)}return()=>{r.current&&(r.current.destroy(),r.current=null)}}},[]),n.useEffect(()=>{if(!r.current||!l)return;let e=!1;return c(async()=>{try{const s=await r.current.loadPDF(l);if(e)return;if(!s.success){console.error("AnnotPdf: Failed to load PDF:",s.error),t&&t(new Error(s.error));return}f&&f({pageCount:s.pageCount})}catch(s){if(e)return;console.error("AnnotPdf: Failed to load PDF:",s),t&&t(s)}}),()=>{e=!0}},[l,f,t,c]),n.useEffect(()=>{!r.current||!u||typeof u!="number"||c(async()=>{try{const e=await r.current.setPage(u);if(!e.success){console.error("AnnotPdf: Failed to set page:",e.error),t&&t(new Error(e.error));return}a&&a(u)}catch(e){console.error("AnnotPdf: Failed to set page:",e),t&&t(e)}})},[u,a,t,c]),n.useEffect(()=>{!r.current||!i||typeof i!="number"||c(async()=>{try{const e=await r.current.setScale(i);e.success||(console.error("AnnotPdf: Failed to set scale:",e.error),t&&t(new Error(e.error)))}catch(e){console.error("AnnotPdf: Failed to set scale:",e),t&&t(e)}})},[i,t,c]),n.useEffect(()=>{if(r.current)try{r.current.setAnnotations(A||[])}catch(e){console.error("AnnotPdf: Failed to set annotations:",e),t&&t(e)}},[A,t]),n.useEffect(()=>{if(!(!r.current||o===void 0||o===null))try{r.current.setTime(o)}catch(e){console.error("AnnotPdf: Failed to set time:",e),t&&t(e)}},[o,t]);const w={position:"relative",display:"inline-block",lineHeight:0,...R},b={position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",overflow:"hidden"},S={display:"block",...p};return P.jsxs("div",{className:F,style:w,children:[P.jsx("canvas",{ref:d,style:S}),P.jsx("div",{ref:y,style:b})]})}exports.default=m;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const d=require("react/jsx-runtime"),n=require("react"),j=require("./index2.cjs");function m({pdfUrl:l,page:c=1,scale:u=1.5,annotations:y=[],currentTime:i=0,onLoad:P,onError:t,onPageChange:A,className:F,style:R,canvasStyle:p}){const f=n.useRef(null),a=n.useRef(null),r=n.useRef(null),h=n.useRef(Promise.resolve()),o=n.useCallback(e=>{h.current=h.current.then(e).catch(v=>{console.error("AnnotPdf: Queued operation failed:",v)})},[]);n.useEffect(()=>{if(!(!f.current||!a.current)){try{r.current=new j.AnnotationRenderer({canvasElement:f.current,container:a.current})}catch(e){console.error("AnnotPdf: Failed to initialize renderer:",e),t&&t(e)}return()=>{r.current&&(r.current.destroy(),r.current=null)}}},[]),n.useEffect(()=>{if(!r.current||!l)return;let e=!1;return o(async()=>{try{const s=await r.current.loadPDF(l);if(e)return;if(!s.success){console.error("AnnotPdf: Failed to load PDF:",s.error),t&&t(new Error(s.error));return}P&&P({pageCount:s.pageCount})}catch(s){if(e)return;console.error("AnnotPdf: Failed to load PDF:",s),t&&t(s)}}),()=>{e=!0}},[l,o]),n.useEffect(()=>{!r.current||!c||typeof c!="number"||o(async()=>{try{const e=await r.current.setPage(c);if(!e.success){console.error("AnnotPdf: Failed to set page:",e.error),t&&t(new Error(e.error));return}A&&A(c)}catch(e){console.error("AnnotPdf: Failed to set page:",e),t&&t(e)}})},[c,o]),n.useEffect(()=>{!r.current||!u||typeof u!="number"||o(async()=>{try{const e=await r.current.setScale(u);e.success||(console.error("AnnotPdf: Failed to set scale:",e.error),t&&t(new Error(e.error)))}catch(e){console.error("AnnotPdf: Failed to set scale:",e),t&&t(e)}})},[u,o]),n.useEffect(()=>{if(r.current)try{r.current.setAnnotations(y||[])}catch(e){console.error("AnnotPdf: Failed to set annotations:",e),t&&t(e)}},[y]),n.useEffect(()=>{if(!(!r.current||i===void 0||i===null))try{r.current.setTime(i)}catch(e){console.error("AnnotPdf: Failed to set time:",e),t&&t(e)}},[i]);const w={position:"relative",display:"inline-block",lineHeight:0,...R},b={position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",overflow:"hidden"},S={display:"block",...p};return d.jsxs("div",{className:F,style:w,children:[d.jsx("canvas",{ref:f,style:S}),d.jsx("div",{ref:a,style:b})]})}exports.default=m;
2
2
  //# sourceMappingURL=index14.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index14.cjs","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, onLoad, onError, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, onPageChange, onError, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, onError, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations, onError]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime, onError]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"8LA4EA,SAASA,EAAS,CAEhB,OAAAC,EAGA,KAAAC,EAAO,EACP,MAAAC,EAAQ,IACR,YAAAC,EAAc,CAAA,EACd,YAAAC,EAAc,EAGd,OAAAC,EACA,QAAAC,EACA,aAAAC,EAGA,UAAAC,EACA,MAAAC,EACA,YAAAC,CACF,EAAG,CAUD,MAAMC,EAAYC,EAAAA,OAAO,IAAI,EAMvBC,EAAoBD,EAAAA,OAAO,IAAI,EAO/BE,EAAYF,EAAAA,OAAO,IAAI,EAQvBG,EAAcH,EAAAA,OAAO,QAAQ,QAAA,CAAS,EAgBtCI,EAAiBC,cAAaC,GAAc,CAChDH,EAAY,QAAUA,EAAY,QAC/B,KAAKG,CAAS,EACd,MAAMC,GAAS,CAEd,QAAQ,MAAM,qCAAsCA,CAAK,CAC3D,CAAC,CACL,EAAG,CAAA,CAAE,EAULC,EAAAA,UAAU,IAAM,CAEd,GAAI,GAACT,EAAU,SAAW,CAACE,EAAkB,SAK7C,IAAI,CACFC,EAAU,QAAU,IAAIO,qBAAmB,CACzC,cAAeV,EAAU,QACzB,UAAWE,EAAkB,OAAA,CAC9B,CACH,OAASM,EAAO,CACd,QAAQ,MAAM,2CAA4CA,CAAK,EAC3Db,GACFA,EAAQa,CAAK,CAEjB,CAGA,MAAO,IAAM,CACPL,EAAU,UACZA,EAAU,QAAQ,QAAA,EAClBA,EAAU,QAAU,KAExB,EACF,EAAG,CAAA,CAAE,EAWLM,EAAAA,UAAU,IAAM,CAEd,GAAI,CAACN,EAAU,SAAW,CAACd,EACzB,OAGF,IAAIsB,EAAY,GAiChB,OAAAN,EA/BgB,SAAY,CAC1B,GAAI,CACF,MAAMO,EAAS,MAAMT,EAAU,QAAQ,QAAQd,CAAM,EAGrD,GAAIsB,EAAW,OAGf,GAAI,CAACC,EAAO,QAAS,CACnB,QAAQ,MAAM,gCAAiCA,EAAO,KAAK,EACvDjB,GACFA,EAAQ,IAAI,MAAMiB,EAAO,KAAK,CAAC,EAEjC,MACF,CAGIlB,GACFA,EAAO,CAAE,UAAWkB,EAAO,SAAA,CAAW,CAE1C,OAASJ,EAAO,CACd,GAAIG,EAAW,OAEf,QAAQ,MAAM,gCAAiCH,CAAK,EAChDb,GACFA,EAAQa,CAAK,CAEjB,CACF,CAGsB,EAGf,IAAM,CACXG,EAAY,EACd,CACF,EAAG,CAACtB,EAAQK,EAAQC,EAASU,CAAc,CAAC,EAU5CI,EAAAA,UAAU,IAAM,CAEV,CAACN,EAAU,SAAW,CAACb,GAAQ,OAAOA,GAAS,UAKnDe,EAAe,SAAY,CACzB,GAAI,CACF,MAAMO,EAAS,MAAMT,EAAU,QAAQ,QAAQb,CAAI,EAGnD,GAAI,CAACsB,EAAO,QAAS,CACnB,QAAQ,MAAM,gCAAiCA,EAAO,KAAK,EACvDjB,GACFA,EAAQ,IAAI,MAAMiB,EAAO,KAAK,CAAC,EAEjC,MACF,CAGIhB,GACFA,EAAaN,CAAI,CAErB,OAASkB,EAAO,CACd,QAAQ,MAAM,gCAAiCA,CAAK,EAChDb,GACFA,EAAQa,CAAK,CAEjB,CACF,CAAC,CACH,EAAG,CAAClB,EAAMM,EAAcD,EAASU,CAAc,CAAC,EAUhDI,EAAAA,UAAU,IAAM,CAEV,CAACN,EAAU,SAAW,CAACZ,GAAS,OAAOA,GAAU,UAKrDc,EAAe,SAAY,CACzB,GAAI,CACF,MAAMO,EAAS,MAAMT,EAAU,QAAQ,SAASZ,CAAK,EAGhDqB,EAAO,UACV,QAAQ,MAAM,iCAAkCA,EAAO,KAAK,EACxDjB,GACFA,EAAQ,IAAI,MAAMiB,EAAO,KAAK,CAAC,EAGrC,OAASJ,EAAO,CACd,QAAQ,MAAM,iCAAkCA,CAAK,EACjDb,GACFA,EAAQa,CAAK,CAEjB,CACF,CAAC,CACH,EAAG,CAACjB,EAAOI,EAASU,CAAc,CAAC,EASnCI,EAAAA,UAAU,IAAM,CAEd,GAAKN,EAAU,QAKf,GAAI,CACFA,EAAU,QAAQ,eAAeX,GAAe,CAAA,CAAE,CACpD,OAASgB,EAAO,CACd,QAAQ,MAAM,uCAAwCA,CAAK,EACvDb,GACFA,EAAQa,CAAK,CAEjB,CACF,EAAG,CAAChB,EAAaG,CAAO,CAAC,EASzBc,EAAAA,UAAU,IAAM,CAEd,GAAI,GAACN,EAAU,SAAWV,IAAgB,QAAaA,IAAgB,MAKvE,GAAI,CACFU,EAAU,QAAQ,QAAQV,CAAW,CACvC,OAASe,EAAO,CACd,QAAQ,MAAM,gCAAiCA,CAAK,EAChDb,GACFA,EAAQa,CAAK,CAEjB,CACF,EAAG,CAACf,EAAaE,CAAO,CAAC,EAUzB,MAAMkB,EAAwB,CAC5B,SAAU,WACV,QAAS,eACT,WAAY,EACZ,GAAGf,CAAA,EAOCgB,EAAoB,CACxB,SAAU,WACV,IAAK,EACL,KAAM,EACN,MAAO,OACP,OAAQ,OACR,cAAe,OACf,SAAU,QAAA,EAONC,EAAqB,CACzB,QAAS,QACT,GAAGhB,CAAA,EAOL,OACEiB,EAAAA,KAAC,MAAA,CAAI,UAAAnB,EAAsB,MAAOgB,EAChC,SAAA,CAAAI,EAAAA,IAAC,SAAA,CAAO,IAAKjB,EAAW,MAAOe,EAAoB,EACnDE,EAAAA,IAAC,MAAA,CAAI,IAAKf,EAAmB,MAAOY,CAAA,CAAmB,CAAA,EACzD,CAEJ"}
1
+ {"version":3,"file":"index14.cjs","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"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"}
package/dist/index14.js CHANGED
@@ -1,34 +1,34 @@
1
1
  import { jsxs as S, jsx as F } from "react/jsx-runtime";
2
- import { useRef as u, useCallback as k, useEffect as i } from "react";
2
+ import { useRef as u, useCallback as k, useEffect as c } from "react";
3
3
  import { AnnotationRenderer as x } from "./index2.js";
4
- function q({
4
+ function Q({
5
5
  // Required props
6
6
  pdfUrl: a,
7
7
  // Optional props with defaults
8
- page: s = 1,
9
- scale: o = 1.5,
10
- annotations: A = [],
8
+ page: i = 1,
9
+ scale: s = 1.5,
10
+ annotations: y = [],
11
11
  currentTime: l = 0,
12
12
  // Callbacks
13
- onLoad: f,
13
+ onLoad: P,
14
14
  onError: t,
15
- onPageChange: d,
15
+ onPageChange: h,
16
16
  // Styling
17
17
  className: v,
18
18
  style: m,
19
19
  canvasStyle: w
20
20
  }) {
21
- const y = u(null), P = u(null), r = u(null), h = u(Promise.resolve()), c = k((e) => {
22
- h.current = h.current.then(e).catch((p) => {
21
+ const f = u(null), d = u(null), r = u(null), A = u(Promise.resolve()), o = k((e) => {
22
+ A.current = A.current.then(e).catch((p) => {
23
23
  console.error("AnnotPdf: Queued operation failed:", p);
24
24
  });
25
25
  }, []);
26
- i(() => {
27
- if (!(!y.current || !P.current)) {
26
+ c(() => {
27
+ if (!(!f.current || !d.current)) {
28
28
  try {
29
29
  r.current = new x({
30
- canvasElement: y.current,
31
- container: P.current
30
+ canvasElement: f.current,
31
+ container: d.current
32
32
  });
33
33
  } catch (e) {
34
34
  console.error("AnnotPdf: Failed to initialize renderer:", e), t && t(e);
@@ -37,11 +37,11 @@ function q({
37
37
  r.current && (r.current.destroy(), r.current = null);
38
38
  };
39
39
  }
40
- }, []), i(() => {
40
+ }, []), c(() => {
41
41
  if (!r.current || !a)
42
42
  return;
43
43
  let e = !1;
44
- return c(async () => {
44
+ return o(async () => {
45
45
  try {
46
46
  const n = await r.current.loadPDF(a);
47
47
  if (e) return;
@@ -49,7 +49,7 @@ function q({
49
49
  console.error("AnnotPdf: Failed to load PDF:", n.error), t && t(new Error(n.error));
50
50
  return;
51
51
  }
52
- f && f({ pageCount: n.pageCount });
52
+ P && P({ pageCount: n.pageCount });
53
53
  } catch (n) {
54
54
  if (e) return;
55
55
  console.error("AnnotPdf: Failed to load PDF:", n), t && t(n);
@@ -57,43 +57,43 @@ function q({
57
57
  }), () => {
58
58
  e = !0;
59
59
  };
60
- }, [a, f, t, c]), i(() => {
61
- !r.current || !s || typeof s != "number" || c(async () => {
60
+ }, [a, o]), c(() => {
61
+ !r.current || !i || typeof i != "number" || o(async () => {
62
62
  try {
63
- const e = await r.current.setPage(s);
63
+ const e = await r.current.setPage(i);
64
64
  if (!e.success) {
65
65
  console.error("AnnotPdf: Failed to set page:", e.error), t && t(new Error(e.error));
66
66
  return;
67
67
  }
68
- d && d(s);
68
+ h && h(i);
69
69
  } catch (e) {
70
70
  console.error("AnnotPdf: Failed to set page:", e), t && t(e);
71
71
  }
72
72
  });
73
- }, [s, d, t, c]), i(() => {
74
- !r.current || !o || typeof o != "number" || c(async () => {
73
+ }, [i, o]), c(() => {
74
+ !r.current || !s || typeof s != "number" || o(async () => {
75
75
  try {
76
- const e = await r.current.setScale(o);
76
+ const e = await r.current.setScale(s);
77
77
  e.success || (console.error("AnnotPdf: Failed to set scale:", e.error), t && t(new Error(e.error)));
78
78
  } catch (e) {
79
79
  console.error("AnnotPdf: Failed to set scale:", e), t && t(e);
80
80
  }
81
81
  });
82
- }, [o, t, c]), i(() => {
82
+ }, [s, o]), c(() => {
83
83
  if (r.current)
84
84
  try {
85
- r.current.setAnnotations(A || []);
85
+ r.current.setAnnotations(y || []);
86
86
  } catch (e) {
87
87
  console.error("AnnotPdf: Failed to set annotations:", e), t && t(e);
88
88
  }
89
- }, [A, t]), i(() => {
89
+ }, [y]), c(() => {
90
90
  if (!(!r.current || l === void 0 || l === null))
91
91
  try {
92
92
  r.current.setTime(l);
93
93
  } catch (e) {
94
94
  console.error("AnnotPdf: Failed to set time:", e), t && t(e);
95
95
  }
96
- }, [l, t]);
96
+ }, [l]);
97
97
  const b = {
98
98
  position: "relative",
99
99
  display: "inline-block",
@@ -101,7 +101,7 @@ function q({
101
101
  // Remove extra space below canvas
102
102
  ...m
103
103
  // User styles override defaults
104
- }, R = {
104
+ }, C = {
105
105
  position: "absolute",
106
106
  top: 0,
107
107
  left: 0,
@@ -110,17 +110,17 @@ function q({
110
110
  pointerEvents: "none",
111
111
  // Allow clicks to pass through to canvas
112
112
  overflow: "hidden"
113
- }, C = {
113
+ }, R = {
114
114
  display: "block",
115
115
  ...w
116
116
  // User styles override defaults
117
117
  };
118
118
  return /* @__PURE__ */ S("div", { className: v, style: b, children: [
119
- /* @__PURE__ */ F("canvas", { ref: y, style: C }),
120
- /* @__PURE__ */ F("div", { ref: P, style: R })
119
+ /* @__PURE__ */ F("canvas", { ref: f, style: R }),
120
+ /* @__PURE__ */ F("div", { ref: d, style: C })
121
121
  ] });
122
122
  }
123
123
  export {
124
- q as default
124
+ Q as default
125
125
  };
126
126
  //# sourceMappingURL=index14.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index14.js","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, onLoad, onError, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, onPageChange, onError, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, onError, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations, onError]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime, onError]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"index14.js","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"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"}
package/dist/index7.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const y=require("./index6.cjs"),u=require("./index10.cjs");class p extends y.default{constructor(e,r){super(e,r),this.layerElement=document.createElement("div"),this.layerElement.style.position="absolute",this.layerElement.style.inset="0",this.layerElement.style.pointerEvents="none",this.layerElement.style.zIndex="25",this.container.appendChild(this.layerElement),this.elements=new Map,this.rafId=null}render(){this.layerElement.innerHTML="",this.elements.clear(),this.annotations.forEach(e=>{if(e.mode!=="quads"||!e.quads?.length)return;const r=e.quads.reduce((a,i)=>a+i.w,0);e.quads.forEach((a,i)=>{const s=u.rectNormToAbs(a,this.viewport),n=e.quads.slice(0,i).reduce((m,c)=>m+c.w,0),h=n/r,d=(n+a.w)/r,t=document.createElement("div");t.style.position="absolute",t.style.left=`${s.left}px`,t.style.top=`${s.top}px`,t.style.width=`${s.width}px`,t.style.height=`${s.height}px`,t.style.overflow="hidden",t.style.borderRadius="2px";const l=document.createElement("div");l.style.width="100%",l.style.height="100%",l.style.background=e?.style?.color??"rgba(255,230,100,0.35)",l.style.outline="1px solid rgba(255,200,0,0.6)",l.style.transformOrigin="left center",l.style.transform="scaleX(0)",l.style.willChange="transform",t.appendChild(l),this.layerElement.appendChild(t);const o=`${e.id}-${i}`;this.elements.set(o,{element:l,wrapper:t,annotation:e,segStart:h,segEnd:d})})})}updateTime(e){super.updateTime(e),this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null);const r=()=>{this.isDestroyed||(this.elements.forEach(({element:a,wrapper:i,annotation:s,segStart:n,segEnd:h})=>{if(e<s.start)i.style.display="none";else{i.style.display="block";const d=Math.max(0,Math.min(1,(e-s.start)/Math.max(1e-6,s.end-s.start))),t=Math.max(0,Math.min(1,(d-n)/Math.max(1e-6,h-n)));a.style.transform=`scaleX(${t})`}}),this.rafId=requestAnimationFrame(r))};r()}update(){}destroy(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.elements.clear(),this.elements=null,this.layerElement&&this.layerElement.parentNode&&this.layerElement.parentNode.removeChild(this.layerElement),this.layerElement=null,super.destroy()}}exports.default=p;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const c=require("./index6.cjs"),u=require("./index10.cjs");class p extends c.default{constructor(e,a){super(e,a),this.layerElement=document.createElement("div"),this.layerElement.style.position="absolute",this.layerElement.style.inset="0",this.layerElement.style.pointerEvents="none",this.layerElement.style.zIndex="25",this.container.appendChild(this.layerElement),this.elements=new Map}render(){this.layerElement.innerHTML="",this.elements.clear(),this.annotations.forEach(e=>{if(e.mode!=="quads"||!e.quads?.length)return;const a=e.quads.reduce((r,s)=>r+s.w,0);e.quads.forEach((r,s)=>{const i=u.rectNormToAbs(r,this.viewport),n=e.quads.slice(0,s).reduce((y,m)=>y+m.w,0),h=n/a,d=(n+r.w)/a,t=document.createElement("div");t.style.position="absolute",t.style.left=`${i.left}px`,t.style.top=`${i.top}px`,t.style.width=`${i.width}px`,t.style.height=`${i.height}px`,t.style.overflow="hidden",t.style.borderRadius="2px";const l=document.createElement("div");l.style.width="100%",l.style.height="100%",l.style.background=e?.style?.color??"rgba(255,230,100,0.35)",l.style.outline="1px solid rgba(255,200,0,0.6)",l.style.transformOrigin="left center",l.style.transform="scaleX(0)",l.style.willChange="transform",t.appendChild(l),this.layerElement.appendChild(t);const o=`${e.id}-${s}`;this.elements.set(o,{element:l,wrapper:t,annotation:e,segStart:h,segEnd:d})})})}updateTime(e){super.updateTime(e),!this.isDestroyed&&this.elements.forEach(({element:a,wrapper:r,annotation:s,segStart:i,segEnd:n})=>{if(e<s.start)r.style.display="none";else{r.style.display="block";const h=Math.max(0,Math.min(1,(e-s.start)/Math.max(1e-6,s.end-s.start))),d=Math.max(0,Math.min(1,(h-i)/Math.max(1e-6,n-i)));a.style.transform=`scaleX(${d})`}})}update(){}destroy(){this.elements.clear(),this.elements=null,this.layerElement&&this.layerElement.parentNode&&this.layerElement.parentNode.removeChild(this.layerElement),this.layerElement=null,super.destroy()}}exports.default=p;
2
2
  //# sourceMappingURL=index7.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index7.cjs","sources":["../src/layers/HighlightLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\nimport { rectNormToAbs } from '../utils/coordinateUtils.js';\n\n/**\n * HighlightLayer - Renders highlight annotations with progressive reveal\n *\n * Extends BaseLayer to render rectangular highlight regions (quads) with\n * progressive left-to-right scaleX animation based on timeline position.\n * Supports multi-line highlights with per-quad timing segments.\n *\n * @extends BaseLayer\n */\nclass HighlightLayer extends BaseLayer {\n /**\n * Creates a new HighlightLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement('div');\n this.layerElement.style.position = 'absolute';\n this.layerElement.style.inset = '0';\n this.layerElement.style.pointerEvents = 'none';\n this.layerElement.style.zIndex = '25';\n\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage\n this.elements = new Map();\n\n // Initialize RAF ID\n this.rafId = null;\n }\n\n /**\n * Renders highlight elements for all annotations\n *\n * Creates DOM structure for each quad in each annotation. Calculates\n * timing segments for progressive animation. Clears and recreates all\n * elements when called.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = '';\n this.elements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Skip if not quad mode or no quads\n if (annotation.mode !== 'quads' || !annotation.quads?.length) {\n return;\n }\n\n // Calculate total width across all quads\n const totalW = annotation.quads.reduce((sum, quad) => sum + quad.w, 0);\n\n // Process each quad\n annotation.quads.forEach((quad, idx) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(quad, this.viewport);\n\n // Calculate timing segment for this quad\n const prevW = annotation.quads.slice(0, idx).reduce((sum, q) => sum + q.w, 0);\n const segStart = prevW / totalW;\n const segEnd = (prevW + quad.w) / totalW;\n\n // Create wrapper div\n const wrapper = document.createElement('div');\n wrapper.style.position = 'absolute';\n wrapper.style.left = `${abs.left}px`;\n wrapper.style.top = `${abs.top}px`;\n wrapper.style.width = `${abs.width}px`;\n wrapper.style.height = `${abs.height}px`;\n wrapper.style.overflow = 'hidden';\n wrapper.style.borderRadius = '2px';\n\n // Create highlight div\n const highlight = document.createElement('div');\n highlight.style.width = '100%';\n highlight.style.height = '100%';\n highlight.style.background = annotation?.style?.color ?? 'rgba(255,230,100,0.35)';\n highlight.style.outline = '1px solid rgba(255,200,0,0.6)';\n highlight.style.transformOrigin = 'left center';\n highlight.style.transform = 'scaleX(0)';\n highlight.style.willChange = 'transform';\n\n // Assemble DOM structure\n wrapper.appendChild(highlight);\n this.layerElement.appendChild(wrapper);\n\n // Store reference for animation\n const key = `${annotation.id}-${idx}`;\n this.elements.set(key, {\n element: highlight,\n wrapper: wrapper,\n annotation: annotation,\n segStart: segStart,\n segEnd: segEnd\n });\n });\n });\n }\n\n /**\n * Updates highlight animations based on current timeline position\n *\n * Starts requestAnimationFrame loop to animate scaleX transform for\n * each highlight element. Calculates progress for each quad segment\n * and updates visibility.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Cancel existing RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Start animation loop\n const animate = () => {\n if (this.isDestroyed) {\n return;\n }\n\n // Update each highlight element\n this.elements.forEach(({ element, wrapper, annotation, segStart, segEnd }) => {\n // Hide wrapper if time hasn't reached annotation start\n if (nowSec < annotation.start) {\n wrapper.style.display = 'none';\n } else {\n // Show wrapper\n wrapper.style.display = 'block';\n\n // Calculate global progress (0 to 1)\n const globalProgress = Math.max(\n 0,\n Math.min(\n 1,\n (nowSec - annotation.start) / Math.max(1e-6, annotation.end - annotation.start)\n )\n );\n\n // Calculate local progress for this quad segment (0 to 1)\n const localProgress = Math.max(\n 0,\n Math.min(\n 1,\n (globalProgress - segStart) / Math.max(1e-6, segEnd - segStart)\n )\n );\n\n // Apply scaleX transform\n element.style.transform = `scaleX(${localProgress})`;\n }\n });\n\n // Schedule next frame\n this.rafId = requestAnimationFrame(animate);\n };\n\n animate();\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by HighlightLayer - animation handled in updateTime()\n */\n update() {\n // Not used - updateTime handles animation directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Cancels animation loop, clears element storage, removes DOM elements,\n * and calls parent cleanup.\n */\n destroy() {\n // Cancel RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Clear element storage\n this.elements.clear();\n this.elements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default HighlightLayer;\n"],"names":["HighlightLayer","BaseLayer","container","viewport","annotation","totalW","sum","quad","idx","abs","rectNormToAbs","prevW","q","segStart","segEnd","wrapper","highlight","key","nowSec","animate","element","globalProgress","localProgress"],"mappings":"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"}
1
+ {"version":3,"file":"index7.cjs","sources":["../src/layers/HighlightLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\nimport { rectNormToAbs } from '../utils/coordinateUtils.js';\n\n/**\n * HighlightLayer - Renders highlight annotations with progressive reveal\n *\n * Extends BaseLayer to render rectangular highlight regions (quads) with\n * progressive left-to-right scaleX animation based on timeline position.\n * Supports multi-line highlights with per-quad timing segments.\n *\n * @extends BaseLayer\n */\nclass HighlightLayer extends BaseLayer {\n /**\n * Creates a new HighlightLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement('div');\n this.layerElement.style.position = 'absolute';\n this.layerElement.style.inset = '0';\n this.layerElement.style.pointerEvents = 'none';\n this.layerElement.style.zIndex = '25';\n\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage\n this.elements = new Map();\n }\n\n /**\n * Renders highlight elements for all annotations\n *\n * Creates DOM structure for each quad in each annotation. Calculates\n * timing segments for progressive animation. Clears and recreates all\n * elements when called.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = '';\n this.elements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Skip if not quad mode or no quads\n if (annotation.mode !== 'quads' || !annotation.quads?.length) {\n return;\n }\n\n // Calculate total width across all quads\n const totalW = annotation.quads.reduce((sum, quad) => sum + quad.w, 0);\n\n // Process each quad\n annotation.quads.forEach((quad, idx) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(quad, this.viewport);\n\n // Calculate timing segment for this quad\n const prevW = annotation.quads.slice(0, idx).reduce((sum, q) => sum + q.w, 0);\n const segStart = prevW / totalW;\n const segEnd = (prevW + quad.w) / totalW;\n\n // Create wrapper div\n const wrapper = document.createElement('div');\n wrapper.style.position = 'absolute';\n wrapper.style.left = `${abs.left}px`;\n wrapper.style.top = `${abs.top}px`;\n wrapper.style.width = `${abs.width}px`;\n wrapper.style.height = `${abs.height}px`;\n wrapper.style.overflow = 'hidden';\n wrapper.style.borderRadius = '2px';\n\n // Create highlight div\n const highlight = document.createElement('div');\n highlight.style.width = '100%';\n highlight.style.height = '100%';\n highlight.style.background = annotation?.style?.color ?? 'rgba(255,230,100,0.35)';\n highlight.style.outline = '1px solid rgba(255,200,0,0.6)';\n highlight.style.transformOrigin = 'left center';\n highlight.style.transform = 'scaleX(0)';\n highlight.style.willChange = 'transform';\n\n // Assemble DOM structure\n wrapper.appendChild(highlight);\n this.layerElement.appendChild(wrapper);\n\n // Store reference for animation\n const key = `${annotation.id}-${idx}`;\n this.elements.set(key, {\n element: highlight,\n wrapper: wrapper,\n annotation: annotation,\n segStart: segStart,\n segEnd: segEnd\n });\n });\n });\n }\n\n /**\n * Updates highlight animations based on current timeline position\n *\n * Updates scaleX transform for each highlight element based on timeline.\n * Calculates progress for each quad segment and updates visibility.\n * Renders once per call - no continuous loop.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n if (this.isDestroyed) {\n return;\n }\n\n // Update each highlight element\n this.elements.forEach(({ element, wrapper, annotation, segStart, segEnd }) => {\n // Hide wrapper if time hasn't reached annotation start\n if (nowSec < annotation.start) {\n wrapper.style.display = 'none';\n } else {\n // Show wrapper\n wrapper.style.display = 'block';\n\n // Calculate global progress (0 to 1)\n const globalProgress = Math.max(\n 0,\n Math.min(\n 1,\n (nowSec - annotation.start) / Math.max(1e-6, annotation.end - annotation.start)\n )\n );\n\n // Calculate local progress for this quad segment (0 to 1)\n const localProgress = Math.max(\n 0,\n Math.min(\n 1,\n (globalProgress - segStart) / Math.max(1e-6, segEnd - segStart)\n )\n );\n\n // Apply scaleX transform\n element.style.transform = `scaleX(${localProgress})`;\n }\n });\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by HighlightLayer - animation handled in updateTime()\n */\n update() {\n // Not used - updateTime handles animation directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Clears element storage, removes DOM elements, and calls parent cleanup.\n */\n destroy() {\n // Clear element storage\n this.elements.clear();\n this.elements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default HighlightLayer;\n"],"names":["HighlightLayer","BaseLayer","container","viewport","annotation","totalW","sum","quad","idx","abs","rectNormToAbs","prevW","q","segStart","segEnd","wrapper","highlight","key","nowSec","element","globalProgress","localProgress"],"mappings":"uKAYA,MAAMA,UAAuBC,EAAAA,OAAU,CAUrC,YAAYC,EAAWC,EAAU,CAC/B,MAAMD,EAAWC,CAAQ,EAGzB,KAAK,aAAe,SAAS,cAAc,KAAK,EAChD,KAAK,aAAa,MAAM,SAAW,WACnC,KAAK,aAAa,MAAM,MAAQ,IAChC,KAAK,aAAa,MAAM,cAAgB,OACxC,KAAK,aAAa,MAAM,OAAS,KAEjC,KAAK,UAAU,YAAY,KAAK,YAAY,EAG5C,KAAK,SAAW,IAAI,GACtB,CASA,QAAS,CAEP,KAAK,aAAa,UAAY,GAC9B,KAAK,SAAS,MAAK,EAGnB,KAAK,YAAY,QAASC,GAAe,CAEvC,GAAIA,EAAW,OAAS,SAAW,CAACA,EAAW,OAAO,OACpD,OAIF,MAAMC,EAASD,EAAW,MAAM,OAAO,CAACE,EAAKC,IAASD,EAAMC,EAAK,EAAG,CAAC,EAGrEH,EAAW,MAAM,QAAQ,CAACG,EAAMC,IAAQ,CAEtC,MAAMC,EAAMC,EAAAA,cAAcH,EAAM,KAAK,QAAQ,EAGvCI,EAAQP,EAAW,MAAM,MAAM,EAAGI,CAAG,EAAE,OAAO,CAACF,EAAKM,IAAMN,EAAMM,EAAE,EAAG,CAAC,EACtEC,EAAWF,EAAQN,EACnBS,GAAUH,EAAQJ,EAAK,GAAKF,EAG5BU,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,MAAM,SAAW,WACzBA,EAAQ,MAAM,KAAO,GAAGN,EAAI,IAAI,KAChCM,EAAQ,MAAM,IAAM,GAAGN,EAAI,GAAG,KAC9BM,EAAQ,MAAM,MAAQ,GAAGN,EAAI,KAAK,KAClCM,EAAQ,MAAM,OAAS,GAAGN,EAAI,MAAM,KACpCM,EAAQ,MAAM,SAAW,SACzBA,EAAQ,MAAM,aAAe,MAG7B,MAAMC,EAAY,SAAS,cAAc,KAAK,EAC9CA,EAAU,MAAM,MAAQ,OACxBA,EAAU,MAAM,OAAS,OACzBA,EAAU,MAAM,WAAaZ,GAAY,OAAO,OAAS,yBACzDY,EAAU,MAAM,QAAU,gCAC1BA,EAAU,MAAM,gBAAkB,cAClCA,EAAU,MAAM,UAAY,YAC5BA,EAAU,MAAM,WAAa,YAG7BD,EAAQ,YAAYC,CAAS,EAC7B,KAAK,aAAa,YAAYD,CAAO,EAGrC,MAAME,EAAM,GAAGb,EAAW,EAAE,IAAII,CAAG,GACnC,KAAK,SAAS,IAAIS,EAAK,CACrB,QAASD,EACT,QAASD,EACT,WAAYX,EACZ,SAAUS,EACV,OAAQC,CAClB,CAAS,CACH,CAAC,CACH,CAAC,CACH,CAWA,WAAWI,EAAQ,CACjB,MAAM,WAAWA,CAAM,EAEnB,MAAK,aAKT,KAAK,SAAS,QAAQ,CAAC,CAAE,QAAAC,EAAS,QAAAJ,EAAS,WAAAX,EAAY,SAAAS,EAAU,OAAAC,KAAa,CAE5E,GAAII,EAASd,EAAW,MACtBW,EAAQ,MAAM,QAAU,WACnB,CAELA,EAAQ,MAAM,QAAU,QAGxB,MAAMK,EAAiB,KAAK,IAC1B,EACA,KAAK,IACH,GACCF,EAASd,EAAW,OAAS,KAAK,IAAI,KAAMA,EAAW,IAAMA,EAAW,KAAK,CAC1F,CACA,EAGciB,EAAgB,KAAK,IACzB,EACA,KAAK,IACH,GACCD,EAAiBP,GAAY,KAAK,IAAI,KAAMC,EAASD,CAAQ,CAC1E,CACA,EAGQM,EAAQ,MAAM,UAAY,UAAUE,CAAa,GACnD,CACF,CAAC,CACH,CAOA,QAAS,CAET,CAOA,SAAU,CAER,KAAK,SAAS,MAAK,EACnB,KAAK,SAAW,KAGZ,KAAK,cAAgB,KAAK,aAAa,YACzC,KAAK,aAAa,WAAW,YAAY,KAAK,YAAY,EAE5D,KAAK,aAAe,KAGpB,MAAM,QAAO,CACf,CACF"}
package/dist/index7.js CHANGED
@@ -1,6 +1,6 @@
1
- import c from "./index6.js";
2
- import { rectNormToAbs as p } from "./index10.js";
3
- class g extends c {
1
+ import p from "./index6.js";
2
+ import { rectNormToAbs as c } from "./index10.js";
3
+ class f extends p {
4
4
  /**
5
5
  * Creates a new HighlightLayer instance
6
6
  *
@@ -10,8 +10,8 @@ class g extends c {
10
10
  * @param {number} viewport.height - Viewport height in pixels
11
11
  * @param {number} viewport.scale - PDF scale/zoom level
12
12
  */
13
- constructor(e, r) {
14
- super(e, r), this.layerElement = document.createElement("div"), this.layerElement.style.position = "absolute", this.layerElement.style.inset = "0", this.layerElement.style.pointerEvents = "none", this.layerElement.style.zIndex = "25", this.container.appendChild(this.layerElement), this.elements = /* @__PURE__ */ new Map(), this.rafId = null;
13
+ constructor(e, a) {
14
+ super(e, a), this.layerElement = document.createElement("div"), this.layerElement.style.position = "absolute", this.layerElement.style.inset = "0", this.layerElement.style.pointerEvents = "none", this.layerElement.style.zIndex = "25", this.container.appendChild(this.layerElement), this.elements = /* @__PURE__ */ new Map();
15
15
  }
16
16
  /**
17
17
  * Renders highlight elements for all annotations
@@ -24,18 +24,18 @@ class g extends c {
24
24
  this.layerElement.innerHTML = "", this.elements.clear(), this.annotations.forEach((e) => {
25
25
  if (e.mode !== "quads" || !e.quads?.length)
26
26
  return;
27
- const r = e.quads.reduce((a, i) => a + i.w, 0);
28
- e.quads.forEach((a, i) => {
29
- const s = p(a, this.viewport), n = e.quads.slice(0, i).reduce((o, y) => o + y.w, 0), h = n / r, d = (n + a.w) / r, t = document.createElement("div");
30
- t.style.position = "absolute", t.style.left = `${s.left}px`, t.style.top = `${s.top}px`, t.style.width = `${s.width}px`, t.style.height = `${s.height}px`, t.style.overflow = "hidden", t.style.borderRadius = "2px";
27
+ const a = e.quads.reduce((r, s) => r + s.w, 0);
28
+ e.quads.forEach((r, s) => {
29
+ const i = c(r, this.viewport), h = e.quads.slice(0, s).reduce((o, y) => o + y.w, 0), n = h / a, d = (h + r.w) / a, t = document.createElement("div");
30
+ t.style.position = "absolute", t.style.left = `${i.left}px`, t.style.top = `${i.top}px`, t.style.width = `${i.width}px`, t.style.height = `${i.height}px`, t.style.overflow = "hidden", t.style.borderRadius = "2px";
31
31
  const l = document.createElement("div");
32
32
  l.style.width = "100%", l.style.height = "100%", l.style.background = e?.style?.color ?? "rgba(255,230,100,0.35)", l.style.outline = "1px solid rgba(255,200,0,0.6)", l.style.transformOrigin = "left center", l.style.transform = "scaleX(0)", l.style.willChange = "transform", t.appendChild(l), this.layerElement.appendChild(t);
33
- const m = `${e.id}-${i}`;
33
+ const m = `${e.id}-${s}`;
34
34
  this.elements.set(m, {
35
35
  element: l,
36
36
  wrapper: t,
37
37
  annotation: e,
38
- segStart: h,
38
+ segStart: n,
39
39
  segEnd: d
40
40
  });
41
41
  });
@@ -44,38 +44,34 @@ class g extends c {
44
44
  /**
45
45
  * Updates highlight animations based on current timeline position
46
46
  *
47
- * Starts requestAnimationFrame loop to animate scaleX transform for
48
- * each highlight element. Calculates progress for each quad segment
49
- * and updates visibility.
47
+ * Updates scaleX transform for each highlight element based on timeline.
48
+ * Calculates progress for each quad segment and updates visibility.
49
+ * Renders once per call - no continuous loop.
50
50
  *
51
51
  * @param {number} nowSec - Current timeline position in seconds
52
52
  */
53
53
  updateTime(e) {
54
- super.updateTime(e), this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null);
55
- const r = () => {
56
- this.isDestroyed || (this.elements.forEach(({ element: a, wrapper: i, annotation: s, segStart: n, segEnd: h }) => {
57
- if (e < s.start)
58
- i.style.display = "none";
59
- else {
60
- i.style.display = "block";
61
- const d = Math.max(
62
- 0,
63
- Math.min(
64
- 1,
65
- (e - s.start) / Math.max(1e-6, s.end - s.start)
66
- )
67
- ), t = Math.max(
68
- 0,
69
- Math.min(
70
- 1,
71
- (d - n) / Math.max(1e-6, h - n)
72
- )
73
- );
74
- a.style.transform = `scaleX(${t})`;
75
- }
76
- }), this.rafId = requestAnimationFrame(r));
77
- };
78
- r();
54
+ super.updateTime(e), !this.isDestroyed && this.elements.forEach(({ element: a, wrapper: r, annotation: s, segStart: i, segEnd: h }) => {
55
+ if (e < s.start)
56
+ r.style.display = "none";
57
+ else {
58
+ r.style.display = "block";
59
+ const n = Math.max(
60
+ 0,
61
+ Math.min(
62
+ 1,
63
+ (e - s.start) / Math.max(1e-6, s.end - s.start)
64
+ )
65
+ ), d = Math.max(
66
+ 0,
67
+ Math.min(
68
+ 1,
69
+ (n - i) / Math.max(1e-6, h - i)
70
+ )
71
+ );
72
+ a.style.transform = `scaleX(${d})`;
73
+ }
74
+ });
79
75
  }
80
76
  /**
81
77
  * Updates the visual state of the layer
@@ -87,14 +83,13 @@ class g extends c {
87
83
  /**
88
84
  * Destroys the layer and releases all resources
89
85
  *
90
- * Cancels animation loop, clears element storage, removes DOM elements,
91
- * and calls parent cleanup.
86
+ * Clears element storage, removes DOM elements, and calls parent cleanup.
92
87
  */
93
88
  destroy() {
94
- this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null), this.elements.clear(), this.elements = null, this.layerElement && this.layerElement.parentNode && this.layerElement.parentNode.removeChild(this.layerElement), this.layerElement = null, super.destroy();
89
+ this.elements.clear(), this.elements = null, this.layerElement && this.layerElement.parentNode && this.layerElement.parentNode.removeChild(this.layerElement), this.layerElement = null, super.destroy();
95
90
  }
96
91
  }
97
92
  export {
98
- g as default
93
+ f as default
99
94
  };
100
95
  //# sourceMappingURL=index7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index7.js","sources":["../src/layers/HighlightLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\nimport { rectNormToAbs } from '../utils/coordinateUtils.js';\n\n/**\n * HighlightLayer - Renders highlight annotations with progressive reveal\n *\n * Extends BaseLayer to render rectangular highlight regions (quads) with\n * progressive left-to-right scaleX animation based on timeline position.\n * Supports multi-line highlights with per-quad timing segments.\n *\n * @extends BaseLayer\n */\nclass HighlightLayer extends BaseLayer {\n /**\n * Creates a new HighlightLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement('div');\n this.layerElement.style.position = 'absolute';\n this.layerElement.style.inset = '0';\n this.layerElement.style.pointerEvents = 'none';\n this.layerElement.style.zIndex = '25';\n\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage\n this.elements = new Map();\n\n // Initialize RAF ID\n this.rafId = null;\n }\n\n /**\n * Renders highlight elements for all annotations\n *\n * Creates DOM structure for each quad in each annotation. Calculates\n * timing segments for progressive animation. Clears and recreates all\n * elements when called.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = '';\n this.elements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Skip if not quad mode or no quads\n if (annotation.mode !== 'quads' || !annotation.quads?.length) {\n return;\n }\n\n // Calculate total width across all quads\n const totalW = annotation.quads.reduce((sum, quad) => sum + quad.w, 0);\n\n // Process each quad\n annotation.quads.forEach((quad, idx) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(quad, this.viewport);\n\n // Calculate timing segment for this quad\n const prevW = annotation.quads.slice(0, idx).reduce((sum, q) => sum + q.w, 0);\n const segStart = prevW / totalW;\n const segEnd = (prevW + quad.w) / totalW;\n\n // Create wrapper div\n const wrapper = document.createElement('div');\n wrapper.style.position = 'absolute';\n wrapper.style.left = `${abs.left}px`;\n wrapper.style.top = `${abs.top}px`;\n wrapper.style.width = `${abs.width}px`;\n wrapper.style.height = `${abs.height}px`;\n wrapper.style.overflow = 'hidden';\n wrapper.style.borderRadius = '2px';\n\n // Create highlight div\n const highlight = document.createElement('div');\n highlight.style.width = '100%';\n highlight.style.height = '100%';\n highlight.style.background = annotation?.style?.color ?? 'rgba(255,230,100,0.35)';\n highlight.style.outline = '1px solid rgba(255,200,0,0.6)';\n highlight.style.transformOrigin = 'left center';\n highlight.style.transform = 'scaleX(0)';\n highlight.style.willChange = 'transform';\n\n // Assemble DOM structure\n wrapper.appendChild(highlight);\n this.layerElement.appendChild(wrapper);\n\n // Store reference for animation\n const key = `${annotation.id}-${idx}`;\n this.elements.set(key, {\n element: highlight,\n wrapper: wrapper,\n annotation: annotation,\n segStart: segStart,\n segEnd: segEnd\n });\n });\n });\n }\n\n /**\n * Updates highlight animations based on current timeline position\n *\n * Starts requestAnimationFrame loop to animate scaleX transform for\n * each highlight element. Calculates progress for each quad segment\n * and updates visibility.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Cancel existing RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Start animation loop\n const animate = () => {\n if (this.isDestroyed) {\n return;\n }\n\n // Update each highlight element\n this.elements.forEach(({ element, wrapper, annotation, segStart, segEnd }) => {\n // Hide wrapper if time hasn't reached annotation start\n if (nowSec < annotation.start) {\n wrapper.style.display = 'none';\n } else {\n // Show wrapper\n wrapper.style.display = 'block';\n\n // Calculate global progress (0 to 1)\n const globalProgress = Math.max(\n 0,\n Math.min(\n 1,\n (nowSec - annotation.start) / Math.max(1e-6, annotation.end - annotation.start)\n )\n );\n\n // Calculate local progress for this quad segment (0 to 1)\n const localProgress = Math.max(\n 0,\n Math.min(\n 1,\n (globalProgress - segStart) / Math.max(1e-6, segEnd - segStart)\n )\n );\n\n // Apply scaleX transform\n element.style.transform = `scaleX(${localProgress})`;\n }\n });\n\n // Schedule next frame\n this.rafId = requestAnimationFrame(animate);\n };\n\n animate();\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by HighlightLayer - animation handled in updateTime()\n */\n update() {\n // Not used - updateTime handles animation directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Cancels animation loop, clears element storage, removes DOM elements,\n * and calls parent cleanup.\n */\n destroy() {\n // Cancel RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Clear element storage\n this.elements.clear();\n this.elements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default HighlightLayer;\n"],"names":["HighlightLayer","BaseLayer","container","viewport","annotation","totalW","sum","quad","idx","abs","rectNormToAbs","prevW","q","segStart","segEnd","wrapper","highlight","key","nowSec","animate","element","globalProgress","localProgress"],"mappings":"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"}
1
+ {"version":3,"file":"index7.js","sources":["../src/layers/HighlightLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\nimport { rectNormToAbs } from '../utils/coordinateUtils.js';\n\n/**\n * HighlightLayer - Renders highlight annotations with progressive reveal\n *\n * Extends BaseLayer to render rectangular highlight regions (quads) with\n * progressive left-to-right scaleX animation based on timeline position.\n * Supports multi-line highlights with per-quad timing segments.\n *\n * @extends BaseLayer\n */\nclass HighlightLayer extends BaseLayer {\n /**\n * Creates a new HighlightLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement('div');\n this.layerElement.style.position = 'absolute';\n this.layerElement.style.inset = '0';\n this.layerElement.style.pointerEvents = 'none';\n this.layerElement.style.zIndex = '25';\n\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage\n this.elements = new Map();\n }\n\n /**\n * Renders highlight elements for all annotations\n *\n * Creates DOM structure for each quad in each annotation. Calculates\n * timing segments for progressive animation. Clears and recreates all\n * elements when called.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = '';\n this.elements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Skip if not quad mode or no quads\n if (annotation.mode !== 'quads' || !annotation.quads?.length) {\n return;\n }\n\n // Calculate total width across all quads\n const totalW = annotation.quads.reduce((sum, quad) => sum + quad.w, 0);\n\n // Process each quad\n annotation.quads.forEach((quad, idx) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(quad, this.viewport);\n\n // Calculate timing segment for this quad\n const prevW = annotation.quads.slice(0, idx).reduce((sum, q) => sum + q.w, 0);\n const segStart = prevW / totalW;\n const segEnd = (prevW + quad.w) / totalW;\n\n // Create wrapper div\n const wrapper = document.createElement('div');\n wrapper.style.position = 'absolute';\n wrapper.style.left = `${abs.left}px`;\n wrapper.style.top = `${abs.top}px`;\n wrapper.style.width = `${abs.width}px`;\n wrapper.style.height = `${abs.height}px`;\n wrapper.style.overflow = 'hidden';\n wrapper.style.borderRadius = '2px';\n\n // Create highlight div\n const highlight = document.createElement('div');\n highlight.style.width = '100%';\n highlight.style.height = '100%';\n highlight.style.background = annotation?.style?.color ?? 'rgba(255,230,100,0.35)';\n highlight.style.outline = '1px solid rgba(255,200,0,0.6)';\n highlight.style.transformOrigin = 'left center';\n highlight.style.transform = 'scaleX(0)';\n highlight.style.willChange = 'transform';\n\n // Assemble DOM structure\n wrapper.appendChild(highlight);\n this.layerElement.appendChild(wrapper);\n\n // Store reference for animation\n const key = `${annotation.id}-${idx}`;\n this.elements.set(key, {\n element: highlight,\n wrapper: wrapper,\n annotation: annotation,\n segStart: segStart,\n segEnd: segEnd\n });\n });\n });\n }\n\n /**\n * Updates highlight animations based on current timeline position\n *\n * Updates scaleX transform for each highlight element based on timeline.\n * Calculates progress for each quad segment and updates visibility.\n * Renders once per call - no continuous loop.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n if (this.isDestroyed) {\n return;\n }\n\n // Update each highlight element\n this.elements.forEach(({ element, wrapper, annotation, segStart, segEnd }) => {\n // Hide wrapper if time hasn't reached annotation start\n if (nowSec < annotation.start) {\n wrapper.style.display = 'none';\n } else {\n // Show wrapper\n wrapper.style.display = 'block';\n\n // Calculate global progress (0 to 1)\n const globalProgress = Math.max(\n 0,\n Math.min(\n 1,\n (nowSec - annotation.start) / Math.max(1e-6, annotation.end - annotation.start)\n )\n );\n\n // Calculate local progress for this quad segment (0 to 1)\n const localProgress = Math.max(\n 0,\n Math.min(\n 1,\n (globalProgress - segStart) / Math.max(1e-6, segEnd - segStart)\n )\n );\n\n // Apply scaleX transform\n element.style.transform = `scaleX(${localProgress})`;\n }\n });\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by HighlightLayer - animation handled in updateTime()\n */\n update() {\n // Not used - updateTime handles animation directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Clears element storage, removes DOM elements, and calls parent cleanup.\n */\n destroy() {\n // Clear element storage\n this.elements.clear();\n this.elements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default HighlightLayer;\n"],"names":["HighlightLayer","BaseLayer","container","viewport","annotation","totalW","sum","quad","idx","abs","rectNormToAbs","prevW","q","segStart","segEnd","wrapper","highlight","key","nowSec","element","globalProgress","localProgress"],"mappings":"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"}
package/dist/index9.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const c=require("./index6.cjs");class d extends c.default{constructor(t,s){super(t,s),this.canvasElement=document.createElement("canvas"),this.canvasElement.style.position="absolute",this.canvasElement.style.inset="0",this.canvasElement.style.pointerEvents="none",this.canvasElement.style.zIndex="40",this.container.appendChild(this.canvasElement),this.ctx=this.canvasElement.getContext("2d"),this.rafId=null,this._setupCanvas()}_setupCanvas(){const t=window.devicePixelRatio||1;this.canvasElement.width=Math.round(this.viewport.width*t),this.canvasElement.height=Math.round(this.viewport.height*t),this.canvasElement.style.width=`${this.viewport.width}px`,this.canvasElement.style.height=`${this.viewport.height}px`,this.ctx.setTransform(t,0,0,t,0,0)}setViewport(t){super.setViewport(t),this._setupCanvas()}updateTime(t){super.updateTime(t),this.rafId&&cancelAnimationFrame(this.rafId);const s=()=>{if(!this.isDestroyed){this.ctx.clearRect(0,0,this.canvasElement.width,this.canvasElement.height);for(const e of this.annotations){if(t<e.start)continue;const o=e.end-e.start,l=Math.min(t-e.start,o);for(const i of e.strokes||[]){this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.strokeStyle=i.color||"#1f2937",this.ctx.lineWidth=i.size||3,this.ctx.beginPath();let n=!1;for(const a of i.points){if(a.t>l)break;const h=a.x*this.viewport.width,r=a.y*this.viewport.height;n?this.ctx.lineTo(h,r):(this.ctx.moveTo(h,r),n=!0)}n&&this.ctx.stroke()}}this.rafId=requestAnimationFrame(s)}};s()}render(){}update(){}destroy(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.ctx=null,this.canvasElement&&this.canvasElement.parentNode&&this.canvasElement.parentNode.removeChild(this.canvasElement),this.canvasElement=null,super.destroy()}}exports.default=d;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=require("./index6.cjs");class c extends l.default{constructor(t,e){super(t,e),this.canvasElement=document.createElement("canvas"),this.canvasElement.style.position="absolute",this.canvasElement.style.inset="0",this.canvasElement.style.pointerEvents="none",this.canvasElement.style.zIndex="40",this.container.appendChild(this.canvasElement),this.ctx=this.canvasElement.getContext("2d"),this._setupCanvas()}_setupCanvas(){const t=window.devicePixelRatio||1;this.canvasElement.width=Math.round(this.viewport.width*t),this.canvasElement.height=Math.round(this.viewport.height*t),this.canvasElement.style.width=`${this.viewport.width}px`,this.canvasElement.style.height=`${this.viewport.height}px`,this.ctx.setTransform(t,0,0,t,0,0)}setViewport(t){super.setViewport(t),this._setupCanvas()}updateTime(t){if(super.updateTime(t),!this.isDestroyed){this.ctx.clearRect(0,0,this.canvasElement.width,this.canvasElement.height);for(const e of this.annotations){if(t<e.start)continue;const o=e.end-e.start,r=Math.min(t-e.start,o);for(const s of e.strokes||[]){this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.strokeStyle=s.color||"#1f2937",this.ctx.lineWidth=s.size||3,this.ctx.beginPath();let i=!1;for(const n of s.points){if(n.t>r)break;const a=n.x*this.viewport.width,h=n.y*this.viewport.height;i?this.ctx.lineTo(a,h):(this.ctx.moveTo(a,h),i=!0)}i&&this.ctx.stroke()}}}}render(){}update(){}destroy(){this.ctx=null,this.canvasElement&&this.canvasElement.parentNode&&this.canvasElement.parentNode.removeChild(this.canvasElement),this.canvasElement=null,super.destroy()}}exports.default=c;
2
2
  //# sourceMappingURL=index9.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index9.cjs","sources":["../src/layers/DrawingLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\n\n/**\n * DrawingLayer - Renders ink/drawing annotations on HTML canvas\n *\n * Extends BaseLayer to provide progressive stroke animation for ink annotations.\n * Draws stroke points incrementally based on timeline position using requestAnimationFrame.\n * Handles device pixel ratio scaling for crisp rendering on high-DPI displays.\n *\n * Features:\n * - Progressive stroke drawing point-by-point\n * - Multiple strokes per annotation with custom colors/sizes\n * - Device pixel ratio handling for Retina displays\n * - Smooth 60fps animation with RAF\n * - Efficient canvas clear/redraw cycle\n *\n * @extends BaseLayer\n */\nclass DrawingLayer extends BaseLayer {\n /**\n * Creates a new DrawingLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create canvas element\n this.canvasElement = document.createElement('canvas');\n this.canvasElement.style.position = 'absolute';\n this.canvasElement.style.inset = '0';\n this.canvasElement.style.pointerEvents = 'none';\n this.canvasElement.style.zIndex = '40';\n\n // Append to container\n this.container.appendChild(this.canvasElement);\n\n // Get 2D context\n this.ctx = this.canvasElement.getContext('2d');\n\n // Initialize animation frame ID\n this.rafId = null;\n\n // Setup canvas with device pixel ratio\n this._setupCanvas();\n }\n\n /**\n * Configures canvas dimensions with device pixel ratio scaling\n *\n * Sets canvas buffer size for high-resolution rendering on Retina displays\n * while maintaining correct display size in CSS pixels. Scales context\n * transform to allow drawing with CSS pixel coordinates.\n *\n * @private\n */\n _setupCanvas() {\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer resolution (high-res for crisp rendering)\n this.canvasElement.width = Math.round(this.viewport.width * dpr);\n this.canvasElement.height = Math.round(this.viewport.height * dpr);\n\n // Set canvas display size (CSS pixels)\n this.canvasElement.style.width = `${this.viewport.width}px`;\n this.canvasElement.style.height = `${this.viewport.height}px`;\n\n // Scale context to account for device pixel ratio\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Updates viewport dimensions and resizes canvas\n *\n * Reconfigures canvas buffer and display size when viewport changes\n * due to page navigation or zoom operations.\n *\n * @param {Object} viewport - New viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n * @override\n */\n setViewport(viewport) {\n super.setViewport(viewport);\n this._setupCanvas();\n }\n\n /**\n * Updates timeline position and starts progressive stroke drawing\n *\n * Cancels any existing animation loop and starts a new requestAnimationFrame\n * loop to redraw the canvas with strokes progressively drawn based on elapsed time.\n * Each frame clears the canvas and redraws all visible strokes.\n *\n * @param {number} nowSec - Current timeline position in seconds\n * @throws {Error} If called after layer is destroyed\n * @override\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Cancel existing RAF to prevent multiple loops\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n }\n\n // Start drawing loop\n const draw = () => {\n // Check destroyed state\n if (this.isDestroyed) return;\n\n // Clear canvas\n this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);\n\n // Draw each annotation\n for (const a of this.annotations) {\n // Skip annotations that haven't started yet\n if (nowSec < a.start) continue;\n\n // Calculate elapsed time (capped at duration for persistence)\n const duration = a.end - a.start;\n const elapsed = Math.min(nowSec - a.start, duration);\n\n // Draw each stroke\n for (const stroke of (a.strokes || [])) {\n // Configure stroke style\n this.ctx.lineCap = 'round';\n this.ctx.lineJoin = 'round';\n this.ctx.strokeStyle = stroke.color || '#1f2937';\n this.ctx.lineWidth = stroke.size || 3;\n this.ctx.beginPath();\n\n let started = false;\n\n // Draw points up to current time\n for (const point of stroke.points) {\n // Skip points that haven't been drawn yet\n if (point.t > elapsed) break;\n\n // Convert normalized coordinates to canvas pixels\n const x = point.x * this.viewport.width;\n const y = point.y * this.viewport.height;\n\n if (!started) {\n this.ctx.moveTo(x, y);\n started = true;\n } else {\n this.ctx.lineTo(x, y);\n }\n }\n\n // Render the stroke\n if (started) {\n this.ctx.stroke();\n }\n }\n }\n\n // Schedule next frame\n this.rafId = requestAnimationFrame(draw);\n };\n\n // Start the loop\n draw();\n }\n\n /**\n * Renders the layer content\n *\n * No-op for DrawingLayer - canvas rendering happens in updateTime() RAF loop.\n * Canvas element is created once in constructor and drawn to continuously.\n *\n * @override\n */\n render() {\n // No-op: Canvas rendering happens in updateTime() RAF loop\n // Canvas element is created once in constructor\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used for DrawingLayer - updateTime() handles updates via RAF loop.\n *\n * @override\n */\n update() {\n // Not used - updateTime handles drawing via RAF loop\n }\n\n /**\n * Destroys the layer and releases resources\n *\n * Cancels animation loop, clears references, and removes canvas from DOM.\n * Safe to call multiple times (idempotent).\n *\n * @override\n */\n destroy() {\n // Cancel animation loop first\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Clear context reference\n this.ctx = null;\n\n // Remove canvas from DOM\n if (this.canvasElement && this.canvasElement.parentNode) {\n this.canvasElement.parentNode.removeChild(this.canvasElement);\n }\n this.canvasElement = null;\n\n // Call parent cleanup (always last)\n super.destroy();\n }\n}\n\nexport default DrawingLayer;\n"],"names":["DrawingLayer","BaseLayer","container","viewport","dpr","nowSec","draw","a","duration","elapsed","stroke","started","point","x","y"],"mappings":"4IAkBA,MAAMA,UAAqBC,EAAAA,OAAU,CAUnC,YAAYC,EAAWC,EAAU,CAC/B,MAAMD,EAAWC,CAAQ,EAGzB,KAAK,cAAgB,SAAS,cAAc,QAAQ,EACpD,KAAK,cAAc,MAAM,SAAW,WACpC,KAAK,cAAc,MAAM,MAAQ,IACjC,KAAK,cAAc,MAAM,cAAgB,OACzC,KAAK,cAAc,MAAM,OAAS,KAGlC,KAAK,UAAU,YAAY,KAAK,aAAa,EAG7C,KAAK,IAAM,KAAK,cAAc,WAAW,IAAI,EAG7C,KAAK,MAAQ,KAGb,KAAK,aAAY,CACnB,CAWA,cAAe,CACb,MAAMC,EAAM,OAAO,kBAAoB,EAGvC,KAAK,cAAc,MAAQ,KAAK,MAAM,KAAK,SAAS,MAAQA,CAAG,EAC/D,KAAK,cAAc,OAAS,KAAK,MAAM,KAAK,SAAS,OAASA,CAAG,EAGjE,KAAK,cAAc,MAAM,MAAQ,GAAG,KAAK,SAAS,KAAK,KACvD,KAAK,cAAc,MAAM,OAAS,GAAG,KAAK,SAAS,MAAM,KAGzD,KAAK,IAAI,aAAaA,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,CAC5C,CAcA,YAAYD,EAAU,CACpB,MAAM,YAAYA,CAAQ,EAC1B,KAAK,aAAY,CACnB,CAaA,WAAWE,EAAQ,CACjB,MAAM,WAAWA,CAAM,EAGnB,KAAK,OACP,qBAAqB,KAAK,KAAK,EAIjC,MAAMC,EAAO,IAAM,CAEjB,GAAI,MAAK,YAGT,MAAK,IAAI,UAAU,EAAG,EAAG,KAAK,cAAc,MAAO,KAAK,cAAc,MAAM,EAG5E,UAAWC,KAAK,KAAK,YAAa,CAEhC,GAAIF,EAASE,EAAE,MAAO,SAGtB,MAAMC,EAAWD,EAAE,IAAMA,EAAE,MACrBE,EAAU,KAAK,IAAIJ,EAASE,EAAE,MAAOC,CAAQ,EAGnD,UAAWE,KAAWH,EAAE,SAAW,CAAA,EAAK,CAEtC,KAAK,IAAI,QAAU,QACnB,KAAK,IAAI,SAAW,QACpB,KAAK,IAAI,YAAcG,EAAO,OAAS,UACvC,KAAK,IAAI,UAAYA,EAAO,MAAQ,EACpC,KAAK,IAAI,UAAS,EAElB,IAAIC,EAAU,GAGd,UAAWC,KAASF,EAAO,OAAQ,CAEjC,GAAIE,EAAM,EAAIH,EAAS,MAGvB,MAAMI,EAAID,EAAM,EAAI,KAAK,SAAS,MAC5BE,EAAIF,EAAM,EAAI,KAAK,SAAS,OAE7BD,EAIH,KAAK,IAAI,OAAOE,EAAGC,CAAC,GAHpB,KAAK,IAAI,OAAOD,EAAGC,CAAC,EACpBH,EAAU,GAId,CAGIA,GACF,KAAK,IAAI,OAAM,CAEnB,CACF,CAGA,KAAK,MAAQ,sBAAsBL,CAAI,EACzC,EAGAA,EAAI,CACN,CAUA,QAAS,CAGT,CASA,QAAS,CAET,CAUA,SAAU,CAEJ,KAAK,QACP,qBAAqB,KAAK,KAAK,EAC/B,KAAK,MAAQ,MAIf,KAAK,IAAM,KAGP,KAAK,eAAiB,KAAK,cAAc,YAC3C,KAAK,cAAc,WAAW,YAAY,KAAK,aAAa,EAE9D,KAAK,cAAgB,KAGrB,MAAM,QAAO,CACf,CACF"}
1
+ {"version":3,"file":"index9.cjs","sources":["../src/layers/DrawingLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\n\n/**\n * DrawingLayer - Renders ink/drawing annotations on HTML canvas\n *\n * Extends BaseLayer to provide progressive stroke animation for ink annotations.\n * Draws stroke points incrementally based on timeline position using requestAnimationFrame.\n * Handles device pixel ratio scaling for crisp rendering on high-DPI displays.\n *\n * Features:\n * - Progressive stroke drawing point-by-point\n * - Multiple strokes per annotation with custom colors/sizes\n * - Device pixel ratio handling for Retina displays\n * - Smooth 60fps animation with RAF\n * - Efficient canvas clear/redraw cycle\n *\n * @extends BaseLayer\n */\nclass DrawingLayer extends BaseLayer {\n /**\n * Creates a new DrawingLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create canvas element\n this.canvasElement = document.createElement('canvas');\n this.canvasElement.style.position = 'absolute';\n this.canvasElement.style.inset = '0';\n this.canvasElement.style.pointerEvents = 'none';\n this.canvasElement.style.zIndex = '40';\n\n // Append to container\n this.container.appendChild(this.canvasElement);\n\n // Get 2D context\n this.ctx = this.canvasElement.getContext('2d');\n\n // Setup canvas with device pixel ratio\n this._setupCanvas();\n }\n\n /**\n * Configures canvas dimensions with device pixel ratio scaling\n *\n * Sets canvas buffer size for high-resolution rendering on Retina displays\n * while maintaining correct display size in CSS pixels. Scales context\n * transform to allow drawing with CSS pixel coordinates.\n *\n * @private\n */\n _setupCanvas() {\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer resolution (high-res for crisp rendering)\n this.canvasElement.width = Math.round(this.viewport.width * dpr);\n this.canvasElement.height = Math.round(this.viewport.height * dpr);\n\n // Set canvas display size (CSS pixels)\n this.canvasElement.style.width = `${this.viewport.width}px`;\n this.canvasElement.style.height = `${this.viewport.height}px`;\n\n // Scale context to account for device pixel ratio\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Updates viewport dimensions and resizes canvas\n *\n * Reconfigures canvas buffer and display size when viewport changes\n * due to page navigation or zoom operations.\n *\n * @param {Object} viewport - New viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n * @override\n */\n setViewport(viewport) {\n super.setViewport(viewport);\n this._setupCanvas();\n }\n\n /**\n * Updates timeline position and draws progressive strokes\n *\n * Redraws the canvas with strokes progressively drawn based on elapsed time.\n * Clears the canvas and redraws all visible strokes.\n * Renders once per call - no continuous loop.\n *\n * @param {number} nowSec - Current timeline position in seconds\n * @throws {Error} If called after layer is destroyed\n * @override\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Check destroyed state\n if (this.isDestroyed) return;\n\n // Clear canvas\n this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);\n\n // Draw each annotation\n for (const a of this.annotations) {\n // Skip annotations that haven't started yet\n if (nowSec < a.start) continue;\n\n // Calculate elapsed time (capped at duration for persistence)\n const duration = a.end - a.start;\n const elapsed = Math.min(nowSec - a.start, duration);\n\n // Draw each stroke\n for (const stroke of (a.strokes || [])) {\n // Configure stroke style\n this.ctx.lineCap = 'round';\n this.ctx.lineJoin = 'round';\n this.ctx.strokeStyle = stroke.color || '#1f2937';\n this.ctx.lineWidth = stroke.size || 3;\n this.ctx.beginPath();\n\n let started = false;\n\n // Draw points up to current time\n for (const point of stroke.points) {\n // Skip points that haven't been drawn yet\n if (point.t > elapsed) break;\n\n // Convert normalized coordinates to canvas pixels\n const x = point.x * this.viewport.width;\n const y = point.y * this.viewport.height;\n\n if (!started) {\n this.ctx.moveTo(x, y);\n started = true;\n } else {\n this.ctx.lineTo(x, y);\n }\n }\n\n // Render the stroke\n if (started) {\n this.ctx.stroke();\n }\n }\n }\n }\n\n /**\n * Renders the layer content\n *\n * No-op for DrawingLayer - canvas rendering happens in updateTime().\n * Canvas element is created once in constructor.\n *\n * @override\n */\n render() {\n // No-op: Canvas rendering happens in updateTime()\n // Canvas element is created once in constructor\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used for DrawingLayer - updateTime() handles drawing directly.\n *\n * @override\n */\n update() {\n // Not used - updateTime handles drawing directly\n }\n\n /**\n * Destroys the layer and releases resources\n *\n * Clears references and removes canvas from DOM.\n * Safe to call multiple times (idempotent).\n *\n * @override\n */\n destroy() {\n // Clear context reference\n this.ctx = null;\n\n // Remove canvas from DOM\n if (this.canvasElement && this.canvasElement.parentNode) {\n this.canvasElement.parentNode.removeChild(this.canvasElement);\n }\n this.canvasElement = null;\n\n // Call parent cleanup (always last)\n super.destroy();\n }\n}\n\nexport default DrawingLayer;\n"],"names":["DrawingLayer","BaseLayer","container","viewport","dpr","nowSec","a","duration","elapsed","stroke","started","point","x","y"],"mappings":"4IAkBA,MAAMA,UAAqBC,EAAAA,OAAU,CAUnC,YAAYC,EAAWC,EAAU,CAC/B,MAAMD,EAAWC,CAAQ,EAGzB,KAAK,cAAgB,SAAS,cAAc,QAAQ,EACpD,KAAK,cAAc,MAAM,SAAW,WACpC,KAAK,cAAc,MAAM,MAAQ,IACjC,KAAK,cAAc,MAAM,cAAgB,OACzC,KAAK,cAAc,MAAM,OAAS,KAGlC,KAAK,UAAU,YAAY,KAAK,aAAa,EAG7C,KAAK,IAAM,KAAK,cAAc,WAAW,IAAI,EAG7C,KAAK,aAAY,CACnB,CAWA,cAAe,CACb,MAAMC,EAAM,OAAO,kBAAoB,EAGvC,KAAK,cAAc,MAAQ,KAAK,MAAM,KAAK,SAAS,MAAQA,CAAG,EAC/D,KAAK,cAAc,OAAS,KAAK,MAAM,KAAK,SAAS,OAASA,CAAG,EAGjE,KAAK,cAAc,MAAM,MAAQ,GAAG,KAAK,SAAS,KAAK,KACvD,KAAK,cAAc,MAAM,OAAS,GAAG,KAAK,SAAS,MAAM,KAGzD,KAAK,IAAI,aAAaA,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,CAC5C,CAcA,YAAYD,EAAU,CACpB,MAAM,YAAYA,CAAQ,EAC1B,KAAK,aAAY,CACnB,CAaA,WAAWE,EAAQ,CAIjB,GAHA,MAAM,WAAWA,CAAM,EAGnB,MAAK,YAGT,MAAK,IAAI,UAAU,EAAG,EAAG,KAAK,cAAc,MAAO,KAAK,cAAc,MAAM,EAG5E,UAAWC,KAAK,KAAK,YAAa,CAEhC,GAAID,EAASC,EAAE,MAAO,SAGtB,MAAMC,EAAWD,EAAE,IAAMA,EAAE,MACrBE,EAAU,KAAK,IAAIH,EAASC,EAAE,MAAOC,CAAQ,EAGnD,UAAWE,KAAWH,EAAE,SAAW,CAAA,EAAK,CAEtC,KAAK,IAAI,QAAU,QACnB,KAAK,IAAI,SAAW,QACpB,KAAK,IAAI,YAAcG,EAAO,OAAS,UACvC,KAAK,IAAI,UAAYA,EAAO,MAAQ,EACpC,KAAK,IAAI,UAAS,EAElB,IAAIC,EAAU,GAGd,UAAWC,KAASF,EAAO,OAAQ,CAEjC,GAAIE,EAAM,EAAIH,EAAS,MAGvB,MAAMI,EAAID,EAAM,EAAI,KAAK,SAAS,MAC5BE,EAAIF,EAAM,EAAI,KAAK,SAAS,OAE7BD,EAIH,KAAK,IAAI,OAAOE,EAAGC,CAAC,GAHpB,KAAK,IAAI,OAAOD,EAAGC,CAAC,EACpBH,EAAU,GAId,CAGIA,GACF,KAAK,IAAI,OAAM,CAEnB,CACF,EACF,CAUA,QAAS,CAGT,CASA,QAAS,CAET,CAUA,SAAU,CAER,KAAK,IAAM,KAGP,KAAK,eAAiB,KAAK,cAAc,YAC3C,KAAK,cAAc,WAAW,YAAY,KAAK,aAAa,EAE9D,KAAK,cAAgB,KAGrB,MAAM,QAAO,CACf,CACF"}
package/dist/index9.js CHANGED
@@ -1,5 +1,5 @@
1
- import l from "./index6.js";
2
- class p extends l {
1
+ import c from "./index6.js";
2
+ class p extends c {
3
3
  /**
4
4
  * Creates a new DrawingLayer instance
5
5
  *
@@ -9,8 +9,8 @@ class p extends l {
9
9
  * @param {number} viewport.height - Viewport height in pixels
10
10
  * @param {number} viewport.scale - PDF scale/zoom level
11
11
  */
12
- constructor(t, s) {
13
- super(t, s), this.canvasElement = document.createElement("canvas"), this.canvasElement.style.position = "absolute", this.canvasElement.style.inset = "0", this.canvasElement.style.pointerEvents = "none", this.canvasElement.style.zIndex = "40", this.container.appendChild(this.canvasElement), this.ctx = this.canvasElement.getContext("2d"), this.rafId = null, this._setupCanvas();
12
+ constructor(t, e) {
13
+ super(t, e), this.canvasElement = document.createElement("canvas"), this.canvasElement.style.position = "absolute", this.canvasElement.style.inset = "0", this.canvasElement.style.pointerEvents = "none", this.canvasElement.style.zIndex = "40", this.container.appendChild(this.canvasElement), this.ctx = this.canvasElement.getContext("2d"), this._setupCanvas();
14
14
  }
15
15
  /**
16
16
  * Configures canvas dimensions with device pixel ratio scaling
@@ -41,45 +41,40 @@ class p extends l {
41
41
  super.setViewport(t), this._setupCanvas();
42
42
  }
43
43
  /**
44
- * Updates timeline position and starts progressive stroke drawing
44
+ * Updates timeline position and draws progressive strokes
45
45
  *
46
- * Cancels any existing animation loop and starts a new requestAnimationFrame
47
- * loop to redraw the canvas with strokes progressively drawn based on elapsed time.
48
- * Each frame clears the canvas and redraws all visible strokes.
46
+ * Redraws the canvas with strokes progressively drawn based on elapsed time.
47
+ * Clears the canvas and redraws all visible strokes.
48
+ * Renders once per call - no continuous loop.
49
49
  *
50
50
  * @param {number} nowSec - Current timeline position in seconds
51
51
  * @throws {Error} If called after layer is destroyed
52
52
  * @override
53
53
  */
54
54
  updateTime(t) {
55
- super.updateTime(t), this.rafId && cancelAnimationFrame(this.rafId);
56
- const s = () => {
57
- if (!this.isDestroyed) {
58
- this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
59
- for (const e of this.annotations) {
60
- if (t < e.start) continue;
61
- const o = e.end - e.start, c = Math.min(t - e.start, o);
62
- for (const i of e.strokes || []) {
63
- this.ctx.lineCap = "round", this.ctx.lineJoin = "round", this.ctx.strokeStyle = i.color || "#1f2937", this.ctx.lineWidth = i.size || 3, this.ctx.beginPath();
64
- let n = !1;
65
- for (const a of i.points) {
66
- if (a.t > c) break;
67
- const h = a.x * this.viewport.width, r = a.y * this.viewport.height;
68
- n ? this.ctx.lineTo(h, r) : (this.ctx.moveTo(h, r), n = !0);
69
- }
70
- n && this.ctx.stroke();
55
+ if (super.updateTime(t), !this.isDestroyed) {
56
+ this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
57
+ for (const e of this.annotations) {
58
+ if (t < e.start) continue;
59
+ const o = e.end - e.start, r = Math.min(t - e.start, o);
60
+ for (const s of e.strokes || []) {
61
+ this.ctx.lineCap = "round", this.ctx.lineJoin = "round", this.ctx.strokeStyle = s.color || "#1f2937", this.ctx.lineWidth = s.size || 3, this.ctx.beginPath();
62
+ let i = !1;
63
+ for (const n of s.points) {
64
+ if (n.t > r) break;
65
+ const a = n.x * this.viewport.width, h = n.y * this.viewport.height;
66
+ i ? this.ctx.lineTo(a, h) : (this.ctx.moveTo(a, h), i = !0);
71
67
  }
68
+ i && this.ctx.stroke();
72
69
  }
73
- this.rafId = requestAnimationFrame(s);
74
70
  }
75
- };
76
- s();
71
+ }
77
72
  }
78
73
  /**
79
74
  * Renders the layer content
80
75
  *
81
- * No-op for DrawingLayer - canvas rendering happens in updateTime() RAF loop.
82
- * Canvas element is created once in constructor and drawn to continuously.
76
+ * No-op for DrawingLayer - canvas rendering happens in updateTime().
77
+ * Canvas element is created once in constructor.
83
78
  *
84
79
  * @override
85
80
  */
@@ -88,7 +83,7 @@ class p extends l {
88
83
  /**
89
84
  * Updates the visual state of the layer
90
85
  *
91
- * Not used for DrawingLayer - updateTime() handles updates via RAF loop.
86
+ * Not used for DrawingLayer - updateTime() handles drawing directly.
92
87
  *
93
88
  * @override
94
89
  */
@@ -97,13 +92,13 @@ class p extends l {
97
92
  /**
98
93
  * Destroys the layer and releases resources
99
94
  *
100
- * Cancels animation loop, clears references, and removes canvas from DOM.
95
+ * Clears references and removes canvas from DOM.
101
96
  * Safe to call multiple times (idempotent).
102
97
  *
103
98
  * @override
104
99
  */
105
100
  destroy() {
106
- this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null), this.ctx = null, this.canvasElement && this.canvasElement.parentNode && this.canvasElement.parentNode.removeChild(this.canvasElement), this.canvasElement = null, super.destroy();
101
+ this.ctx = null, this.canvasElement && this.canvasElement.parentNode && this.canvasElement.parentNode.removeChild(this.canvasElement), this.canvasElement = null, super.destroy();
107
102
  }
108
103
  }
109
104
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"index9.js","sources":["../src/layers/DrawingLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\n\n/**\n * DrawingLayer - Renders ink/drawing annotations on HTML canvas\n *\n * Extends BaseLayer to provide progressive stroke animation for ink annotations.\n * Draws stroke points incrementally based on timeline position using requestAnimationFrame.\n * Handles device pixel ratio scaling for crisp rendering on high-DPI displays.\n *\n * Features:\n * - Progressive stroke drawing point-by-point\n * - Multiple strokes per annotation with custom colors/sizes\n * - Device pixel ratio handling for Retina displays\n * - Smooth 60fps animation with RAF\n * - Efficient canvas clear/redraw cycle\n *\n * @extends BaseLayer\n */\nclass DrawingLayer extends BaseLayer {\n /**\n * Creates a new DrawingLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create canvas element\n this.canvasElement = document.createElement('canvas');\n this.canvasElement.style.position = 'absolute';\n this.canvasElement.style.inset = '0';\n this.canvasElement.style.pointerEvents = 'none';\n this.canvasElement.style.zIndex = '40';\n\n // Append to container\n this.container.appendChild(this.canvasElement);\n\n // Get 2D context\n this.ctx = this.canvasElement.getContext('2d');\n\n // Initialize animation frame ID\n this.rafId = null;\n\n // Setup canvas with device pixel ratio\n this._setupCanvas();\n }\n\n /**\n * Configures canvas dimensions with device pixel ratio scaling\n *\n * Sets canvas buffer size for high-resolution rendering on Retina displays\n * while maintaining correct display size in CSS pixels. Scales context\n * transform to allow drawing with CSS pixel coordinates.\n *\n * @private\n */\n _setupCanvas() {\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer resolution (high-res for crisp rendering)\n this.canvasElement.width = Math.round(this.viewport.width * dpr);\n this.canvasElement.height = Math.round(this.viewport.height * dpr);\n\n // Set canvas display size (CSS pixels)\n this.canvasElement.style.width = `${this.viewport.width}px`;\n this.canvasElement.style.height = `${this.viewport.height}px`;\n\n // Scale context to account for device pixel ratio\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Updates viewport dimensions and resizes canvas\n *\n * Reconfigures canvas buffer and display size when viewport changes\n * due to page navigation or zoom operations.\n *\n * @param {Object} viewport - New viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n * @override\n */\n setViewport(viewport) {\n super.setViewport(viewport);\n this._setupCanvas();\n }\n\n /**\n * Updates timeline position and starts progressive stroke drawing\n *\n * Cancels any existing animation loop and starts a new requestAnimationFrame\n * loop to redraw the canvas with strokes progressively drawn based on elapsed time.\n * Each frame clears the canvas and redraws all visible strokes.\n *\n * @param {number} nowSec - Current timeline position in seconds\n * @throws {Error} If called after layer is destroyed\n * @override\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Cancel existing RAF to prevent multiple loops\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n }\n\n // Start drawing loop\n const draw = () => {\n // Check destroyed state\n if (this.isDestroyed) return;\n\n // Clear canvas\n this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);\n\n // Draw each annotation\n for (const a of this.annotations) {\n // Skip annotations that haven't started yet\n if (nowSec < a.start) continue;\n\n // Calculate elapsed time (capped at duration for persistence)\n const duration = a.end - a.start;\n const elapsed = Math.min(nowSec - a.start, duration);\n\n // Draw each stroke\n for (const stroke of (a.strokes || [])) {\n // Configure stroke style\n this.ctx.lineCap = 'round';\n this.ctx.lineJoin = 'round';\n this.ctx.strokeStyle = stroke.color || '#1f2937';\n this.ctx.lineWidth = stroke.size || 3;\n this.ctx.beginPath();\n\n let started = false;\n\n // Draw points up to current time\n for (const point of stroke.points) {\n // Skip points that haven't been drawn yet\n if (point.t > elapsed) break;\n\n // Convert normalized coordinates to canvas pixels\n const x = point.x * this.viewport.width;\n const y = point.y * this.viewport.height;\n\n if (!started) {\n this.ctx.moveTo(x, y);\n started = true;\n } else {\n this.ctx.lineTo(x, y);\n }\n }\n\n // Render the stroke\n if (started) {\n this.ctx.stroke();\n }\n }\n }\n\n // Schedule next frame\n this.rafId = requestAnimationFrame(draw);\n };\n\n // Start the loop\n draw();\n }\n\n /**\n * Renders the layer content\n *\n * No-op for DrawingLayer - canvas rendering happens in updateTime() RAF loop.\n * Canvas element is created once in constructor and drawn to continuously.\n *\n * @override\n */\n render() {\n // No-op: Canvas rendering happens in updateTime() RAF loop\n // Canvas element is created once in constructor\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used for DrawingLayer - updateTime() handles updates via RAF loop.\n *\n * @override\n */\n update() {\n // Not used - updateTime handles drawing via RAF loop\n }\n\n /**\n * Destroys the layer and releases resources\n *\n * Cancels animation loop, clears references, and removes canvas from DOM.\n * Safe to call multiple times (idempotent).\n *\n * @override\n */\n destroy() {\n // Cancel animation loop first\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Clear context reference\n this.ctx = null;\n\n // Remove canvas from DOM\n if (this.canvasElement && this.canvasElement.parentNode) {\n this.canvasElement.parentNode.removeChild(this.canvasElement);\n }\n this.canvasElement = null;\n\n // Call parent cleanup (always last)\n super.destroy();\n }\n}\n\nexport default DrawingLayer;\n"],"names":["DrawingLayer","BaseLayer","container","viewport","dpr","nowSec","draw","a","duration","elapsed","stroke","started","point","x","y"],"mappings":"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"}
1
+ {"version":3,"file":"index9.js","sources":["../src/layers/DrawingLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\n\n/**\n * DrawingLayer - Renders ink/drawing annotations on HTML canvas\n *\n * Extends BaseLayer to provide progressive stroke animation for ink annotations.\n * Draws stroke points incrementally based on timeline position using requestAnimationFrame.\n * Handles device pixel ratio scaling for crisp rendering on high-DPI displays.\n *\n * Features:\n * - Progressive stroke drawing point-by-point\n * - Multiple strokes per annotation with custom colors/sizes\n * - Device pixel ratio handling for Retina displays\n * - Smooth 60fps animation with RAF\n * - Efficient canvas clear/redraw cycle\n *\n * @extends BaseLayer\n */\nclass DrawingLayer extends BaseLayer {\n /**\n * Creates a new DrawingLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create canvas element\n this.canvasElement = document.createElement('canvas');\n this.canvasElement.style.position = 'absolute';\n this.canvasElement.style.inset = '0';\n this.canvasElement.style.pointerEvents = 'none';\n this.canvasElement.style.zIndex = '40';\n\n // Append to container\n this.container.appendChild(this.canvasElement);\n\n // Get 2D context\n this.ctx = this.canvasElement.getContext('2d');\n\n // Setup canvas with device pixel ratio\n this._setupCanvas();\n }\n\n /**\n * Configures canvas dimensions with device pixel ratio scaling\n *\n * Sets canvas buffer size for high-resolution rendering on Retina displays\n * while maintaining correct display size in CSS pixels. Scales context\n * transform to allow drawing with CSS pixel coordinates.\n *\n * @private\n */\n _setupCanvas() {\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer resolution (high-res for crisp rendering)\n this.canvasElement.width = Math.round(this.viewport.width * dpr);\n this.canvasElement.height = Math.round(this.viewport.height * dpr);\n\n // Set canvas display size (CSS pixels)\n this.canvasElement.style.width = `${this.viewport.width}px`;\n this.canvasElement.style.height = `${this.viewport.height}px`;\n\n // Scale context to account for device pixel ratio\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Updates viewport dimensions and resizes canvas\n *\n * Reconfigures canvas buffer and display size when viewport changes\n * due to page navigation or zoom operations.\n *\n * @param {Object} viewport - New viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - PDF scale/zoom level\n * @override\n */\n setViewport(viewport) {\n super.setViewport(viewport);\n this._setupCanvas();\n }\n\n /**\n * Updates timeline position and draws progressive strokes\n *\n * Redraws the canvas with strokes progressively drawn based on elapsed time.\n * Clears the canvas and redraws all visible strokes.\n * Renders once per call - no continuous loop.\n *\n * @param {number} nowSec - Current timeline position in seconds\n * @throws {Error} If called after layer is destroyed\n * @override\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Check destroyed state\n if (this.isDestroyed) return;\n\n // Clear canvas\n this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);\n\n // Draw each annotation\n for (const a of this.annotations) {\n // Skip annotations that haven't started yet\n if (nowSec < a.start) continue;\n\n // Calculate elapsed time (capped at duration for persistence)\n const duration = a.end - a.start;\n const elapsed = Math.min(nowSec - a.start, duration);\n\n // Draw each stroke\n for (const stroke of (a.strokes || [])) {\n // Configure stroke style\n this.ctx.lineCap = 'round';\n this.ctx.lineJoin = 'round';\n this.ctx.strokeStyle = stroke.color || '#1f2937';\n this.ctx.lineWidth = stroke.size || 3;\n this.ctx.beginPath();\n\n let started = false;\n\n // Draw points up to current time\n for (const point of stroke.points) {\n // Skip points that haven't been drawn yet\n if (point.t > elapsed) break;\n\n // Convert normalized coordinates to canvas pixels\n const x = point.x * this.viewport.width;\n const y = point.y * this.viewport.height;\n\n if (!started) {\n this.ctx.moveTo(x, y);\n started = true;\n } else {\n this.ctx.lineTo(x, y);\n }\n }\n\n // Render the stroke\n if (started) {\n this.ctx.stroke();\n }\n }\n }\n }\n\n /**\n * Renders the layer content\n *\n * No-op for DrawingLayer - canvas rendering happens in updateTime().\n * Canvas element is created once in constructor.\n *\n * @override\n */\n render() {\n // No-op: Canvas rendering happens in updateTime()\n // Canvas element is created once in constructor\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used for DrawingLayer - updateTime() handles drawing directly.\n *\n * @override\n */\n update() {\n // Not used - updateTime handles drawing directly\n }\n\n /**\n * Destroys the layer and releases resources\n *\n * Clears references and removes canvas from DOM.\n * Safe to call multiple times (idempotent).\n *\n * @override\n */\n destroy() {\n // Clear context reference\n this.ctx = null;\n\n // Remove canvas from DOM\n if (this.canvasElement && this.canvasElement.parentNode) {\n this.canvasElement.parentNode.removeChild(this.canvasElement);\n }\n this.canvasElement = null;\n\n // Call parent cleanup (always last)\n super.destroy();\n }\n}\n\nexport default DrawingLayer;\n"],"names":["DrawingLayer","BaseLayer","container","viewport","dpr","nowSec","a","duration","elapsed","stroke","started","point","x","y"],"mappings":";AAkBA,MAAMA,UAAqBC,EAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUnC,YAAYC,GAAWC,GAAU;AAC/B,UAAMD,GAAWC,CAAQ,GAGzB,KAAK,gBAAgB,SAAS,cAAc,QAAQ,GACpD,KAAK,cAAc,MAAM,WAAW,YACpC,KAAK,cAAc,MAAM,QAAQ,KACjC,KAAK,cAAc,MAAM,gBAAgB,QACzC,KAAK,cAAc,MAAM,SAAS,MAGlC,KAAK,UAAU,YAAY,KAAK,aAAa,GAG7C,KAAK,MAAM,KAAK,cAAc,WAAW,IAAI,GAG7C,KAAK,aAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,eAAe;AACb,UAAMC,IAAM,OAAO,oBAAoB;AAGvC,SAAK,cAAc,QAAQ,KAAK,MAAM,KAAK,SAAS,QAAQA,CAAG,GAC/D,KAAK,cAAc,SAAS,KAAK,MAAM,KAAK,SAAS,SAASA,CAAG,GAGjE,KAAK,cAAc,MAAM,QAAQ,GAAG,KAAK,SAAS,KAAK,MACvD,KAAK,cAAc,MAAM,SAAS,GAAG,KAAK,SAAS,MAAM,MAGzD,KAAK,IAAI,aAAaA,GAAK,GAAG,GAAGA,GAAK,GAAG,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,YAAYD,GAAU;AACpB,UAAM,YAAYA,CAAQ,GAC1B,KAAK,aAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,WAAWE,GAAQ;AAIjB,QAHA,MAAM,WAAWA,CAAM,GAGnB,MAAK,aAGT;AAAA,WAAK,IAAI,UAAU,GAAG,GAAG,KAAK,cAAc,OAAO,KAAK,cAAc,MAAM;AAG5E,iBAAWC,KAAK,KAAK,aAAa;AAEhC,YAAID,IAASC,EAAE,MAAO;AAGtB,cAAMC,IAAWD,EAAE,MAAMA,EAAE,OACrBE,IAAU,KAAK,IAAIH,IAASC,EAAE,OAAOC,CAAQ;AAGnD,mBAAWE,KAAWH,EAAE,WAAW,CAAA,GAAK;AAEtC,eAAK,IAAI,UAAU,SACnB,KAAK,IAAI,WAAW,SACpB,KAAK,IAAI,cAAcG,EAAO,SAAS,WACvC,KAAK,IAAI,YAAYA,EAAO,QAAQ,GACpC,KAAK,IAAI,UAAS;AAElB,cAAIC,IAAU;AAGd,qBAAWC,KAASF,EAAO,QAAQ;AAEjC,gBAAIE,EAAM,IAAIH,EAAS;AAGvB,kBAAMI,IAAID,EAAM,IAAI,KAAK,SAAS,OAC5BE,IAAIF,EAAM,IAAI,KAAK,SAAS;AAElC,YAAKD,IAIH,KAAK,IAAI,OAAOE,GAAGC,CAAC,KAHpB,KAAK,IAAI,OAAOD,GAAGC,CAAC,GACpBH,IAAU;AAAA,UAId;AAGA,UAAIA,KACF,KAAK,IAAI,OAAM;AAAA,QAEnB;AAAA,MACF;AAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAS;AAAA,EAGT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU;AAER,SAAK,MAAM,MAGP,KAAK,iBAAiB,KAAK,cAAc,cAC3C,KAAK,cAAc,WAAW,YAAY,KAAK,aAAa,GAE9D,KAAK,gBAAgB,MAGrB,MAAM,QAAO;AAAA,EACf;AACF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-annotation-renderer",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Framework-agnostic PDF annotation renderer with timeline synchronization for educational content and interactive documents",
6
6
  "keywords": [