web-annotation-renderer 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index5.cjs","sources":["../src/renderer/StrokeRenderer.js"],"sourcesContent":["/**\n * StrokeRenderer - Unified canvas-based annotation renderer\n *\n * Single entry point for rendering annotations as strokes on canvas.\n * Handles conversion from annotations to strokes and progressive rendering.\n *\n * @module renderer/StrokeRenderer\n */\n\nimport { highlightToStrokes, textToStrokes } from '../converters/index.js';\nimport { deepMerge } from '../pen/effects.js';\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG = {\n pen: {\n jitter: { amplitude: 1.0, frequency: 0.08 },\n pressure: { taperIn: 0.15, taperOut: 0.20 },\n wobble: { amplitude: 1.5, frequency: 0.05 }\n },\n highlight: {\n color: 'rgba(255, 255, 0, 0.3)',\n width: 24,\n lineCap: 'butt',\n jitter: { amplitude: 0 }\n },\n text: {\n color: 'rgba(220, 20, 60, 1.0)',\n width: 2,\n fontSize: 16,\n lineCap: 'round'\n }\n};\n\n/**\n * StrokeRenderer class\n *\n * Converts annotations to strokes and renders them progressively on canvas.\n *\n * @class\n * @example\n * const renderer = new StrokeRenderer(canvas, {\n * highlight: { color: 'rgba(0, 255, 200, 0.4)' }\n * });\n * renderer.setViewport(800, 600);\n * renderer.setAnnotations(annotations);\n * renderer.render(1.5); // Render at t=1.5 seconds\n */\nclass StrokeRenderer {\n /**\n * Create StrokeRenderer instance\n *\n * @param {HTMLCanvasElement} canvas - Canvas element for rendering\n * @param {Object} [config={}] - Configuration overrides\n * @param {Object} [config.pen] - Global pen settings\n * @param {Object} [config.highlight] - Highlight type settings\n * @param {Object} [config.text] - Text type settings\n */\n constructor(canvas, config = {}) {\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error('StrokeRenderer: canvas must be a valid HTMLCanvasElement');\n }\n\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n this.config = deepMerge(DEFAULT_CONFIG, config);\n this.strokes = [];\n this.viewport = { width: 0, height: 0 };\n\n // Register built-in converters\n this.converters = {\n highlight: highlightToStrokes,\n text: textToStrokes\n };\n }\n\n /**\n * Register a custom converter for a new annotation type\n *\n * @param {string} type - Annotation type name\n * @param {Function} converter - Converter function (annotation, style) => strokes[]\n */\n registerConverter(type, converter) {\n if (typeof converter !== 'function') {\n throw new Error('StrokeRenderer.registerConverter: converter must be a function');\n }\n this.converters[type] = converter;\n }\n\n /**\n * Set viewport dimensions and configure canvas\n *\n * Handles high-DPI displays by scaling the canvas buffer.\n *\n * @param {number} width - Viewport width in CSS pixels\n * @param {number} height - Viewport height in CSS pixels\n */\n setViewport(width, height) {\n this.viewport = { width, height };\n\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer size (high-res)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set canvas display size (CSS)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n // Scale context for high-DPI\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Set annotations and convert them to strokes\n *\n * Clears existing strokes and converts all annotations.\n *\n * @param {Array} annotations - Array of annotation objects\n * @param {number} [page] - Optional page filter (only convert annotations for this page)\n */\n setAnnotations(annotations, page = null) {\n if (!Array.isArray(annotations)) {\n console.warn('StrokeRenderer.setAnnotations: annotations must be an array');\n this.strokes = [];\n return;\n }\n\n // Filter by page if specified\n const filtered = page !== null\n ? annotations.filter(a => a.page === page)\n : annotations;\n\n // Convert each annotation to strokes\n this.strokes = filtered.flatMap(annotation => {\n const converter = this.converters[annotation.type];\n\n if (!converter) {\n console.warn(`StrokeRenderer: Unknown annotation type \"${annotation.type}\"`);\n return [];\n }\n\n // Resolve style: pen → type → annotation.style\n const style = this._resolveStyle(annotation);\n\n return converter(annotation, style);\n });\n }\n\n /**\n * Set pre-converted strokes directly\n *\n * Bypasses conversion, useful when strokes come from external source.\n *\n * @param {Array} strokes - Array of stroke command objects\n */\n setStrokes(strokes) {\n if (!Array.isArray(strokes)) {\n console.warn('StrokeRenderer.setStrokes: strokes must be an array');\n this.strokes = [];\n return;\n }\n this.strokes = strokes;\n }\n\n /**\n * Render strokes at the given time\n *\n * Clears canvas and draws all visible strokes with appropriate progress.\n *\n * @param {number} time - Current time in seconds\n */\n render(time) {\n const { ctx, viewport, strokes } = this;\n\n // Clear canvas\n ctx.clearRect(0, 0, viewport.width, viewport.height);\n\n // Draw each stroke\n for (const stroke of strokes) {\n // Skip if not started yet\n if (time < stroke.start) {\n continue;\n }\n\n // Calculate progress\n const duration = stroke.end - stroke.start;\n const elapsed = time - stroke.start;\n const progress = duration > 0 ? Math.min(1, elapsed / duration) : 1;\n\n this._drawStroke(stroke, progress);\n }\n }\n\n /**\n * Clear the canvas\n */\n clear() {\n this.ctx.clearRect(0, 0, this.viewport.width, this.viewport.height);\n }\n\n /**\n * Destroy the renderer and release resources\n */\n destroy() {\n this.strokes = [];\n this.ctx = null;\n this.canvas = null;\n this.config = null;\n this.converters = null;\n }\n\n /**\n * Resolve style for an annotation\n *\n * Merges: pen config → type config → annotation.style\n *\n * @private\n * @param {Object} annotation - Annotation object\n * @returns {Object} Resolved style object\n */\n _resolveStyle(annotation) {\n const { type, style: annotationStyle } = annotation;\n\n // Start with pen config (global)\n let resolved = { ...this.config.pen };\n\n // Merge type config\n if (this.config[type]) {\n resolved = deepMerge(resolved, this.config[type]);\n }\n\n // Merge annotation-level style\n if (annotationStyle) {\n resolved = deepMerge(resolved, annotationStyle);\n }\n\n return resolved;\n }\n\n /**\n * Draw a single stroke with progress\n *\n * @private\n * @param {Object} stroke - Stroke command object\n * @param {number} progress - Progress from 0 to 1\n */\n _drawStroke(stroke, progress) {\n const { ctx, viewport } = this;\n const { points, color, width, lineCap, pressures } = stroke;\n\n if (!points || points.length < 2) return;\n\n // Calculate visible point count\n const pointCount = Math.max(2, Math.floor(points.length * progress));\n const visiblePoints = points.slice(0, pointCount);\n\n // Configure stroke style\n ctx.strokeStyle = color || 'rgba(0, 0, 0, 0.5)';\n ctx.lineCap = lineCap || 'round';\n ctx.lineJoin = 'round';\n\n // Draw with variable width if pressures provided\n if (pressures && pressures.length >= visiblePoints.length) {\n this._drawVariableWidthStroke(visiblePoints, width, pressures.slice(0, pointCount));\n } else {\n this._drawConstantWidthStroke(visiblePoints, width);\n }\n }\n\n /**\n * Draw stroke with constant width\n *\n * @private\n * @param {Array} points - Array of [x, y] normalized coordinates\n * @param {number} width - Stroke width in pixels\n */\n _drawConstantWidthStroke(points, width) {\n const { ctx, viewport } = this;\n\n ctx.lineWidth = width || 2;\n ctx.beginPath();\n\n for (let i = 0; i < points.length; i++) {\n const [normX, normY] = points[i];\n const px = normX * viewport.width;\n const py = normY * viewport.height;\n\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n\n ctx.stroke();\n }\n\n /**\n * Draw stroke with variable width based on pressure\n *\n * @private\n * @param {Array} points - Array of [x, y] normalized coordinates\n * @param {number} baseWidth - Base stroke width in pixels\n * @param {Array} pressures - Pressure values (0-1) per point\n */\n _drawVariableWidthStroke(points, baseWidth, pressures) {\n const { ctx, viewport } = this;\n\n for (let i = 1; i < points.length; i++) {\n const [x1, y1] = points[i - 1];\n const [x2, y2] = points[i];\n\n const px1 = x1 * viewport.width;\n const py1 = y1 * viewport.height;\n const px2 = x2 * viewport.width;\n const py2 = y2 * viewport.height;\n\n // Average pressure between two points\n const p1 = pressures[i - 1] || 1;\n const p2 = pressures[i] || 1;\n const avgPressure = (p1 + p2) / 2;\n\n // Apply pressure to width (min 0.5)\n const width = Math.max(0.5, baseWidth * avgPressure);\n\n ctx.lineWidth = width;\n ctx.beginPath();\n ctx.moveTo(px1, py1);\n ctx.lineTo(px2, py2);\n ctx.stroke();\n }\n }\n}\n\nexport { StrokeRenderer };\nexport default StrokeRenderer;\n"],"names":["DEFAULT_CONFIG","StrokeRenderer","canvas","config","deepMerge","highlightToStrokes","textToStrokes","type","converter","width","height","dpr","annotations","page","filtered","a","annotation","style","strokes","time","ctx","viewport","stroke","duration","elapsed","progress","annotationStyle","resolved","points","color","lineCap","pressures","pointCount","visiblePoints","i","normX","normY","px","py","baseWidth","x1","y1","x2","y2","px1","py1","px2","py2","p1","p2","avgPressure"],"mappings":"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"}
1
+ {"version":3,"file":"index5.cjs","sources":["../src/renderer/StrokeRenderer.js"],"sourcesContent":["/**\n * StrokeRenderer - Unified canvas-based annotation renderer\n *\n * Single entry point for rendering annotations as strokes on canvas.\n * Handles conversion from annotations to strokes and progressive rendering.\n *\n * @module renderer/StrokeRenderer\n */\n\nimport { highlightToStrokes, textToStrokes } from '../converters/index.js';\nimport { deepMerge } from '../pen/effects.js';\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG = {\n pen: {\n jitter: { amplitude: 1.0, frequency: 0.08 },\n pressure: { taperIn: 0.15, taperOut: 0.20 },\n wobble: { amplitude: 1.5, frequency: 0.05 }\n },\n highlight: {\n color: 'rgba(255, 255, 0, 0.3)',\n width: 24,\n lineCap: 'butt',\n jitter: { amplitude: 0 }\n },\n text: {\n color: 'rgba(220, 20, 60, 1.0)',\n width: 2,\n fontSize: 16,\n lineCap: 'round',\n jitter: { amplitude: 0 },\n pressure: { taperIn: 0, taperOut: 0 }\n }\n};\n\n/**\n * StrokeRenderer class\n *\n * Converts annotations to strokes and renders them progressively on canvas.\n *\n * @class\n * @example\n * const renderer = new StrokeRenderer(canvas, {\n * highlight: { color: 'rgba(0, 255, 200, 0.4)' }\n * });\n * renderer.setViewport(800, 600);\n * renderer.setAnnotations(annotations);\n * renderer.render(1.5); // Render at t=1.5 seconds\n */\nclass StrokeRenderer {\n /**\n * Create StrokeRenderer instance\n *\n * @param {HTMLCanvasElement} canvas - Canvas element for rendering\n * @param {Object} [config={}] - Configuration overrides\n * @param {Object} [config.pen] - Global pen settings\n * @param {Object} [config.highlight] - Highlight type settings\n * @param {Object} [config.text] - Text type settings\n */\n constructor(canvas, config = {}) {\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error('StrokeRenderer: canvas must be a valid HTMLCanvasElement');\n }\n\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n this.config = deepMerge(DEFAULT_CONFIG, config);\n this.strokes = [];\n this.viewport = { width: 0, height: 0 };\n\n // Register built-in converters\n this.converters = {\n highlight: highlightToStrokes,\n text: textToStrokes\n };\n }\n\n /**\n * Register a custom converter for a new annotation type\n *\n * @param {string} type - Annotation type name\n * @param {Function} converter - Converter function (annotation, style) => strokes[]\n */\n registerConverter(type, converter) {\n if (typeof converter !== 'function') {\n throw new Error('StrokeRenderer.registerConverter: converter must be a function');\n }\n this.converters[type] = converter;\n }\n\n /**\n * Set viewport dimensions and configure canvas\n *\n * Handles high-DPI displays by scaling the canvas buffer.\n *\n * @param {number} width - Viewport width in CSS pixels\n * @param {number} height - Viewport height in CSS pixels\n */\n setViewport(width, height) {\n this.viewport = { width, height };\n\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer size (high-res)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set canvas display size (CSS)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n // Scale context for high-DPI\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Set annotations and convert them to strokes\n *\n * Clears existing strokes and converts all annotations.\n *\n * @param {Array} annotations - Array of annotation objects\n * @param {number} [page] - Optional page filter (only convert annotations for this page)\n */\n setAnnotations(annotations, page = null) {\n if (!Array.isArray(annotations)) {\n console.warn('StrokeRenderer.setAnnotations: annotations must be an array');\n this.strokes = [];\n return;\n }\n\n // Filter by page if specified\n const filtered = page !== null\n ? annotations.filter(a => a.page === page)\n : annotations;\n\n // Convert each annotation to strokes\n this.strokes = filtered.flatMap(annotation => {\n const converter = this.converters[annotation.type];\n\n if (!converter) {\n console.warn(`StrokeRenderer: Unknown annotation type \"${annotation.type}\"`);\n return [];\n }\n\n // Resolve style: pen → type → annotation.style\n const style = this._resolveStyle(annotation);\n\n return converter(annotation, style);\n });\n }\n\n /**\n * Set pre-converted strokes directly\n *\n * Bypasses conversion, useful when strokes come from external source.\n *\n * @param {Array} strokes - Array of stroke command objects\n */\n setStrokes(strokes) {\n if (!Array.isArray(strokes)) {\n console.warn('StrokeRenderer.setStrokes: strokes must be an array');\n this.strokes = [];\n return;\n }\n this.strokes = strokes;\n }\n\n /**\n * Render strokes at the given time\n *\n * Clears canvas and draws all visible strokes with appropriate progress.\n *\n * @param {number} time - Current time in seconds\n */\n render(time) {\n const { ctx, viewport, strokes } = this;\n\n // Clear canvas\n ctx.clearRect(0, 0, viewport.width, viewport.height);\n\n // Draw each stroke\n for (const stroke of strokes) {\n // Skip if not started yet\n if (time < stroke.start) {\n continue;\n }\n\n // Calculate progress\n const duration = stroke.end - stroke.start;\n const elapsed = time - stroke.start;\n const progress = duration > 0 ? Math.min(1, elapsed / duration) : 1;\n\n this._drawStroke(stroke, progress);\n }\n }\n\n /**\n * Clear the canvas\n */\n clear() {\n this.ctx.clearRect(0, 0, this.viewport.width, this.viewport.height);\n }\n\n /**\n * Destroy the renderer and release resources\n */\n destroy() {\n this.strokes = [];\n this.ctx = null;\n this.canvas = null;\n this.config = null;\n this.converters = null;\n }\n\n /**\n * Resolve style for an annotation\n *\n * Merges: pen config → type config → annotation.style\n *\n * @private\n * @param {Object} annotation - Annotation object\n * @returns {Object} Resolved style object\n */\n _resolveStyle(annotation) {\n const { type, style: annotationStyle } = annotation;\n\n // Start with pen config (global)\n let resolved = { ...this.config.pen };\n\n // Merge type config\n if (this.config[type]) {\n resolved = deepMerge(resolved, this.config[type]);\n }\n\n // Merge annotation-level style\n if (annotationStyle) {\n resolved = deepMerge(resolved, annotationStyle);\n }\n\n return resolved;\n }\n\n /**\n * Linearly interpolate between two points\n *\n * @private\n * @param {Array} p1 - Start point [x, y]\n * @param {Array} p2 - End point [x, y]\n * @param {number} t - Interpolation factor (0-1)\n * @returns {Array} Interpolated point [x, y]\n */\n _interpolatePoint(p1, p2, t) {\n return [\n p1[0] + (p2[0] - p1[0]) * t,\n p1[1] + (p2[1] - p1[1]) * t\n ];\n }\n\n /**\n * Get pressure values for visible points including interpolated final\n *\n * @private\n * @param {Array} pressures - Full pressure array\n * @param {number} lastCompleteIndex - Index of last complete point\n * @param {number} segmentProgress - Progress within current segment (0-1)\n * @returns {Array} Pressure values for visible points\n */\n _interpolatePressures(pressures, lastCompleteIndex, segmentProgress) {\n const visiblePressures = pressures.slice(0, lastCompleteIndex + 1);\n\n if (lastCompleteIndex < pressures.length - 1 && segmentProgress > 0) {\n const p1 = pressures[lastCompleteIndex];\n const p2 = pressures[lastCompleteIndex + 1];\n visiblePressures.push(p1 + (p2 - p1) * segmentProgress);\n }\n\n return visiblePressures;\n }\n\n /**\n * Draw a single stroke with progress\n *\n * Uses endpoint interpolation for smooth progressive rendering.\n *\n * @private\n * @param {Object} stroke - Stroke command object\n * @param {number} progress - Progress from 0 to 1\n */\n _drawStroke(stroke, progress) {\n const { ctx } = this;\n const { points, color, width, lineCap, pressures, uniformScale, baseX, baseY } = stroke;\n\n if (!points || points.length < 2) return;\n\n // Configure stroke style\n ctx.strokeStyle = color || 'rgba(0, 0, 0, 0.5)';\n ctx.lineCap = lineCap || 'round';\n ctx.lineJoin = 'round';\n\n // Fast path: full stroke, no interpolation needed\n if (progress >= 1) {\n if (pressures && pressures.length >= points.length) {\n this._drawVariableWidthStroke(points, width, pressures, uniformScale, baseX, baseY);\n } else {\n this._drawConstantWidthStroke(points, width, uniformScale, baseX, baseY);\n }\n return;\n }\n\n // Calculate segment position for interpolation\n const totalSegments = points.length - 1;\n const progressAlongPath = progress * totalSegments;\n const lastCompleteIndex = Math.floor(progressAlongPath);\n const segmentProgress = progressAlongPath - lastCompleteIndex;\n\n // Build visible points array with complete points\n const visiblePoints = points.slice(0, lastCompleteIndex + 1);\n\n // Interpolate final point if mid-segment\n if (lastCompleteIndex < totalSegments && segmentProgress > 0) {\n const p1 = points[lastCompleteIndex];\n const p2 = points[lastCompleteIndex + 1];\n visiblePoints.push(this._interpolatePoint(p1, p2, segmentProgress));\n }\n\n // Need at least 2 points to draw a line\n if (visiblePoints.length < 2) return;\n\n // Draw with variable width if pressures provided\n if (pressures && pressures.length >= points.length) {\n const visiblePressures = this._interpolatePressures(\n pressures, lastCompleteIndex, segmentProgress\n );\n this._drawVariableWidthStroke(visiblePoints, width, visiblePressures, uniformScale, baseX, baseY);\n } else {\n this._drawConstantWidthStroke(visiblePoints, width, uniformScale, baseX, baseY);\n }\n }\n\n /**\n * Draw stroke with constant width\n *\n * @private\n * @param {Array} points - Array of [x, y] coordinates (normalized or offset)\n * @param {number} width - Stroke width in pixels\n * @param {boolean} [uniformScale=false] - Use uniform scaling to preserve aspect ratio\n * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)\n * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)\n */\n _drawConstantWidthStroke(points, width, uniformScale = false, baseX = null, baseY = null) {\n const { ctx, viewport } = this;\n\n ctx.lineWidth = width || 2;\n ctx.beginPath();\n\n // When uniformScale is true and baseX/baseY provided, points are offsets from base position\n // Base position is in mixed coords (X: width-normalized, Y: height-normalized)\n // Offsets are in uniform space (both scaled by viewport.height)\n const hasBasePosition = uniformScale && baseX !== null && baseY !== null;\n\n for (let i = 0; i < points.length; i++) {\n const [coordX, coordY] = points[i];\n let px, py;\n\n if (hasBasePosition) {\n // Base position in pixels + uniform-scaled offset\n px = baseX * viewport.width + coordX * viewport.height;\n py = baseY * viewport.height + coordY * viewport.height;\n } else if (uniformScale) {\n // Legacy: full coordinates in uniform space\n px = coordX * viewport.height;\n py = coordY * viewport.height;\n } else {\n // Standard: X scaled by width, Y by height\n px = coordX * viewport.width;\n py = coordY * viewport.height;\n }\n\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n\n ctx.stroke();\n }\n\n /**\n * Draw stroke with variable width based on pressure\n *\n * @private\n * @param {Array} points - Array of [x, y] coordinates (normalized or offset)\n * @param {number} baseWidth - Base stroke width in pixels\n * @param {Array} pressures - Pressure values (0-1) per point\n * @param {boolean} [uniformScale=false] - Use uniform scaling to preserve aspect ratio\n * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)\n * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)\n */\n _drawVariableWidthStroke(points, baseWidth, pressures, uniformScale = false, baseX = null, baseY = null) {\n const { ctx, viewport } = this;\n\n // When uniformScale is true and baseX/baseY provided, points are offsets from base position\n const hasBasePosition = uniformScale && baseX !== null && baseY !== null;\n\n for (let i = 1; i < points.length; i++) {\n const [c1x, c1y] = points[i - 1];\n const [c2x, c2y] = points[i];\n\n let px1, py1, px2, py2;\n\n if (hasBasePosition) {\n // Base position in pixels + uniform-scaled offset\n px1 = baseX * viewport.width + c1x * viewport.height;\n py1 = baseY * viewport.height + c1y * viewport.height;\n px2 = baseX * viewport.width + c2x * viewport.height;\n py2 = baseY * viewport.height + c2y * viewport.height;\n } else if (uniformScale) {\n // Legacy: full coordinates in uniform space\n px1 = c1x * viewport.height;\n py1 = c1y * viewport.height;\n px2 = c2x * viewport.height;\n py2 = c2y * viewport.height;\n } else {\n // Standard: X scaled by width, Y by height\n px1 = c1x * viewport.width;\n py1 = c1y * viewport.height;\n px2 = c2x * viewport.width;\n py2 = c2y * viewport.height;\n }\n\n // Average pressure between two points\n const p1 = pressures[i - 1] || 1;\n const p2 = pressures[i] || 1;\n const avgPressure = (p1 + p2) / 2;\n\n // Apply pressure to width (min 0.5)\n const width = Math.max(0.5, baseWidth * avgPressure);\n\n ctx.lineWidth = width;\n ctx.beginPath();\n ctx.moveTo(px1, py1);\n ctx.lineTo(px2, py2);\n ctx.stroke();\n }\n }\n}\n\nexport { StrokeRenderer };\nexport default StrokeRenderer;\n"],"names":["DEFAULT_CONFIG","StrokeRenderer","canvas","config","deepMerge","highlightToStrokes","textToStrokes","type","converter","width","height","dpr","annotations","page","filtered","a","annotation","style","strokes","time","ctx","viewport","stroke","duration","elapsed","progress","annotationStyle","resolved","p1","p2","t","pressures","lastCompleteIndex","segmentProgress","visiblePressures","points","color","lineCap","uniformScale","baseX","baseY","totalSegments","progressAlongPath","visiblePoints","hasBasePosition","i","coordX","coordY","px","py","baseWidth","c1x","c1y","c2x","c2y","px1","py1","px2","py2","avgPressure"],"mappings":"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"}
package/dist/index5.js CHANGED
@@ -1,7 +1,7 @@
1
- import { deepMerge as d } from "./index6.js";
2
- import { textToStrokes as y } from "./index14.js";
3
- import { highlightToStrokes as x } from "./index13.js";
4
- const m = {
1
+ import { deepMerge as k } from "./index6.js";
2
+ import { textToStrokes as _ } from "./index14.js";
3
+ import { highlightToStrokes as b } from "./index13.js";
4
+ const P = {
5
5
  pen: {
6
6
  jitter: { amplitude: 1, frequency: 0.08 },
7
7
  pressure: { taperIn: 0.15, taperOut: 0.2 },
@@ -17,10 +17,12 @@ const m = {
17
17
  color: "rgba(220, 20, 60, 1.0)",
18
18
  width: 2,
19
19
  fontSize: 16,
20
- lineCap: "round"
20
+ lineCap: "round",
21
+ jitter: { amplitude: 0 },
22
+ pressure: { taperIn: 0, taperOut: 0 }
21
23
  }
22
24
  };
23
- class R {
25
+ class W {
24
26
  /**
25
27
  * Create StrokeRenderer instance
26
28
  *
@@ -30,12 +32,12 @@ class R {
30
32
  * @param {Object} [config.highlight] - Highlight type settings
31
33
  * @param {Object} [config.text] - Text type settings
32
34
  */
33
- constructor(t, o = {}) {
35
+ constructor(t, r = {}) {
34
36
  if (!t || !(t instanceof HTMLCanvasElement))
35
37
  throw new Error("StrokeRenderer: canvas must be a valid HTMLCanvasElement");
36
- this.canvas = t, this.ctx = t.getContext("2d"), this.config = d(m, o), this.strokes = [], this.viewport = { width: 0, height: 0 }, this.converters = {
37
- highlight: x,
38
- text: y
38
+ this.canvas = t, this.ctx = t.getContext("2d"), this.config = k(P, r), this.strokes = [], this.viewport = { width: 0, height: 0 }, this.converters = {
39
+ highlight: b,
40
+ text: _
39
41
  };
40
42
  }
41
43
  /**
@@ -44,10 +46,10 @@ class R {
44
46
  * @param {string} type - Annotation type name
45
47
  * @param {Function} converter - Converter function (annotation, style) => strokes[]
46
48
  */
47
- registerConverter(t, o) {
48
- if (typeof o != "function")
49
+ registerConverter(t, r) {
50
+ if (typeof r != "function")
49
51
  throw new Error("StrokeRenderer.registerConverter: converter must be a function");
50
- this.converters[t] = o;
52
+ this.converters[t] = r;
51
53
  }
52
54
  /**
53
55
  * Set viewport dimensions and configure canvas
@@ -57,10 +59,10 @@ class R {
57
59
  * @param {number} width - Viewport width in CSS pixels
58
60
  * @param {number} height - Viewport height in CSS pixels
59
61
  */
60
- setViewport(t, o) {
61
- this.viewport = { width: t, height: o };
62
- const e = window.devicePixelRatio || 1;
63
- this.canvas.width = t * e, this.canvas.height = o * e, this.canvas.style.width = `${t}px`, this.canvas.style.height = `${o}px`, this.ctx.setTransform(e, 0, 0, e, 0, 0);
62
+ setViewport(t, r) {
63
+ this.viewport = { width: t, height: r };
64
+ const i = window.devicePixelRatio || 1;
65
+ this.canvas.width = t * i, this.canvas.height = r * i, this.canvas.style.width = `${t}px`, this.canvas.style.height = `${r}px`, this.ctx.setTransform(i, 0, 0, i, 0, 0);
64
66
  }
65
67
  /**
66
68
  * Set annotations and convert them to strokes
@@ -70,18 +72,18 @@ class R {
70
72
  * @param {Array} annotations - Array of annotation objects
71
73
  * @param {number} [page] - Optional page filter (only convert annotations for this page)
72
74
  */
73
- setAnnotations(t, o = null) {
75
+ setAnnotations(t, r = null) {
74
76
  if (!Array.isArray(t)) {
75
77
  console.warn("StrokeRenderer.setAnnotations: annotations must be an array"), this.strokes = [];
76
78
  return;
77
79
  }
78
- const e = o !== null ? t.filter((r) => r.page === o) : t;
79
- this.strokes = e.flatMap((r) => {
80
- const s = this.converters[r.type];
81
- if (!s)
82
- return console.warn(`StrokeRenderer: Unknown annotation type "${r.type}"`), [];
83
- const i = this._resolveStyle(r);
84
- return s(r, i);
80
+ const i = r !== null ? t.filter((e) => e.page === r) : t;
81
+ this.strokes = i.flatMap((e) => {
82
+ const n = this.converters[e.type];
83
+ if (!n)
84
+ return console.warn(`StrokeRenderer: Unknown annotation type "${e.type}"`), [];
85
+ const o = this._resolveStyle(e);
86
+ return n(e, o);
85
87
  });
86
88
  }
87
89
  /**
@@ -106,13 +108,13 @@ class R {
106
108
  * @param {number} time - Current time in seconds
107
109
  */
108
110
  render(t) {
109
- const { ctx: o, viewport: e, strokes: r } = this;
110
- o.clearRect(0, 0, e.width, e.height);
111
- for (const s of r) {
112
- if (t < s.start)
111
+ const { ctx: r, viewport: i, strokes: e } = this;
112
+ r.clearRect(0, 0, i.width, i.height);
113
+ for (const n of e) {
114
+ if (t < n.start)
113
115
  continue;
114
- const i = s.end - s.start, n = t - s.start, h = i > 0 ? Math.min(1, n / i) : 1;
115
- this._drawStroke(s, h);
116
+ const o = n.end - n.start, h = t - n.start, s = o > 0 ? Math.min(1, h / o) : 1;
117
+ this._drawStroke(n, s);
116
118
  }
117
119
  }
118
120
  /**
@@ -137,57 +139,119 @@ class R {
137
139
  * @returns {Object} Resolved style object
138
140
  */
139
141
  _resolveStyle(t) {
140
- const { type: o, style: e } = t;
141
- let r = { ...this.config.pen };
142
- return this.config[o] && (r = d(r, this.config[o])), e && (r = d(r, e)), r;
142
+ const { type: r, style: i } = t;
143
+ let e = { ...this.config.pen };
144
+ return this.config[r] && (e = k(e, this.config[r])), i && (e = k(e, i)), e;
145
+ }
146
+ /**
147
+ * Linearly interpolate between two points
148
+ *
149
+ * @private
150
+ * @param {Array} p1 - Start point [x, y]
151
+ * @param {Array} p2 - End point [x, y]
152
+ * @param {number} t - Interpolation factor (0-1)
153
+ * @returns {Array} Interpolated point [x, y]
154
+ */
155
+ _interpolatePoint(t, r, i) {
156
+ return [
157
+ t[0] + (r[0] - t[0]) * i,
158
+ t[1] + (r[1] - t[1]) * i
159
+ ];
160
+ }
161
+ /**
162
+ * Get pressure values for visible points including interpolated final
163
+ *
164
+ * @private
165
+ * @param {Array} pressures - Full pressure array
166
+ * @param {number} lastCompleteIndex - Index of last complete point
167
+ * @param {number} segmentProgress - Progress within current segment (0-1)
168
+ * @returns {Array} Pressure values for visible points
169
+ */
170
+ _interpolatePressures(t, r, i) {
171
+ const e = t.slice(0, r + 1);
172
+ if (r < t.length - 1 && i > 0) {
173
+ const n = t[r], o = t[r + 1];
174
+ e.push(n + (o - n) * i);
175
+ }
176
+ return e;
143
177
  }
144
178
  /**
145
179
  * Draw a single stroke with progress
146
180
  *
181
+ * Uses endpoint interpolation for smooth progressive rendering.
182
+ *
147
183
  * @private
148
184
  * @param {Object} stroke - Stroke command object
149
185
  * @param {number} progress - Progress from 0 to 1
150
186
  */
151
- _drawStroke(t, o) {
152
- const { ctx: e, viewport: r } = this, { points: s, color: i, width: n, lineCap: h, pressures: a } = t;
153
- if (!s || s.length < 2) return;
154
- const l = Math.max(2, Math.floor(s.length * o)), c = s.slice(0, l);
155
- e.strokeStyle = i || "rgba(0, 0, 0, 0.5)", e.lineCap = h || "round", e.lineJoin = "round", a && a.length >= c.length ? this._drawVariableWidthStroke(c, n, a.slice(0, l)) : this._drawConstantWidthStroke(c, n);
187
+ _drawStroke(t, r) {
188
+ const { ctx: i } = this, { points: e, color: n, width: o, lineCap: h, pressures: s, uniformScale: g, baseX: l, baseY: a } = t;
189
+ if (!e || e.length < 2) return;
190
+ if (i.strokeStyle = n || "rgba(0, 0, 0, 0.5)", i.lineCap = h || "round", i.lineJoin = "round", r >= 1) {
191
+ s && s.length >= e.length ? this._drawVariableWidthStroke(e, o, s, g, l, a) : this._drawConstantWidthStroke(e, o, g, l, a);
192
+ return;
193
+ }
194
+ const c = e.length - 1, d = r * c, u = Math.floor(d), f = d - u, p = e.slice(0, u + 1);
195
+ if (u < c && f > 0) {
196
+ const w = e[u], v = e[u + 1];
197
+ p.push(this._interpolatePoint(w, v, f));
198
+ }
199
+ if (!(p.length < 2))
200
+ if (s && s.length >= e.length) {
201
+ const w = this._interpolatePressures(
202
+ s,
203
+ u,
204
+ f
205
+ );
206
+ this._drawVariableWidthStroke(p, o, w, g, l, a);
207
+ } else
208
+ this._drawConstantWidthStroke(p, o, g, l, a);
156
209
  }
157
210
  /**
158
211
  * Draw stroke with constant width
159
212
  *
160
213
  * @private
161
- * @param {Array} points - Array of [x, y] normalized coordinates
214
+ * @param {Array} points - Array of [x, y] coordinates (normalized or offset)
162
215
  * @param {number} width - Stroke width in pixels
216
+ * @param {boolean} [uniformScale=false] - Use uniform scaling to preserve aspect ratio
217
+ * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)
218
+ * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)
163
219
  */
164
- _drawConstantWidthStroke(t, o) {
165
- const { ctx: e, viewport: r } = this;
166
- e.lineWidth = o || 2, e.beginPath();
167
- for (let s = 0; s < t.length; s++) {
168
- const [i, n] = t[s], h = i * r.width, a = n * r.height;
169
- s === 0 ? e.moveTo(h, a) : e.lineTo(h, a);
220
+ _drawConstantWidthStroke(t, r, i = !1, e = null, n = null) {
221
+ const { ctx: o, viewport: h } = this;
222
+ o.lineWidth = r || 2, o.beginPath();
223
+ const s = i && e !== null && n !== null;
224
+ for (let g = 0; g < t.length; g++) {
225
+ const [l, a] = t[g];
226
+ let c, d;
227
+ s ? (c = e * h.width + l * h.height, d = n * h.height + a * h.height) : i ? (c = l * h.height, d = a * h.height) : (c = l * h.width, d = a * h.height), g === 0 ? o.moveTo(c, d) : o.lineTo(c, d);
170
228
  }
171
- e.stroke();
229
+ o.stroke();
172
230
  }
173
231
  /**
174
232
  * Draw stroke with variable width based on pressure
175
233
  *
176
234
  * @private
177
- * @param {Array} points - Array of [x, y] normalized coordinates
235
+ * @param {Array} points - Array of [x, y] coordinates (normalized or offset)
178
236
  * @param {number} baseWidth - Base stroke width in pixels
179
237
  * @param {Array} pressures - Pressure values (0-1) per point
238
+ * @param {boolean} [uniformScale=false] - Use uniform scaling to preserve aspect ratio
239
+ * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)
240
+ * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)
180
241
  */
181
- _drawVariableWidthStroke(t, o, e) {
182
- const { ctx: r, viewport: s } = this;
183
- for (let i = 1; i < t.length; i++) {
184
- const [n, h] = t[i - 1], [a, l] = t[i], c = n * s.width, p = h * s.height, f = a * s.width, w = l * s.height, u = e[i - 1] || 1, g = e[i] || 1, v = (u + g) / 2, k = Math.max(0.5, o * v);
185
- r.lineWidth = k, r.beginPath(), r.moveTo(c, p), r.lineTo(f, w), r.stroke();
242
+ _drawVariableWidthStroke(t, r, i, e = !1, n = null, o = null) {
243
+ const { ctx: h, viewport: s } = this, g = e && n !== null && o !== null;
244
+ for (let l = 1; l < t.length; l++) {
245
+ const [a, c] = t[l - 1], [d, u] = t[l];
246
+ let f, p, w, v;
247
+ g ? (f = n * s.width + a * s.height, p = o * s.height + c * s.height, w = n * s.width + d * s.height, v = o * s.height + u * s.height) : e ? (f = a * s.height, p = c * s.height, w = d * s.height, v = u * s.height) : (f = a * s.width, p = c * s.height, w = d * s.width, v = u * s.height);
248
+ const y = i[l - 1] || 1, S = i[l] || 1, x = (y + S) / 2, m = Math.max(0.5, r * x);
249
+ h.lineWidth = m, h.beginPath(), h.moveTo(f, p), h.lineTo(w, v), h.stroke();
186
250
  }
187
251
  }
188
252
  }
189
253
  export {
190
- R as StrokeRenderer,
191
- R as default
254
+ W as StrokeRenderer,
255
+ W as default
192
256
  };
193
257
  //# sourceMappingURL=index5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index5.js","sources":["../src/renderer/StrokeRenderer.js"],"sourcesContent":["/**\n * StrokeRenderer - Unified canvas-based annotation renderer\n *\n * Single entry point for rendering annotations as strokes on canvas.\n * Handles conversion from annotations to strokes and progressive rendering.\n *\n * @module renderer/StrokeRenderer\n */\n\nimport { highlightToStrokes, textToStrokes } from '../converters/index.js';\nimport { deepMerge } from '../pen/effects.js';\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG = {\n pen: {\n jitter: { amplitude: 1.0, frequency: 0.08 },\n pressure: { taperIn: 0.15, taperOut: 0.20 },\n wobble: { amplitude: 1.5, frequency: 0.05 }\n },\n highlight: {\n color: 'rgba(255, 255, 0, 0.3)',\n width: 24,\n lineCap: 'butt',\n jitter: { amplitude: 0 }\n },\n text: {\n color: 'rgba(220, 20, 60, 1.0)',\n width: 2,\n fontSize: 16,\n lineCap: 'round'\n }\n};\n\n/**\n * StrokeRenderer class\n *\n * Converts annotations to strokes and renders them progressively on canvas.\n *\n * @class\n * @example\n * const renderer = new StrokeRenderer(canvas, {\n * highlight: { color: 'rgba(0, 255, 200, 0.4)' }\n * });\n * renderer.setViewport(800, 600);\n * renderer.setAnnotations(annotations);\n * renderer.render(1.5); // Render at t=1.5 seconds\n */\nclass StrokeRenderer {\n /**\n * Create StrokeRenderer instance\n *\n * @param {HTMLCanvasElement} canvas - Canvas element for rendering\n * @param {Object} [config={}] - Configuration overrides\n * @param {Object} [config.pen] - Global pen settings\n * @param {Object} [config.highlight] - Highlight type settings\n * @param {Object} [config.text] - Text type settings\n */\n constructor(canvas, config = {}) {\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error('StrokeRenderer: canvas must be a valid HTMLCanvasElement');\n }\n\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n this.config = deepMerge(DEFAULT_CONFIG, config);\n this.strokes = [];\n this.viewport = { width: 0, height: 0 };\n\n // Register built-in converters\n this.converters = {\n highlight: highlightToStrokes,\n text: textToStrokes\n };\n }\n\n /**\n * Register a custom converter for a new annotation type\n *\n * @param {string} type - Annotation type name\n * @param {Function} converter - Converter function (annotation, style) => strokes[]\n */\n registerConverter(type, converter) {\n if (typeof converter !== 'function') {\n throw new Error('StrokeRenderer.registerConverter: converter must be a function');\n }\n this.converters[type] = converter;\n }\n\n /**\n * Set viewport dimensions and configure canvas\n *\n * Handles high-DPI displays by scaling the canvas buffer.\n *\n * @param {number} width - Viewport width in CSS pixels\n * @param {number} height - Viewport height in CSS pixels\n */\n setViewport(width, height) {\n this.viewport = { width, height };\n\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer size (high-res)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set canvas display size (CSS)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n // Scale context for high-DPI\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Set annotations and convert them to strokes\n *\n * Clears existing strokes and converts all annotations.\n *\n * @param {Array} annotations - Array of annotation objects\n * @param {number} [page] - Optional page filter (only convert annotations for this page)\n */\n setAnnotations(annotations, page = null) {\n if (!Array.isArray(annotations)) {\n console.warn('StrokeRenderer.setAnnotations: annotations must be an array');\n this.strokes = [];\n return;\n }\n\n // Filter by page if specified\n const filtered = page !== null\n ? annotations.filter(a => a.page === page)\n : annotations;\n\n // Convert each annotation to strokes\n this.strokes = filtered.flatMap(annotation => {\n const converter = this.converters[annotation.type];\n\n if (!converter) {\n console.warn(`StrokeRenderer: Unknown annotation type \"${annotation.type}\"`);\n return [];\n }\n\n // Resolve style: pen → type → annotation.style\n const style = this._resolveStyle(annotation);\n\n return converter(annotation, style);\n });\n }\n\n /**\n * Set pre-converted strokes directly\n *\n * Bypasses conversion, useful when strokes come from external source.\n *\n * @param {Array} strokes - Array of stroke command objects\n */\n setStrokes(strokes) {\n if (!Array.isArray(strokes)) {\n console.warn('StrokeRenderer.setStrokes: strokes must be an array');\n this.strokes = [];\n return;\n }\n this.strokes = strokes;\n }\n\n /**\n * Render strokes at the given time\n *\n * Clears canvas and draws all visible strokes with appropriate progress.\n *\n * @param {number} time - Current time in seconds\n */\n render(time) {\n const { ctx, viewport, strokes } = this;\n\n // Clear canvas\n ctx.clearRect(0, 0, viewport.width, viewport.height);\n\n // Draw each stroke\n for (const stroke of strokes) {\n // Skip if not started yet\n if (time < stroke.start) {\n continue;\n }\n\n // Calculate progress\n const duration = stroke.end - stroke.start;\n const elapsed = time - stroke.start;\n const progress = duration > 0 ? Math.min(1, elapsed / duration) : 1;\n\n this._drawStroke(stroke, progress);\n }\n }\n\n /**\n * Clear the canvas\n */\n clear() {\n this.ctx.clearRect(0, 0, this.viewport.width, this.viewport.height);\n }\n\n /**\n * Destroy the renderer and release resources\n */\n destroy() {\n this.strokes = [];\n this.ctx = null;\n this.canvas = null;\n this.config = null;\n this.converters = null;\n }\n\n /**\n * Resolve style for an annotation\n *\n * Merges: pen config → type config → annotation.style\n *\n * @private\n * @param {Object} annotation - Annotation object\n * @returns {Object} Resolved style object\n */\n _resolveStyle(annotation) {\n const { type, style: annotationStyle } = annotation;\n\n // Start with pen config (global)\n let resolved = { ...this.config.pen };\n\n // Merge type config\n if (this.config[type]) {\n resolved = deepMerge(resolved, this.config[type]);\n }\n\n // Merge annotation-level style\n if (annotationStyle) {\n resolved = deepMerge(resolved, annotationStyle);\n }\n\n return resolved;\n }\n\n /**\n * Draw a single stroke with progress\n *\n * @private\n * @param {Object} stroke - Stroke command object\n * @param {number} progress - Progress from 0 to 1\n */\n _drawStroke(stroke, progress) {\n const { ctx, viewport } = this;\n const { points, color, width, lineCap, pressures } = stroke;\n\n if (!points || points.length < 2) return;\n\n // Calculate visible point count\n const pointCount = Math.max(2, Math.floor(points.length * progress));\n const visiblePoints = points.slice(0, pointCount);\n\n // Configure stroke style\n ctx.strokeStyle = color || 'rgba(0, 0, 0, 0.5)';\n ctx.lineCap = lineCap || 'round';\n ctx.lineJoin = 'round';\n\n // Draw with variable width if pressures provided\n if (pressures && pressures.length >= visiblePoints.length) {\n this._drawVariableWidthStroke(visiblePoints, width, pressures.slice(0, pointCount));\n } else {\n this._drawConstantWidthStroke(visiblePoints, width);\n }\n }\n\n /**\n * Draw stroke with constant width\n *\n * @private\n * @param {Array} points - Array of [x, y] normalized coordinates\n * @param {number} width - Stroke width in pixels\n */\n _drawConstantWidthStroke(points, width) {\n const { ctx, viewport } = this;\n\n ctx.lineWidth = width || 2;\n ctx.beginPath();\n\n for (let i = 0; i < points.length; i++) {\n const [normX, normY] = points[i];\n const px = normX * viewport.width;\n const py = normY * viewport.height;\n\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n\n ctx.stroke();\n }\n\n /**\n * Draw stroke with variable width based on pressure\n *\n * @private\n * @param {Array} points - Array of [x, y] normalized coordinates\n * @param {number} baseWidth - Base stroke width in pixels\n * @param {Array} pressures - Pressure values (0-1) per point\n */\n _drawVariableWidthStroke(points, baseWidth, pressures) {\n const { ctx, viewport } = this;\n\n for (let i = 1; i < points.length; i++) {\n const [x1, y1] = points[i - 1];\n const [x2, y2] = points[i];\n\n const px1 = x1 * viewport.width;\n const py1 = y1 * viewport.height;\n const px2 = x2 * viewport.width;\n const py2 = y2 * viewport.height;\n\n // Average pressure between two points\n const p1 = pressures[i - 1] || 1;\n const p2 = pressures[i] || 1;\n const avgPressure = (p1 + p2) / 2;\n\n // Apply pressure to width (min 0.5)\n const width = Math.max(0.5, baseWidth * avgPressure);\n\n ctx.lineWidth = width;\n ctx.beginPath();\n ctx.moveTo(px1, py1);\n ctx.lineTo(px2, py2);\n ctx.stroke();\n }\n }\n}\n\nexport { StrokeRenderer };\nexport default StrokeRenderer;\n"],"names":["DEFAULT_CONFIG","StrokeRenderer","canvas","config","deepMerge","highlightToStrokes","textToStrokes","type","converter","width","height","dpr","annotations","page","filtered","a","annotation","style","strokes","time","ctx","viewport","stroke","duration","elapsed","progress","annotationStyle","resolved","points","color","lineCap","pressures","pointCount","visiblePoints","i","normX","normY","px","py","baseWidth","x1","y1","x2","y2","px1","py1","px2","py2","p1","p2","avgPressure"],"mappings":"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"}
1
+ {"version":3,"file":"index5.js","sources":["../src/renderer/StrokeRenderer.js"],"sourcesContent":["/**\n * StrokeRenderer - Unified canvas-based annotation renderer\n *\n * Single entry point for rendering annotations as strokes on canvas.\n * Handles conversion from annotations to strokes and progressive rendering.\n *\n * @module renderer/StrokeRenderer\n */\n\nimport { highlightToStrokes, textToStrokes } from '../converters/index.js';\nimport { deepMerge } from '../pen/effects.js';\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG = {\n pen: {\n jitter: { amplitude: 1.0, frequency: 0.08 },\n pressure: { taperIn: 0.15, taperOut: 0.20 },\n wobble: { amplitude: 1.5, frequency: 0.05 }\n },\n highlight: {\n color: 'rgba(255, 255, 0, 0.3)',\n width: 24,\n lineCap: 'butt',\n jitter: { amplitude: 0 }\n },\n text: {\n color: 'rgba(220, 20, 60, 1.0)',\n width: 2,\n fontSize: 16,\n lineCap: 'round',\n jitter: { amplitude: 0 },\n pressure: { taperIn: 0, taperOut: 0 }\n }\n};\n\n/**\n * StrokeRenderer class\n *\n * Converts annotations to strokes and renders them progressively on canvas.\n *\n * @class\n * @example\n * const renderer = new StrokeRenderer(canvas, {\n * highlight: { color: 'rgba(0, 255, 200, 0.4)' }\n * });\n * renderer.setViewport(800, 600);\n * renderer.setAnnotations(annotations);\n * renderer.render(1.5); // Render at t=1.5 seconds\n */\nclass StrokeRenderer {\n /**\n * Create StrokeRenderer instance\n *\n * @param {HTMLCanvasElement} canvas - Canvas element for rendering\n * @param {Object} [config={}] - Configuration overrides\n * @param {Object} [config.pen] - Global pen settings\n * @param {Object} [config.highlight] - Highlight type settings\n * @param {Object} [config.text] - Text type settings\n */\n constructor(canvas, config = {}) {\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error('StrokeRenderer: canvas must be a valid HTMLCanvasElement');\n }\n\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n this.config = deepMerge(DEFAULT_CONFIG, config);\n this.strokes = [];\n this.viewport = { width: 0, height: 0 };\n\n // Register built-in converters\n this.converters = {\n highlight: highlightToStrokes,\n text: textToStrokes\n };\n }\n\n /**\n * Register a custom converter for a new annotation type\n *\n * @param {string} type - Annotation type name\n * @param {Function} converter - Converter function (annotation, style) => strokes[]\n */\n registerConverter(type, converter) {\n if (typeof converter !== 'function') {\n throw new Error('StrokeRenderer.registerConverter: converter must be a function');\n }\n this.converters[type] = converter;\n }\n\n /**\n * Set viewport dimensions and configure canvas\n *\n * Handles high-DPI displays by scaling the canvas buffer.\n *\n * @param {number} width - Viewport width in CSS pixels\n * @param {number} height - Viewport height in CSS pixels\n */\n setViewport(width, height) {\n this.viewport = { width, height };\n\n const dpr = window.devicePixelRatio || 1;\n\n // Set canvas buffer size (high-res)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set canvas display size (CSS)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n // Scale context for high-DPI\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n /**\n * Set annotations and convert them to strokes\n *\n * Clears existing strokes and converts all annotations.\n *\n * @param {Array} annotations - Array of annotation objects\n * @param {number} [page] - Optional page filter (only convert annotations for this page)\n */\n setAnnotations(annotations, page = null) {\n if (!Array.isArray(annotations)) {\n console.warn('StrokeRenderer.setAnnotations: annotations must be an array');\n this.strokes = [];\n return;\n }\n\n // Filter by page if specified\n const filtered = page !== null\n ? annotations.filter(a => a.page === page)\n : annotations;\n\n // Convert each annotation to strokes\n this.strokes = filtered.flatMap(annotation => {\n const converter = this.converters[annotation.type];\n\n if (!converter) {\n console.warn(`StrokeRenderer: Unknown annotation type \"${annotation.type}\"`);\n return [];\n }\n\n // Resolve style: pen → type → annotation.style\n const style = this._resolveStyle(annotation);\n\n return converter(annotation, style);\n });\n }\n\n /**\n * Set pre-converted strokes directly\n *\n * Bypasses conversion, useful when strokes come from external source.\n *\n * @param {Array} strokes - Array of stroke command objects\n */\n setStrokes(strokes) {\n if (!Array.isArray(strokes)) {\n console.warn('StrokeRenderer.setStrokes: strokes must be an array');\n this.strokes = [];\n return;\n }\n this.strokes = strokes;\n }\n\n /**\n * Render strokes at the given time\n *\n * Clears canvas and draws all visible strokes with appropriate progress.\n *\n * @param {number} time - Current time in seconds\n */\n render(time) {\n const { ctx, viewport, strokes } = this;\n\n // Clear canvas\n ctx.clearRect(0, 0, viewport.width, viewport.height);\n\n // Draw each stroke\n for (const stroke of strokes) {\n // Skip if not started yet\n if (time < stroke.start) {\n continue;\n }\n\n // Calculate progress\n const duration = stroke.end - stroke.start;\n const elapsed = time - stroke.start;\n const progress = duration > 0 ? Math.min(1, elapsed / duration) : 1;\n\n this._drawStroke(stroke, progress);\n }\n }\n\n /**\n * Clear the canvas\n */\n clear() {\n this.ctx.clearRect(0, 0, this.viewport.width, this.viewport.height);\n }\n\n /**\n * Destroy the renderer and release resources\n */\n destroy() {\n this.strokes = [];\n this.ctx = null;\n this.canvas = null;\n this.config = null;\n this.converters = null;\n }\n\n /**\n * Resolve style for an annotation\n *\n * Merges: pen config → type config → annotation.style\n *\n * @private\n * @param {Object} annotation - Annotation object\n * @returns {Object} Resolved style object\n */\n _resolveStyle(annotation) {\n const { type, style: annotationStyle } = annotation;\n\n // Start with pen config (global)\n let resolved = { ...this.config.pen };\n\n // Merge type config\n if (this.config[type]) {\n resolved = deepMerge(resolved, this.config[type]);\n }\n\n // Merge annotation-level style\n if (annotationStyle) {\n resolved = deepMerge(resolved, annotationStyle);\n }\n\n return resolved;\n }\n\n /**\n * Linearly interpolate between two points\n *\n * @private\n * @param {Array} p1 - Start point [x, y]\n * @param {Array} p2 - End point [x, y]\n * @param {number} t - Interpolation factor (0-1)\n * @returns {Array} Interpolated point [x, y]\n */\n _interpolatePoint(p1, p2, t) {\n return [\n p1[0] + (p2[0] - p1[0]) * t,\n p1[1] + (p2[1] - p1[1]) * t\n ];\n }\n\n /**\n * Get pressure values for visible points including interpolated final\n *\n * @private\n * @param {Array} pressures - Full pressure array\n * @param {number} lastCompleteIndex - Index of last complete point\n * @param {number} segmentProgress - Progress within current segment (0-1)\n * @returns {Array} Pressure values for visible points\n */\n _interpolatePressures(pressures, lastCompleteIndex, segmentProgress) {\n const visiblePressures = pressures.slice(0, lastCompleteIndex + 1);\n\n if (lastCompleteIndex < pressures.length - 1 && segmentProgress > 0) {\n const p1 = pressures[lastCompleteIndex];\n const p2 = pressures[lastCompleteIndex + 1];\n visiblePressures.push(p1 + (p2 - p1) * segmentProgress);\n }\n\n return visiblePressures;\n }\n\n /**\n * Draw a single stroke with progress\n *\n * Uses endpoint interpolation for smooth progressive rendering.\n *\n * @private\n * @param {Object} stroke - Stroke command object\n * @param {number} progress - Progress from 0 to 1\n */\n _drawStroke(stroke, progress) {\n const { ctx } = this;\n const { points, color, width, lineCap, pressures, uniformScale, baseX, baseY } = stroke;\n\n if (!points || points.length < 2) return;\n\n // Configure stroke style\n ctx.strokeStyle = color || 'rgba(0, 0, 0, 0.5)';\n ctx.lineCap = lineCap || 'round';\n ctx.lineJoin = 'round';\n\n // Fast path: full stroke, no interpolation needed\n if (progress >= 1) {\n if (pressures && pressures.length >= points.length) {\n this._drawVariableWidthStroke(points, width, pressures, uniformScale, baseX, baseY);\n } else {\n this._drawConstantWidthStroke(points, width, uniformScale, baseX, baseY);\n }\n return;\n }\n\n // Calculate segment position for interpolation\n const totalSegments = points.length - 1;\n const progressAlongPath = progress * totalSegments;\n const lastCompleteIndex = Math.floor(progressAlongPath);\n const segmentProgress = progressAlongPath - lastCompleteIndex;\n\n // Build visible points array with complete points\n const visiblePoints = points.slice(0, lastCompleteIndex + 1);\n\n // Interpolate final point if mid-segment\n if (lastCompleteIndex < totalSegments && segmentProgress > 0) {\n const p1 = points[lastCompleteIndex];\n const p2 = points[lastCompleteIndex + 1];\n visiblePoints.push(this._interpolatePoint(p1, p2, segmentProgress));\n }\n\n // Need at least 2 points to draw a line\n if (visiblePoints.length < 2) return;\n\n // Draw with variable width if pressures provided\n if (pressures && pressures.length >= points.length) {\n const visiblePressures = this._interpolatePressures(\n pressures, lastCompleteIndex, segmentProgress\n );\n this._drawVariableWidthStroke(visiblePoints, width, visiblePressures, uniformScale, baseX, baseY);\n } else {\n this._drawConstantWidthStroke(visiblePoints, width, uniformScale, baseX, baseY);\n }\n }\n\n /**\n * Draw stroke with constant width\n *\n * @private\n * @param {Array} points - Array of [x, y] coordinates (normalized or offset)\n * @param {number} width - Stroke width in pixels\n * @param {boolean} [uniformScale=false] - Use uniform scaling to preserve aspect ratio\n * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)\n * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)\n */\n _drawConstantWidthStroke(points, width, uniformScale = false, baseX = null, baseY = null) {\n const { ctx, viewport } = this;\n\n ctx.lineWidth = width || 2;\n ctx.beginPath();\n\n // When uniformScale is true and baseX/baseY provided, points are offsets from base position\n // Base position is in mixed coords (X: width-normalized, Y: height-normalized)\n // Offsets are in uniform space (both scaled by viewport.height)\n const hasBasePosition = uniformScale && baseX !== null && baseY !== null;\n\n for (let i = 0; i < points.length; i++) {\n const [coordX, coordY] = points[i];\n let px, py;\n\n if (hasBasePosition) {\n // Base position in pixels + uniform-scaled offset\n px = baseX * viewport.width + coordX * viewport.height;\n py = baseY * viewport.height + coordY * viewport.height;\n } else if (uniformScale) {\n // Legacy: full coordinates in uniform space\n px = coordX * viewport.height;\n py = coordY * viewport.height;\n } else {\n // Standard: X scaled by width, Y by height\n px = coordX * viewport.width;\n py = coordY * viewport.height;\n }\n\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n\n ctx.stroke();\n }\n\n /**\n * Draw stroke with variable width based on pressure\n *\n * @private\n * @param {Array} points - Array of [x, y] coordinates (normalized or offset)\n * @param {number} baseWidth - Base stroke width in pixels\n * @param {Array} pressures - Pressure values (0-1) per point\n * @param {boolean} [uniformScale=false] - Use uniform scaling to preserve aspect ratio\n * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)\n * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)\n */\n _drawVariableWidthStroke(points, baseWidth, pressures, uniformScale = false, baseX = null, baseY = null) {\n const { ctx, viewport } = this;\n\n // When uniformScale is true and baseX/baseY provided, points are offsets from base position\n const hasBasePosition = uniformScale && baseX !== null && baseY !== null;\n\n for (let i = 1; i < points.length; i++) {\n const [c1x, c1y] = points[i - 1];\n const [c2x, c2y] = points[i];\n\n let px1, py1, px2, py2;\n\n if (hasBasePosition) {\n // Base position in pixels + uniform-scaled offset\n px1 = baseX * viewport.width + c1x * viewport.height;\n py1 = baseY * viewport.height + c1y * viewport.height;\n px2 = baseX * viewport.width + c2x * viewport.height;\n py2 = baseY * viewport.height + c2y * viewport.height;\n } else if (uniformScale) {\n // Legacy: full coordinates in uniform space\n px1 = c1x * viewport.height;\n py1 = c1y * viewport.height;\n px2 = c2x * viewport.height;\n py2 = c2y * viewport.height;\n } else {\n // Standard: X scaled by width, Y by height\n px1 = c1x * viewport.width;\n py1 = c1y * viewport.height;\n px2 = c2x * viewport.width;\n py2 = c2y * viewport.height;\n }\n\n // Average pressure between two points\n const p1 = pressures[i - 1] || 1;\n const p2 = pressures[i] || 1;\n const avgPressure = (p1 + p2) / 2;\n\n // Apply pressure to width (min 0.5)\n const width = Math.max(0.5, baseWidth * avgPressure);\n\n ctx.lineWidth = width;\n ctx.beginPath();\n ctx.moveTo(px1, py1);\n ctx.lineTo(px2, py2);\n ctx.stroke();\n }\n }\n}\n\nexport { StrokeRenderer };\nexport default StrokeRenderer;\n"],"names":["DEFAULT_CONFIG","StrokeRenderer","canvas","config","deepMerge","highlightToStrokes","textToStrokes","type","converter","width","height","dpr","annotations","page","filtered","a","annotation","style","strokes","time","ctx","viewport","stroke","duration","elapsed","progress","annotationStyle","resolved","p1","p2","t","pressures","lastCompleteIndex","segmentProgress","visiblePressures","points","color","lineCap","uniformScale","baseX","baseY","totalSegments","progressAlongPath","visiblePoints","hasBasePosition","i","coordX","coordY","px","py","baseWidth","c1x","c1y","c2x","c2y","px1","py1","px2","py2","avgPressure"],"mappings":";;;AAeA,MAAMA,IAAiB;AAAA,EACrB,KAAK;AAAA,IACH,QAAQ,EAAE,WAAW,GAAK,WAAW,KAAI;AAAA,IACzC,UAAU,EAAE,SAAS,MAAM,UAAU,IAAI;AAAA,IACzC,QAAQ,EAAE,WAAW,KAAK,WAAW,KAAI;AAAA,EAC7C;AAAA,EACE,WAAW;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,QAAQ,EAAE,WAAW,EAAC;AAAA,EAC1B;AAAA,EACE,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,QAAQ,EAAE,WAAW,EAAC;AAAA,IACtB,UAAU,EAAE,SAAS,GAAG,UAAU,EAAC;AAAA,EACvC;AACA;AAgBA,MAAMC,EAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUnB,YAAYC,GAAQC,IAAS,IAAI;AAC/B,QAAI,CAACD,KAAU,EAAEA,aAAkB;AACjC,YAAM,IAAI,MAAM,0DAA0D;AAG5E,SAAK,SAASA,GACd,KAAK,MAAMA,EAAO,WAAW,IAAI,GACjC,KAAK,SAASE,EAAUJ,GAAgBG,CAAM,GAC9C,KAAK,UAAU,CAAA,GACf,KAAK,WAAW,EAAE,OAAO,GAAG,QAAQ,EAAC,GAGrC,KAAK,aAAa;AAAA,MAChB,WAAWE;AAAA,MACX,MAAMC;AAAA,IACZ;AAAA,EACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBAAkBC,GAAMC,GAAW;AACjC,QAAI,OAAOA,KAAc;AACvB,YAAM,IAAI,MAAM,gEAAgE;AAElF,SAAK,WAAWD,CAAI,IAAIC;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAYC,GAAOC,GAAQ;AACzB,SAAK,WAAW,EAAE,OAAAD,GAAO,QAAAC,EAAM;AAE/B,UAAMC,IAAM,OAAO,oBAAoB;AAGvC,SAAK,OAAO,QAAQF,IAAQE,GAC5B,KAAK,OAAO,SAASD,IAASC,GAG9B,KAAK,OAAO,MAAM,QAAQ,GAAGF,CAAK,MAClC,KAAK,OAAO,MAAM,SAAS,GAAGC,CAAM,MAGpC,KAAK,IAAI,aAAaC,GAAK,GAAG,GAAGA,GAAK,GAAG,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,eAAeC,GAAaC,IAAO,MAAM;AACvC,QAAI,CAAC,MAAM,QAAQD,CAAW,GAAG;AAC/B,cAAQ,KAAK,6DAA6D,GAC1E,KAAK,UAAU,CAAA;AACf;AAAA,IACF;AAGA,UAAME,IAAWD,MAAS,OACtBD,EAAY,OAAO,CAAAG,MAAKA,EAAE,SAASF,CAAI,IACvCD;AAGJ,SAAK,UAAUE,EAAS,QAAQ,CAAAE,MAAc;AAC5C,YAAMR,IAAY,KAAK,WAAWQ,EAAW,IAAI;AAEjD,UAAI,CAACR;AACH,uBAAQ,KAAK,4CAA4CQ,EAAW,IAAI,GAAG,GACpE,CAAA;AAIT,YAAMC,IAAQ,KAAK,cAAcD,CAAU;AAE3C,aAAOR,EAAUQ,GAAYC,CAAK;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAWC,GAAS;AAClB,QAAI,CAAC,MAAM,QAAQA,CAAO,GAAG;AAC3B,cAAQ,KAAK,qDAAqD,GAClE,KAAK,UAAU,CAAA;AACf;AAAA,IACF;AACA,SAAK,UAAUA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAOC,GAAM;AACX,UAAM,EAAE,KAAAC,GAAK,UAAAC,GAAU,SAAAH,EAAO,IAAK;AAGnC,IAAAE,EAAI,UAAU,GAAG,GAAGC,EAAS,OAAOA,EAAS,MAAM;AAGnD,eAAWC,KAAUJ,GAAS;AAE5B,UAAIC,IAAOG,EAAO;AAChB;AAIF,YAAMC,IAAWD,EAAO,MAAMA,EAAO,OAC/BE,IAAUL,IAAOG,EAAO,OACxBG,IAAWF,IAAW,IAAI,KAAK,IAAI,GAAGC,IAAUD,CAAQ,IAAI;AAElE,WAAK,YAAYD,GAAQG,CAAQ;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,SAAK,IAAI,UAAU,GAAG,GAAG,KAAK,SAAS,OAAO,KAAK,SAAS,MAAM;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,UAAU,CAAA,GACf,KAAK,MAAM,MACX,KAAK,SAAS,MACd,KAAK,SAAS,MACd,KAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,cAAcT,GAAY;AACxB,UAAM,EAAE,MAAAT,GAAM,OAAOmB,EAAe,IAAKV;AAGzC,QAAIW,IAAW,EAAE,GAAG,KAAK,OAAO,IAAG;AAGnC,WAAI,KAAK,OAAOpB,CAAI,MAClBoB,IAAWvB,EAAUuB,GAAU,KAAK,OAAOpB,CAAI,CAAC,IAI9CmB,MACFC,IAAWvB,EAAUuB,GAAUD,CAAe,IAGzCC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBAAkBC,GAAIC,GAAIC,GAAG;AAC3B,WAAO;AAAA,MACLF,EAAG,CAAC,KAAKC,EAAG,CAAC,IAAID,EAAG,CAAC,KAAKE;AAAA,MAC1BF,EAAG,CAAC,KAAKC,EAAG,CAAC,IAAID,EAAG,CAAC,KAAKE;AAAA,IAChC;AAAA,EACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,sBAAsBC,GAAWC,GAAmBC,GAAiB;AACnE,UAAMC,IAAmBH,EAAU,MAAM,GAAGC,IAAoB,CAAC;AAEjE,QAAIA,IAAoBD,EAAU,SAAS,KAAKE,IAAkB,GAAG;AACnE,YAAML,IAAKG,EAAUC,CAAiB,GAChCH,IAAKE,EAAUC,IAAoB,CAAC;AAC1C,MAAAE,EAAiB,KAAKN,KAAMC,IAAKD,KAAMK,CAAe;AAAA,IACxD;AAEA,WAAOC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAYZ,GAAQG,GAAU;AAC5B,UAAM,EAAE,KAAAL,EAAG,IAAK,MACV,EAAE,QAAAe,GAAQ,OAAAC,GAAO,OAAA3B,GAAO,SAAA4B,GAAS,WAAAN,GAAW,cAAAO,GAAc,OAAAC,GAAO,OAAAC,EAAK,IAAKlB;AAEjF,QAAI,CAACa,KAAUA,EAAO,SAAS,EAAG;AAQlC,QALAf,EAAI,cAAcgB,KAAS,sBAC3BhB,EAAI,UAAUiB,KAAW,SACzBjB,EAAI,WAAW,SAGXK,KAAY,GAAG;AACjB,MAAIM,KAAaA,EAAU,UAAUI,EAAO,SAC1C,KAAK,yBAAyBA,GAAQ1B,GAAOsB,GAAWO,GAAcC,GAAOC,CAAK,IAElF,KAAK,yBAAyBL,GAAQ1B,GAAO6B,GAAcC,GAAOC,CAAK;AAEzE;AAAA,IACF;AAGA,UAAMC,IAAgBN,EAAO,SAAS,GAChCO,IAAoBjB,IAAWgB,GAC/BT,IAAoB,KAAK,MAAMU,CAAiB,GAChDT,IAAkBS,IAAoBV,GAGtCW,IAAgBR,EAAO,MAAM,GAAGH,IAAoB,CAAC;AAG3D,QAAIA,IAAoBS,KAAiBR,IAAkB,GAAG;AAC5D,YAAML,IAAKO,EAAOH,CAAiB,GAC7BH,IAAKM,EAAOH,IAAoB,CAAC;AACvC,MAAAW,EAAc,KAAK,KAAK,kBAAkBf,GAAIC,GAAII,CAAe,CAAC;AAAA,IACpE;AAGA,QAAI,EAAAU,EAAc,SAAS;AAG3B,UAAIZ,KAAaA,EAAU,UAAUI,EAAO,QAAQ;AAClD,cAAMD,IAAmB,KAAK;AAAA,UAC5BH;AAAA,UAAWC;AAAA,UAAmBC;AAAA,QACtC;AACM,aAAK,yBAAyBU,GAAelC,GAAOyB,GAAkBI,GAAcC,GAAOC,CAAK;AAAA,MAClG;AACE,aAAK,yBAAyBG,GAAelC,GAAO6B,GAAcC,GAAOC,CAAK;AAAA,EAElF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,yBAAyBL,GAAQ1B,GAAO6B,IAAe,IAAOC,IAAQ,MAAMC,IAAQ,MAAM;AACxF,UAAM,EAAE,KAAApB,GAAK,UAAAC,EAAQ,IAAK;AAE1B,IAAAD,EAAI,YAAYX,KAAS,GACzBW,EAAI,UAAS;AAKb,UAAMwB,IAAkBN,KAAgBC,MAAU,QAAQC,MAAU;AAEpE,aAASK,IAAI,GAAGA,IAAIV,EAAO,QAAQU,KAAK;AACtC,YAAM,CAACC,GAAQC,CAAM,IAAIZ,EAAOU,CAAC;AACjC,UAAIG,GAAIC;AAER,MAAIL,KAEFI,IAAKT,IAAQlB,EAAS,QAAQyB,IAASzB,EAAS,QAChD4B,IAAKT,IAAQnB,EAAS,SAAS0B,IAAS1B,EAAS,UACxCiB,KAETU,IAAKF,IAASzB,EAAS,QACvB4B,IAAKF,IAAS1B,EAAS,WAGvB2B,IAAKF,IAASzB,EAAS,OACvB4B,IAAKF,IAAS1B,EAAS,SAGrBwB,MAAM,IACRzB,EAAI,OAAO4B,GAAIC,CAAE,IAEjB7B,EAAI,OAAO4B,GAAIC,CAAE;AAAA,IAErB;AAEA,IAAA7B,EAAI,OAAM;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,yBAAyBe,GAAQe,GAAWnB,GAAWO,IAAe,IAAOC,IAAQ,MAAMC,IAAQ,MAAM;AACvG,UAAM,EAAE,KAAApB,GAAK,UAAAC,EAAQ,IAAK,MAGpBuB,IAAkBN,KAAgBC,MAAU,QAAQC,MAAU;AAEpE,aAASK,IAAI,GAAGA,IAAIV,EAAO,QAAQU,KAAK;AACtC,YAAM,CAACM,GAAKC,CAAG,IAAIjB,EAAOU,IAAI,CAAC,GACzB,CAACQ,GAAKC,CAAG,IAAInB,EAAOU,CAAC;AAE3B,UAAIU,GAAKC,GAAKC,GAAKC;AAEnB,MAAId,KAEFW,IAAMhB,IAAQlB,EAAS,QAAQ8B,IAAM9B,EAAS,QAC9CmC,IAAMhB,IAAQnB,EAAS,SAAS+B,IAAM/B,EAAS,QAC/CoC,IAAMlB,IAAQlB,EAAS,QAAQgC,IAAMhC,EAAS,QAC9CqC,IAAMlB,IAAQnB,EAAS,SAASiC,IAAMjC,EAAS,UACtCiB,KAETiB,IAAMJ,IAAM9B,EAAS,QACrBmC,IAAMJ,IAAM/B,EAAS,QACrBoC,IAAMJ,IAAMhC,EAAS,QACrBqC,IAAMJ,IAAMjC,EAAS,WAGrBkC,IAAMJ,IAAM9B,EAAS,OACrBmC,IAAMJ,IAAM/B,EAAS,QACrBoC,IAAMJ,IAAMhC,EAAS,OACrBqC,IAAMJ,IAAMjC,EAAS;AAIvB,YAAMO,IAAKG,EAAUc,IAAI,CAAC,KAAK,GACzBhB,IAAKE,EAAUc,CAAC,KAAK,GACrBc,KAAe/B,IAAKC,KAAM,GAG1BpB,IAAQ,KAAK,IAAI,KAAKyC,IAAYS,CAAW;AAEnD,MAAAvC,EAAI,YAAYX,GAChBW,EAAI,UAAS,GACbA,EAAI,OAAOmC,GAAKC,CAAG,GACnBpC,EAAI,OAAOqC,GAAKC,CAAG,GACnBtC,EAAI,OAAM;AAAA,IACZ;AAAA,EACF;AACF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-annotation-renderer",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "Framework-agnostic PDF annotation renderer with timeline synchronization for educational content and interactive documents",
6
6
  "keywords": [