web-annotation-renderer 0.6.1 → 0.6.2

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.
Files changed (81) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +26 -24
  4. package/dist/index.js.map +1 -1
  5. package/dist/index10.cjs +1 -1
  6. package/dist/index10.js +1 -1
  7. package/dist/index11.cjs +1 -1
  8. package/dist/index11.js +2 -2
  9. package/dist/index13.cjs +1 -1
  10. package/dist/index13.js +1 -1
  11. package/dist/index14.cjs +1 -1
  12. package/dist/index14.js +1 -1
  13. package/dist/index15.cjs +1 -1
  14. package/dist/index15.js +1 -1
  15. package/dist/index16.cjs +1 -1
  16. package/dist/index16.js +1 -1
  17. package/dist/index17.cjs +1 -1
  18. package/dist/index17.js +1 -1
  19. package/dist/index18.cjs +1 -1
  20. package/dist/index18.cjs.map +1 -1
  21. package/dist/index18.js +22 -117
  22. package/dist/index18.js.map +1 -1
  23. package/dist/index19.cjs +1 -1
  24. package/dist/index19.cjs.map +1 -1
  25. package/dist/index19.js +83 -69
  26. package/dist/index19.js.map +1 -1
  27. package/dist/index20.cjs +1 -1
  28. package/dist/index20.cjs.map +1 -1
  29. package/dist/index20.js +100 -76
  30. package/dist/index20.js.map +1 -1
  31. package/dist/index21.cjs +1 -1
  32. package/dist/index21.cjs.map +1 -1
  33. package/dist/index21.js +77 -138
  34. package/dist/index21.js.map +1 -1
  35. package/dist/index22.cjs +1 -1
  36. package/dist/index22.cjs.map +1 -1
  37. package/dist/index22.js +139 -36
  38. package/dist/index22.js.map +1 -1
  39. package/dist/index23.cjs +1 -1
  40. package/dist/index23.cjs.map +1 -1
  41. package/dist/index23.js +35 -34
  42. package/dist/index23.js.map +1 -1
  43. package/dist/index24.cjs +1 -1
  44. package/dist/index24.cjs.map +1 -1
  45. package/dist/index24.js +27 -28
  46. package/dist/index24.js.map +1 -1
  47. package/dist/index25.cjs +1 -1
  48. package/dist/index25.cjs.map +1 -1
  49. package/dist/index25.js +38 -40
  50. package/dist/index25.js.map +1 -1
  51. package/dist/index26.cjs +1 -1
  52. package/dist/index26.cjs.map +1 -1
  53. package/dist/index26.js +39 -4
  54. package/dist/index26.js.map +1 -1
  55. package/dist/index27.cjs +1 -1
  56. package/dist/index27.js +4 -4
  57. package/dist/index28.cjs +1 -1
  58. package/dist/index28.cjs.map +1 -1
  59. package/dist/index28.js +5 -71
  60. package/dist/index28.js.map +1 -1
  61. package/dist/index29.cjs +1 -1
  62. package/dist/index29.cjs.map +1 -1
  63. package/dist/index29.js +70 -4
  64. package/dist/index29.js.map +1 -1
  65. package/dist/index30.cjs +1 -1
  66. package/dist/index30.cjs.map +1 -1
  67. package/dist/index30.js +4 -991
  68. package/dist/index30.js.map +1 -1
  69. package/dist/index31.cjs +2 -0
  70. package/dist/index31.cjs.map +1 -0
  71. package/dist/index31.js +995 -0
  72. package/dist/index31.js.map +1 -0
  73. package/dist/index5.cjs +1 -1
  74. package/dist/index5.cjs.map +1 -1
  75. package/dist/index5.js +63 -56
  76. package/dist/index5.js.map +1 -1
  77. package/dist/index9.cjs +1 -1
  78. package/dist/index9.cjs.map +1 -1
  79. package/dist/index9.js +17 -15
  80. package/dist/index9.js.map +1 -1
  81. package/package.json +1 -1
@@ -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 {\n highlightToStrokes,\n textToStrokes,\n underlineToStrokes,\n arrowToStrokes,\n circleToStrokes,\n} from \"../converters/index.js\";\n\n/**\n * Supported annotation types\n */\nconst ANNOTATION_TYPES = [\"highlight\", \"text\", \"underline\", \"arrow\", \"circle\"];\n\n/**\n * Reference viewport height for width scaling\n * Stroke widths are defined relative to this height (500px = roughjs-tester default)\n */\nconst REFERENCE_HEIGHT = 500;\n\n/**\n * Default configuration\n *\n * Each annotation type has:\n * - Rendering options: color, width, lineCap\n * - RoughJS options: roughness, bowing, curveFitting, curveStepCount, maxRandomnessOffset, disableMultiStroke\n */\nconst DEFAULT_CONFIG = {\n highlight: {\n color: \"rgba(255, 255, 0, 0.3)\",\n width: 24,\n lineCap: \"square\",\n roughness: 1.2,\n bowing: 1.2,\n curveFitting: 0.95,\n curveStepCount: 9,\n maxRandomnessOffset: 2,\n disableMultiStroke: false,\n },\n text: {\n color: \"rgba(220, 20, 60, 1.0)\",\n width: 2,\n fontSize: 16,\n lineCap: \"round\",\n roughness: 0.8,\n },\n underline: {\n color: \"rgba(0, 0, 255, 0.8)\",\n width: 2,\n lineCap: \"round\",\n roughness: 2.0,\n bowing: 2.4,\n curveFitting: 0.85,\n curveStepCount: 9,\n maxRandomnessOffset: 3,\n disableMultiStroke: false,\n },\n arrow: {\n color: \"rgba(255, 0, 0, 0.8)\",\n width: 2,\n lineCap: \"round\",\n roughness: 1.8,\n bowing: 1.8,\n curveFitting: 0.9,\n curveStepCount: 9,\n maxRandomnessOffset: 2,\n disableMultiStroke: false,\n },\n circle: {\n color: \"rgba(255, 165, 0, 0.8)\",\n width: 3,\n lineCap: \"round\",\n roughness: 1.7,\n bowing: 2.0,\n curveFitting: 0.8,\n curveStepCount: 12,\n maxRandomnessOffset: 3,\n disableMultiStroke: false,\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 per annotation type\n * @param {Object} [config.highlight] - Highlight type settings\n * @param {Object} [config.text] - Text type settings\n * @param {Object} [config.underline] - Underline type settings\n * @param {Object} [config.arrow] - Arrow type settings\n * @param {Object} [config.circle] - Circle type settings\n */\n constructor(canvas, config = {}) {\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error(\n \"StrokeRenderer: canvas must be a valid HTMLCanvasElement\"\n );\n }\n\n this.canvas = canvas;\n this.ctx = canvas.getContext(\"2d\");\n this.strokes = [];\n this.viewport = { width: 0, height: 0 };\n\n // Initialize config with defaults\n this.config = {};\n for (const type of ANNOTATION_TYPES) {\n this.config[type] = { ...DEFAULT_CONFIG[type] };\n }\n\n // Apply user config if provided\n if (Object.keys(config).length > 0) {\n this.setConfig(config);\n }\n\n // Register built-in converters\n this.converters = {\n highlight: highlightToStrokes,\n text: textToStrokes,\n underline: underlineToStrokes,\n arrow: arrowToStrokes,\n circle: circleToStrokes,\n };\n }\n\n /**\n * Set configuration options\n *\n * Supports global options (applied to all types) and type-specific options.\n *\n * @param {Object} config - Configuration object\n * @param {number} [config.roughness] - Global roughness for all types\n * @param {string} [config.color] - Global color for all types\n * @param {number} [config.width] - Global width for all types\n * @param {Object} [config.highlight] - Highlight-specific options\n * @param {Object} [config.text] - Text-specific options\n * @param {Object} [config.underline] - Underline-specific options\n * @param {Object} [config.arrow] - Arrow-specific options\n * @param {Object} [config.circle] - Circle-specific options\n * @returns {StrokeRenderer} Returns this for chaining\n *\n * @example\n * // Global options\n * renderer.setConfig({ roughness: 2, color: \"blue\" });\n *\n * // Type-specific options\n * renderer.setConfig({ highlight: { color: \"yellow\", width: 30 } });\n *\n * // Combined\n * renderer.setConfig({\n * roughness: 2,\n * highlight: { color: \"yellow\" }\n * });\n */\n setConfig(config) {\n const globalOptions = {};\n const typeOptions = {};\n\n // Separate global options from type-specific options\n for (const [key, value] of Object.entries(config)) {\n if (ANNOTATION_TYPES.includes(key)) {\n typeOptions[key] = value;\n } else {\n globalOptions[key] = value;\n }\n }\n\n // Apply to each type: current config + global + type-specific\n for (const type of ANNOTATION_TYPES) {\n this.config[type] = {\n ...this.config[type],\n ...globalOptions,\n ...(typeOptions[type] || {}),\n };\n }\n\n return this;\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(\n \"StrokeRenderer.registerConverter: converter must be a function\"\n );\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(\n \"StrokeRenderer.setAnnotations: annotations must be an array\"\n );\n this.strokes = [];\n return;\n }\n\n // Filter by page if specified\n const filtered =\n page !== null ? annotations.filter((a) => a.page === page) : 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(\n `StrokeRenderer: Unknown annotation type \"${annotation.type}\"`\n );\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 * Returns the config for the annotation type.\n * Style is managed via setConfig(), not per-annotation.\n *\n * @private\n * @param {Object} annotation - Annotation object\n * @returns {Object} Resolved style object\n */\n _resolveStyle(annotation) {\n const { type } = annotation;\n return this.config[type] || {};\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 [p1[0] + (p2[0] - p1[0]) * t, p1[1] + (p2[1] - p1[1]) * t];\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 {\n points,\n color,\n width,\n lineCap,\n pressures,\n uniformScale,\n baseX,\n baseY,\n } = 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(\n points,\n width,\n pressures,\n uniformScale,\n baseX,\n baseY\n );\n } else {\n this._drawConstantWidthStroke(\n points,\n width,\n uniformScale,\n baseX,\n baseY\n );\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,\n lastCompleteIndex,\n segmentProgress\n );\n this._drawVariableWidthStroke(\n visiblePoints,\n width,\n visiblePressures,\n uniformScale,\n baseX,\n baseY\n );\n } else {\n this._drawConstantWidthStroke(\n visiblePoints,\n width,\n uniformScale,\n baseX,\n baseY\n );\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(\n points,\n width,\n uniformScale = false,\n baseX = null,\n baseY = null\n ) {\n const { ctx, viewport } = this;\n\n // Scale width based on viewport height for consistent appearance\n const scale = viewport.height / REFERENCE_HEIGHT;\n ctx.lineWidth = (width || 2) * scale;\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(\n points,\n baseWidth,\n pressures,\n uniformScale = false,\n baseX = null,\n baseY = null\n ) {\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) and scale for viewport\n const scale = viewport.height / REFERENCE_HEIGHT;\n const width = Math.max(0.5, baseWidth * avgPressure) * scale;\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":["ANNOTATION_TYPES","REFERENCE_HEIGHT","DEFAULT_CONFIG","StrokeRenderer","canvas","config","type","highlightToStrokes","textToStrokes","underlineToStrokes","arrowToStrokes","circleToStrokes","globalOptions","typeOptions","key","value","converter","width","height","dpr","annotations","page","filtered","a","annotation","style","strokes","time","ctx","viewport","stroke","duration","elapsed","progress","p1","p2","t","pressures","lastCompleteIndex","segmentProgress","visiblePressures","points","color","lineCap","uniformScale","baseX","baseY","totalSegments","progressAlongPath","visiblePoints","scale","hasBasePosition","i","coordX","coordY","px","py","baseWidth","c1x","c1y","c2x","c2y","px1","py1","px2","py2","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 {\n highlightToStrokes,\n textToStrokes,\n underlineToStrokes,\n arrowToStrokes,\n circleToStrokes,\n inkToStrokes,\n} from \"../converters/index.js\";\n\n/**\n * Supported annotation types\n */\nconst ANNOTATION_TYPES = [\"highlight\", \"text\", \"underline\", \"arrow\", \"circle\", \"ink\"];\n\n/**\n * Reference viewport height for width scaling\n * Stroke widths are defined relative to this height (500px = roughjs-tester default)\n */\nconst REFERENCE_HEIGHT = 500;\n\n/**\n * Default configuration\n *\n * Each annotation type has:\n * - Rendering options: color, width, lineCap\n * - RoughJS options: roughness, bowing, curveFitting, curveStepCount, maxRandomnessOffset, disableMultiStroke\n */\nconst DEFAULT_CONFIG = {\n highlight: {\n color: \"rgba(255, 255, 0, 0.3)\",\n width: 24,\n lineCap: \"square\",\n roughness: 1.2,\n bowing: 1.2,\n curveFitting: 0.95,\n curveStepCount: 9,\n maxRandomnessOffset: 2,\n disableMultiStroke: false,\n },\n text: {\n color: \"rgba(220, 20, 60, 1.0)\",\n width: 2,\n fontSize: 16,\n lineCap: \"round\",\n roughness: 0.8,\n },\n underline: {\n color: \"rgba(0, 0, 255, 0.8)\",\n width: 2,\n lineCap: \"round\",\n roughness: 2.0,\n bowing: 2.4,\n curveFitting: 0.85,\n curveStepCount: 9,\n maxRandomnessOffset: 3,\n disableMultiStroke: false,\n },\n arrow: {\n color: \"rgba(255, 0, 0, 0.8)\",\n width: 2,\n lineCap: \"round\",\n roughness: 1.8,\n bowing: 1.8,\n curveFitting: 0.9,\n curveStepCount: 9,\n maxRandomnessOffset: 2,\n disableMultiStroke: false,\n },\n circle: {\n color: \"rgba(255, 165, 0, 0.8)\",\n width: 3,\n lineCap: \"round\",\n roughness: 1.7,\n bowing: 2.0,\n curveFitting: 0.8,\n curveStepCount: 12,\n maxRandomnessOffset: 3,\n disableMultiStroke: false,\n },\n ink: {\n color: \"#DC143C\",\n width: 2,\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 per annotation type\n * @param {Object} [config.highlight] - Highlight type settings\n * @param {Object} [config.text] - Text type settings\n * @param {Object} [config.underline] - Underline type settings\n * @param {Object} [config.arrow] - Arrow type settings\n * @param {Object} [config.circle] - Circle type settings\n */\n constructor(canvas, config = {}) {\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error(\n \"StrokeRenderer: canvas must be a valid HTMLCanvasElement\"\n );\n }\n\n this.canvas = canvas;\n this.ctx = canvas.getContext(\"2d\");\n this.strokes = [];\n this.viewport = { width: 0, height: 0 };\n\n // Initialize config with defaults\n this.config = {};\n for (const type of ANNOTATION_TYPES) {\n this.config[type] = { ...DEFAULT_CONFIG[type] };\n }\n\n // Apply user config if provided\n if (Object.keys(config).length > 0) {\n this.setConfig(config);\n }\n\n // Register built-in converters\n this.converters = {\n highlight: highlightToStrokes,\n text: textToStrokes,\n underline: underlineToStrokes,\n arrow: arrowToStrokes,\n circle: circleToStrokes,\n ink: inkToStrokes,\n };\n }\n\n /**\n * Set configuration options\n *\n * Supports global options (applied to all types) and type-specific options.\n *\n * @param {Object} config - Configuration object\n * @param {number} [config.roughness] - Global roughness for all types\n * @param {string} [config.color] - Global color for all types\n * @param {number} [config.width] - Global width for all types\n * @param {Object} [config.highlight] - Highlight-specific options\n * @param {Object} [config.text] - Text-specific options\n * @param {Object} [config.underline] - Underline-specific options\n * @param {Object} [config.arrow] - Arrow-specific options\n * @param {Object} [config.circle] - Circle-specific options\n * @returns {StrokeRenderer} Returns this for chaining\n *\n * @example\n * // Global options\n * renderer.setConfig({ roughness: 2, color: \"blue\" });\n *\n * // Type-specific options\n * renderer.setConfig({ highlight: { color: \"yellow\", width: 30 } });\n *\n * // Combined\n * renderer.setConfig({\n * roughness: 2,\n * highlight: { color: \"yellow\" }\n * });\n */\n setConfig(config) {\n const globalOptions = {};\n const typeOptions = {};\n\n // Separate global options from type-specific options\n for (const [key, value] of Object.entries(config)) {\n if (ANNOTATION_TYPES.includes(key)) {\n typeOptions[key] = value;\n } else {\n globalOptions[key] = value;\n }\n }\n\n // Apply to each type: current config + global + type-specific\n for (const type of ANNOTATION_TYPES) {\n this.config[type] = {\n ...this.config[type],\n ...globalOptions,\n ...(typeOptions[type] || {}),\n };\n }\n\n return this;\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(\n \"StrokeRenderer.registerConverter: converter must be a function\"\n );\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(\n \"StrokeRenderer.setAnnotations: annotations must be an array\"\n );\n this.strokes = [];\n return;\n }\n\n // Filter by page if specified\n const filtered =\n page !== null ? annotations.filter((a) => a.page === page) : 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(\n `StrokeRenderer: Unknown annotation type \"${annotation.type}\"`\n );\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 * Returns the config for the annotation type.\n * Style is managed via setConfig(), not per-annotation.\n *\n * @private\n * @param {Object} annotation - Annotation object\n * @returns {Object} Resolved style object\n */\n _resolveStyle(annotation) {\n const { type } = annotation;\n return this.config[type] || {};\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 [p1[0] + (p2[0] - p1[0]) * t, p1[1] + (p2[1] - p1[1]) * t];\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 {\n points,\n color,\n width,\n lineCap,\n pressures,\n uniformScale,\n baseX,\n baseY,\n } = 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(\n points,\n width,\n pressures,\n uniformScale,\n baseX,\n baseY\n );\n } else {\n this._drawConstantWidthStroke(\n points,\n width,\n uniformScale,\n baseX,\n baseY\n );\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,\n lastCompleteIndex,\n segmentProgress\n );\n this._drawVariableWidthStroke(\n visiblePoints,\n width,\n visiblePressures,\n uniformScale,\n baseX,\n baseY\n );\n } else {\n this._drawConstantWidthStroke(\n visiblePoints,\n width,\n uniformScale,\n baseX,\n baseY\n );\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(\n points,\n width,\n uniformScale = false,\n baseX = null,\n baseY = null\n ) {\n const { ctx, viewport } = this;\n\n // Scale width based on viewport height for consistent appearance\n const scale = viewport.height / REFERENCE_HEIGHT;\n ctx.lineWidth = (width || 2) * scale;\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(\n points,\n baseWidth,\n pressures,\n uniformScale = false,\n baseX = null,\n baseY = null\n ) {\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) and scale for viewport\n const scale = viewport.height / REFERENCE_HEIGHT;\n const width = Math.max(0.5, baseWidth * avgPressure) * scale;\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":["ANNOTATION_TYPES","REFERENCE_HEIGHT","DEFAULT_CONFIG","StrokeRenderer","canvas","config","type","highlightToStrokes","textToStrokes","underlineToStrokes","arrowToStrokes","circleToStrokes","inkToStrokes","globalOptions","typeOptions","key","value","converter","width","height","dpr","annotations","page","filtered","a","annotation","style","strokes","time","ctx","viewport","stroke","duration","elapsed","progress","p1","p2","t","pressures","lastCompleteIndex","segmentProgress","visiblePressures","points","color","lineCap","uniformScale","baseX","baseY","totalSegments","progressAlongPath","visiblePoints","scale","hasBasePosition","i","coordX","coordY","px","py","baseWidth","c1x","c1y","c2x","c2y","px1","py1","px2","py2","avgPressure"],"mappings":"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"}
package/dist/index9.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./index25.cjs");function d(t,n,e,l,o){let i=t;return typeof t=="string"&&(i=parseFloat(t)),typeof i!="number"||isNaN(i)?(o.push(`[${e}]: Field "${l}" invalid value "${t}", using default ${n}`),n):i<0?(o.push(`[${e}]: Field "${l}" value ${i} below range [0,1], clamping to 0`),0):i>1?(o.push(`[${e}]: Field "${l}" value ${i} exceeds range [0,1], clamping to 1`),1):i}function c(t,n,e,l){if(typeof t!="string"||t.trim().length===0)return l.push(`[${e}]: Invalid color format "${t}", using default ${n}`),n;const o=t.trim(),i=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/,r=/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+\s*)?\)$/,u=["red","blue","green","yellow","black","white","gray","grey","orange","purple","pink","brown","transparent"],$=i.test(o),E=r.test(o),T=u.includes(o.toLowerCase());return $||E||T?o:(l.push(`[${e}]: Invalid color format "${t}", using default ${n}`),n)}function F(t,n,e,l,o){let i=t;return typeof t=="string"&&(i=parseFloat(t)),typeof i!="number"||isNaN(i)||i<=0?(o.push(`[${e}]: Field "${l}" invalid value "${t}", using default ${n}`),n):i}function f(t,n,e){const l={};if(typeof t.id!="string"||t.id.trim().length===0){const o=Date.now(),i=Math.random().toString(36).substr(2,9);l.id=`anno-${o}-${i}`,e.push(`[${l.id}]: Auto-generated ID (original was missing or invalid)`)}else l.id=t.id.trim();return l.type=t.type,typeof t.page!="number"||t.page<1?(n.push(`[${l.id}]: Field "page" invalid value "${t.page}", using default ${s.BASE_DEFAULTS.page}`),l.page=s.BASE_DEFAULTS.page):l.page=Math.floor(t.page),typeof t.start!="number"||t.start<0?(n.push(`[${l.id}]: Field "start" invalid value "${t.start}", using default ${s.BASE_DEFAULTS.start}`),l.start=s.BASE_DEFAULTS.start):l.start=t.start,typeof t.end!="number"||t.end<0?(n.push(`[${l.id}]: Field "end" invalid value "${t.end}", using start value ${l.start}`),l.end=l.start):t.end<l.start?(n.push(`[${l.id}]: Field "end" (${t.end}) less than start (${l.start}), clamping to start`),l.end=l.start):l.end=t.end,l}function a(t,n,e){return!t||typeof t!="object"?(e.push(`[${n}]: Invalid quad object, using default`),{x:.1,y:.1,w:.8,h:.05}):{x:d(t.x,.1,n,"quad.x",e),y:d(t.y,.1,n,"quad.y",e),w:d(t.w,.8,n,"quad.w",e),h:d(t.h,.05,n,"quad.h",e)}}function y(t,n,e,l){const o={...t};n.mode!=="quads"?(e.push(`[${t.id}]: Field "mode" invalid value "${n.mode}", using default "${s.HIGHLIGHT_DEFAULTS.mode}"`),o.mode=s.HIGHLIGHT_DEFAULTS.mode):o.mode=n.mode,!Array.isArray(n.quads)||n.quads.length===0?(e.push(`[${t.id}]: Field "quads" missing or empty, using default`),o.quads=s.HIGHLIGHT_DEFAULTS.quads):o.quads=n.quads.map((r,u)=>a(r,t.id,e));const i=s.HIGHLIGHT_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?(e.push(`[${t.id}]: Field "style" missing or invalid, using default`),o.style={color:i}):o.style={color:c(n.style.color,i,t.id,e)},o}function p(t,n,e,l){const o={...t};typeof n.content!="string"||n.content.trim().length===0?(e.push(`[${t.id}]: Field "content" missing or empty, using default "${s.TEXT_DEFAULTS.content}"`),o.content=s.TEXT_DEFAULTS.content):o.content=n.content,o.x=d(n.x,s.TEXT_DEFAULTS.x,t.id,"x",e),o.y=d(n.y,s.TEXT_DEFAULTS.y,t.id,"y",e),o.w=d(n.w,s.TEXT_DEFAULTS.w,t.id,"w",e),o.h=d(n.h,s.TEXT_DEFAULTS.h,t.id,"h",e);const i=s.TEXT_DEFAULTS.style.bg,r=s.TEXT_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?(e.push(`[${t.id}]: Field "style" missing or invalid, using defaults`),o.style={bg:i,color:r}):o.style={bg:c(n.style.bg,i,t.id,e),color:c(n.style.color,r,t.id,e)},o}function m(t,n,e,l){const o={...t};!Array.isArray(n.quads)||n.quads.length===0?(e.push(`[${t.id}]: Field "quads" missing or empty, using default`),o.quads=s.UNDERLINE_DEFAULTS.quads):o.quads=n.quads.map(r=>a(r,t.id,e));const i=s.UNDERLINE_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?o.style={color:i}:o.style={color:c(n.style.color,i,t.id,e)},o}function g(t,n,e,l){const o={...t};o.from_x=d(n.from_x,s.ARROW_DEFAULTS.from_x,t.id,"from_x",e),o.from_y=d(n.from_y,s.ARROW_DEFAULTS.from_y,t.id,"from_y",e),o.to_x=d(n.to_x,s.ARROW_DEFAULTS.to_x,t.id,"to_x",e),o.to_y=d(n.to_y,s.ARROW_DEFAULTS.to_y,t.id,"to_y",e);const i=s.ARROW_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?o.style={color:i}:o.style={color:c(n.style.color,i,t.id,e)},o}function h(t,n,e,l){const o={...t};o.cx=d(n.cx,s.CIRCLE_DEFAULTS.cx,t.id,"cx",e),o.cy=d(n.cy,s.CIRCLE_DEFAULTS.cy,t.id,"cy",e),o.rx=d(n.rx,s.CIRCLE_DEFAULTS.rx,t.id,"rx",e),o.ry=d(n.ry,s.CIRCLE_DEFAULTS.ry,t.id,"ry",e);const i=s.CIRCLE_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?o.style={color:i}:o.style={color:c(n.style.color,i,t.id,e)},o}function A(t,n){const e=[],l=[];if(!t||typeof t!="object")return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Not a valid object`};if(typeof t.type!="string"||t.type.trim().length===0)return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Missing or invalid type field`};const o=t.type.trim(),i=f(t,e,l);let r;if(o==="highlight")r=y(i,t,e);else if(o==="text")r=p(i,t,e);else if(o==="underline")r=m(i,t,e);else if(o==="arrow")r=g(i,t,e);else if(o==="circle")r=h(i,t,e);else return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Unsupported type "${o}"`};return{annotation:r,warnings:e,info:l,critical:null}}function _(t,n={}){n.skipInvalid;const e=n.warnInConsole!==!1,l=n.onWarning||null,o={normalized:[],warnings:[],info:[],skipped:[]};if(!Array.isArray(t)){const i="normalizeAnnotationArray: Input is not an array, returning empty result";return o.warnings.push(i),e&&console.warn(`[Annotation Normalizer] ${i}`),o}return t.forEach((i,r)=>{if(i==null){o.skipped.push({index:r,annotation:i,reason:"Annotation is null or undefined"});return}const u=A(i,r);if(u.critical){o.skipped.push({index:r,annotation:i,reason:u.critical}),e&&console.error(`[Annotation Normalizer] ${u.critical}`);return}o.normalized.push(u.annotation),o.warnings.push(...u.warnings),o.info.push(...u.info)}),e&&(o.warnings.length>0||o.info.length>0||o.skipped.length>0)&&(console.group("[Annotation Normalizer] Validation Summary"),o.normalized.length>0&&console.info(`✓ Normalized ${o.normalized.length} annotation(s)`),o.skipped.length>0&&(console.error(`✗ Skipped ${o.skipped.length} annotation(s)`),o.skipped.forEach(i=>{console.error(` Index ${i.index}: ${i.reason}`)})),o.warnings.length>0&&(console.warn(`⚠ ${o.warnings.length} warning(s):`),o.warnings.forEach(i=>console.warn(` ${i}`))),o.info.length>0&&(console.info(`ℹ ${o.info.length} info message(s):`),o.info.forEach(i=>console.info(` ${i}`))),console.groupEnd()),l&&typeof l=="function"&&l(o),o}exports.normalizeAnnotation=A;exports.normalizeAnnotationArray=_;exports.normalizeArrow=g;exports.normalizeBaseFields=f;exports.normalizeCircle=h;exports.normalizeColor=c;exports.normalizeCoordinate=d;exports.normalizeHighlight=y;exports.normalizePositiveNumber=F;exports.normalizeText=p;exports.normalizeUnderline=m;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./index26.cjs");function d(t,n,e,l,o){let i=t;return typeof t=="string"&&(i=parseFloat(t)),typeof i!="number"||isNaN(i)?(o.push(`[${e}]: Field "${l}" invalid value "${t}", using default ${n}`),n):i<0?(o.push(`[${e}]: Field "${l}" value ${i} below range [0,1], clamping to 0`),0):i>1?(o.push(`[${e}]: Field "${l}" value ${i} exceeds range [0,1], clamping to 1`),1):i}function c(t,n,e,l){if(typeof t!="string"||t.trim().length===0)return l.push(`[${e}]: Invalid color format "${t}", using default ${n}`),n;const o=t.trim(),i=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/,r=/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+\s*)?\)$/,u=["red","blue","green","yellow","black","white","gray","grey","orange","purple","pink","brown","transparent"],$=i.test(o),E=r.test(o),T=u.includes(o.toLowerCase());return $||E||T?o:(l.push(`[${e}]: Invalid color format "${t}", using default ${n}`),n)}function F(t,n,e,l,o){let i=t;return typeof t=="string"&&(i=parseFloat(t)),typeof i!="number"||isNaN(i)||i<=0?(o.push(`[${e}]: Field "${l}" invalid value "${t}", using default ${n}`),n):i}function f(t,n,e){const l={};if(typeof t.id!="string"||t.id.trim().length===0){const o=Date.now(),i=Math.random().toString(36).substr(2,9);l.id=`anno-${o}-${i}`,e.push(`[${l.id}]: Auto-generated ID (original was missing or invalid)`)}else l.id=t.id.trim();return l.type=t.type,typeof t.page!="number"||t.page<1?(n.push(`[${l.id}]: Field "page" invalid value "${t.page}", using default ${s.BASE_DEFAULTS.page}`),l.page=s.BASE_DEFAULTS.page):l.page=Math.floor(t.page),typeof t.start!="number"||t.start<0?(n.push(`[${l.id}]: Field "start" invalid value "${t.start}", using default ${s.BASE_DEFAULTS.start}`),l.start=s.BASE_DEFAULTS.start):l.start=t.start,typeof t.end!="number"||t.end<0?(n.push(`[${l.id}]: Field "end" invalid value "${t.end}", using start value ${l.start}`),l.end=l.start):t.end<l.start?(n.push(`[${l.id}]: Field "end" (${t.end}) less than start (${l.start}), clamping to start`),l.end=l.start):l.end=t.end,l}function a(t,n,e){return!t||typeof t!="object"?(e.push(`[${n}]: Invalid quad object, using default`),{x:.1,y:.1,w:.8,h:.05}):{x:d(t.x,.1,n,"quad.x",e),y:d(t.y,.1,n,"quad.y",e),w:d(t.w,.8,n,"quad.w",e),h:d(t.h,.05,n,"quad.h",e)}}function y(t,n,e,l){const o={...t};n.mode!=="quads"?(e.push(`[${t.id}]: Field "mode" invalid value "${n.mode}", using default "${s.HIGHLIGHT_DEFAULTS.mode}"`),o.mode=s.HIGHLIGHT_DEFAULTS.mode):o.mode=n.mode,!Array.isArray(n.quads)||n.quads.length===0?(e.push(`[${t.id}]: Field "quads" missing or empty, using default`),o.quads=s.HIGHLIGHT_DEFAULTS.quads):o.quads=n.quads.map((r,u)=>a(r,t.id,e));const i=s.HIGHLIGHT_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?(e.push(`[${t.id}]: Field "style" missing or invalid, using default`),o.style={color:i}):o.style={color:c(n.style.color,i,t.id,e)},o}function p(t,n,e,l){const o={...t};typeof n.content!="string"||n.content.trim().length===0?(e.push(`[${t.id}]: Field "content" missing or empty, using default "${s.TEXT_DEFAULTS.content}"`),o.content=s.TEXT_DEFAULTS.content):o.content=n.content,o.x=d(n.x,s.TEXT_DEFAULTS.x,t.id,"x",e),o.y=d(n.y,s.TEXT_DEFAULTS.y,t.id,"y",e),o.w=d(n.w,s.TEXT_DEFAULTS.w,t.id,"w",e),o.h=d(n.h,s.TEXT_DEFAULTS.h,t.id,"h",e);const i=s.TEXT_DEFAULTS.style.bg,r=s.TEXT_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?(e.push(`[${t.id}]: Field "style" missing or invalid, using defaults`),o.style={bg:i,color:r}):o.style={bg:c(n.style.bg,i,t.id,e),color:c(n.style.color,r,t.id,e)},o}function m(t,n,e,l){const o={...t};!Array.isArray(n.quads)||n.quads.length===0?(e.push(`[${t.id}]: Field "quads" missing or empty, using default`),o.quads=s.UNDERLINE_DEFAULTS.quads):o.quads=n.quads.map(r=>a(r,t.id,e));const i=s.UNDERLINE_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?o.style={color:i}:o.style={color:c(n.style.color,i,t.id,e)},o}function g(t,n,e,l){const o={...t};o.from_x=d(n.from_x,s.ARROW_DEFAULTS.from_x,t.id,"from_x",e),o.from_y=d(n.from_y,s.ARROW_DEFAULTS.from_y,t.id,"from_y",e),o.to_x=d(n.to_x,s.ARROW_DEFAULTS.to_x,t.id,"to_x",e),o.to_y=d(n.to_y,s.ARROW_DEFAULTS.to_y,t.id,"to_y",e);const i=s.ARROW_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?o.style={color:i}:o.style={color:c(n.style.color,i,t.id,e)},o}function h(t,n,e,l){const o={...t};o.cx=d(n.cx,s.CIRCLE_DEFAULTS.cx,t.id,"cx",e),o.cy=d(n.cy,s.CIRCLE_DEFAULTS.cy,t.id,"cy",e),o.rx=d(n.rx,s.CIRCLE_DEFAULTS.rx,t.id,"rx",e),o.ry=d(n.ry,s.CIRCLE_DEFAULTS.ry,t.id,"ry",e);const i=s.CIRCLE_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?o.style={color:i}:o.style={color:c(n.style.color,i,t.id,e)},o}function A(t,n){const e=[],l=[];if(!t||typeof t!="object")return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Not a valid object`};if(typeof t.type!="string"||t.type.trim().length===0)return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Missing or invalid type field`};const o=t.type.trim(),i=f(t,e,l);let r;if(o==="highlight")r=y(i,t,e);else if(o==="text")r=p(i,t,e);else if(o==="underline")r=m(i,t,e);else if(o==="arrow")r=g(i,t,e);else if(o==="circle")r=h(i,t,e);else if(o==="ink")r={...i,strokes:t.strokes||[]},t.style&&(r.style=t.style);else return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Unsupported type "${o}"`};return{annotation:r,warnings:e,info:l,critical:null}}function _(t,n={}){n.skipInvalid;const e=n.warnInConsole!==!1,l=n.onWarning||null,o={normalized:[],warnings:[],info:[],skipped:[]};if(!Array.isArray(t)){const i="normalizeAnnotationArray: Input is not an array, returning empty result";return o.warnings.push(i),e&&console.warn(`[Annotation Normalizer] ${i}`),o}return t.forEach((i,r)=>{if(i==null){o.skipped.push({index:r,annotation:i,reason:"Annotation is null or undefined"});return}const u=A(i,r);if(u.critical){o.skipped.push({index:r,annotation:i,reason:u.critical}),e&&console.error(`[Annotation Normalizer] ${u.critical}`);return}o.normalized.push(u.annotation),o.warnings.push(...u.warnings),o.info.push(...u.info)}),e&&(o.warnings.length>0||o.info.length>0||o.skipped.length>0)&&(console.group("[Annotation Normalizer] Validation Summary"),o.normalized.length>0&&console.info(`✓ Normalized ${o.normalized.length} annotation(s)`),o.skipped.length>0&&(console.error(`✗ Skipped ${o.skipped.length} annotation(s)`),o.skipped.forEach(i=>{console.error(` Index ${i.index}: ${i.reason}`)})),o.warnings.length>0&&(console.warn(`⚠ ${o.warnings.length} warning(s):`),o.warnings.forEach(i=>console.warn(` ${i}`))),o.info.length>0&&(console.info(`ℹ ${o.info.length} info message(s):`),o.info.forEach(i=>console.info(` ${i}`))),console.groupEnd()),l&&typeof l=="function"&&l(o),o}exports.normalizeAnnotation=A;exports.normalizeAnnotationArray=_;exports.normalizeArrow=g;exports.normalizeBaseFields=f;exports.normalizeCircle=h;exports.normalizeColor=c;exports.normalizeCoordinate=d;exports.normalizeHighlight=y;exports.normalizePositiveNumber=F;exports.normalizeText=p;exports.normalizeUnderline=m;
2
2
  //# sourceMappingURL=index9.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index9.cjs","sources":["../src/types/validators.js"],"sourcesContent":["/**\n * Annotation Data Normalization Utilities\n *\n * This module provides defensive normalization functions that validate and fix\n * annotation data. Invalid values are replaced with safe defaults and warnings\n * are collected for user feedback.\n *\n * @module types/validators\n */\n\nimport {\n BASE_DEFAULTS,\n HIGHLIGHT_DEFAULTS,\n TEXT_DEFAULTS,\n UNDERLINE_DEFAULTS,\n ARROW_DEFAULTS,\n CIRCLE_DEFAULTS\n} from './defaults.js';\n\n// ============================================================================\n// FIELD-LEVEL NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize coordinate value to 0-1 range\n *\n * Validates that a value is a number in the 0-1 range. Out-of-range values\n * are clamped. Invalid values use the provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Normalized coordinate value in range [0, 1]\n *\n * @example\n * normalizeCoordinate(0.5, 0.1, 'txt-1', 'x', warnings) // Returns: 0.5\n * normalizeCoordinate(5, 0.1, 'txt-1', 'x', warnings) // Returns: 1, adds warning\n * normalizeCoordinate('abc', 0.1, 'txt-1', 'x', warnings) // Returns: 0.1, adds warning\n */\nexport function normalizeCoordinate(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n if (!isNaN(numValue) && numValue === value) {\n // Successfully parsed - no warning needed\n }\n }\n\n // Validate is valid number\n if (typeof numValue !== 'number' || isNaN(numValue)) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n // Range check: clamp to [0, 1]\n if (numValue < 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} below range [0,1], clamping to 0`\n );\n return 0;\n }\n\n if (numValue > 1) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} exceeds range [0,1], clamping to 1`\n );\n return 1;\n }\n\n // Valid value\n return numValue;\n}\n\n/**\n * Normalize color string\n *\n * Validates that a value is a valid color string. Supports hex, rgb/rgba,\n * and named colors. Invalid colors use the provided default.\n *\n * @param {*} value - Color value to normalize\n * @param {string} defaultValue - Fallback color if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {string} Valid color string\n *\n * @example\n * normalizeColor('#fff', '#000', 'txt-1', warnings) // Returns: '#fff'\n * normalizeColor('rgba(255,0,0,0.5)', '#000', 'txt-1', warnings) // Returns: 'rgba(255,0,0,0.5)'\n * normalizeColor('notacolor', '#000', 'txt-1', warnings) // Returns: '#000', adds warning\n */\nexport function normalizeColor(value, defaultValue, id, warnings) {\n // Type check: must be non-empty string\n if (typeof value !== 'string' || value.trim().length === 0) {\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n const trimmed = value.trim();\n\n // Regex patterns for color validation (cached at module level)\n const hexPattern = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n\n // Named colors (basic set)\n const namedColors = [\n 'red', 'blue', 'green', 'yellow', 'black', 'white', 'gray',\n 'grey', 'orange', 'purple', 'pink', 'brown', 'transparent'\n ];\n\n // Validate format\n const isHex = hexPattern.test(trimmed);\n const isRgb = rgbPattern.test(trimmed);\n const isNamed = namedColors.includes(trimmed.toLowerCase());\n\n if (isHex || isRgb || isNamed) {\n return trimmed;\n }\n\n // Invalid format\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n}\n\n/**\n * Normalize positive number\n *\n * Validates that a value is a positive number. Invalid values use the\n * provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Positive number\n *\n * @example\n * normalizePositiveNumber(5, 3, 'ink-1', 'size', warnings) // Returns: 5\n * normalizePositiveNumber(-1, 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n * normalizePositiveNumber('abc', 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n */\nexport function normalizePositiveNumber(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n }\n\n // Validate is valid number and positive\n if (typeof numValue !== 'number' || isNaN(numValue) || numValue <= 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n return numValue;\n}\n\n// ============================================================================\n// BASE FIELDS NORMALIZER\n// ============================================================================\n\n/**\n * Normalize common base annotation fields\n *\n * Validates and normalizes fields common to all annotation types: id, type,\n * page, start, and end. Auto-generates ID if missing. Applies safe defaults\n * for invalid values.\n *\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Array to collect warning messages\n * @param {Array<string>} info - Array to collect info messages\n * @returns {Object} Object with normalized base fields\n *\n * @example\n * normalizeBaseFields({ type: 'text', page: 2 }, warnings, info)\n * // Returns: { id: 'anno-1234...', type: 'text', page: 2, start: 0, end: 0 }\n */\nexport function normalizeBaseFields(raw, warnings, info) {\n const base = {};\n\n // ===== ID Field =====\n // Check: non-empty string\n // Invalid: auto-generate unique ID\n if (typeof raw.id !== 'string' || raw.id.trim().length === 0) {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n base.id = `anno-${timestamp}-${random}`;\n info.push(`[${base.id}]: Auto-generated ID (original was missing or invalid)`);\n } else {\n base.id = raw.id.trim();\n }\n\n // ===== Type Field =====\n // Pass through as-is (validated in parent function)\n base.type = raw.type;\n\n // ===== Page Field =====\n // Check: positive integer\n // Invalid: default to 1\n if (typeof raw.page !== 'number' || raw.page < 1) {\n warnings.push(\n `[${base.id}]: Field \"page\" invalid value \"${raw.page}\", using default ${BASE_DEFAULTS.page}`\n );\n base.page = BASE_DEFAULTS.page;\n } else {\n // Floor to ensure integer\n base.page = Math.floor(raw.page);\n }\n\n // ===== Start Field =====\n // Check: non-negative number\n // Invalid: default to 0\n if (typeof raw.start !== 'number' || raw.start < 0) {\n warnings.push(\n `[${base.id}]: Field \"start\" invalid value \"${raw.start}\", using default ${BASE_DEFAULTS.start}`\n );\n base.start = BASE_DEFAULTS.start;\n } else {\n base.start = raw.start;\n }\n\n // ===== End Field =====\n // Check: non-negative number >= start\n // Invalid: clamp to start value\n if (typeof raw.end !== 'number' || raw.end < 0) {\n warnings.push(\n `[${base.id}]: Field \"end\" invalid value \"${raw.end}\", using start value ${base.start}`\n );\n base.end = base.start;\n } else if (raw.end < base.start) {\n warnings.push(\n `[${base.id}]: Field \"end\" (${raw.end}) less than start (${base.start}), clamping to start`\n );\n base.end = base.start;\n } else {\n base.end = raw.end;\n }\n\n return base;\n}\n\n// ============================================================================\n// TYPE-SPECIFIC NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize a single quad (rectangular region)\n *\n * @private\n * @param {Object} quad - Quad object with x, y, w, h\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized quad\n */\nfunction normalizeQuad(quad, id, warnings) {\n if (!quad || typeof quad !== 'object') {\n warnings.push(`[${id}]: Invalid quad object, using default`);\n return { x: 0.1, y: 0.1, w: 0.8, h: 0.05 };\n }\n\n return {\n x: normalizeCoordinate(quad.x, 0.1, id, 'quad.x', warnings),\n y: normalizeCoordinate(quad.y, 0.1, id, 'quad.y', warnings),\n w: normalizeCoordinate(quad.w, 0.8, id, 'quad.w', warnings),\n h: normalizeCoordinate(quad.h, 0.05, id, 'quad.h', warnings)\n };\n}\n\n/**\n * Normalize highlight annotation\n *\n * Validates and normalizes highlight-specific fields: mode, quads array,\n * and style.color. Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized highlight annotation\n *\n * @example\n * normalizeHighlight(base, raw, warnings, info)\n * // Returns: { ...base, mode: 'quads', quads: [...], style: {...} }\n */\nexport function normalizeHighlight(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Mode Field =====\n // Check: value equals \"quads\"\n // Invalid: default to \"quads\"\n if (raw.mode !== 'quads') {\n warnings.push(\n `[${base.id}]: Field \"mode\" invalid value \"${raw.mode}\", using default \"${HIGHLIGHT_DEFAULTS.mode}\"`\n );\n annotation.mode = HIGHLIGHT_DEFAULTS.mode;\n } else {\n annotation.mode = raw.mode;\n }\n\n // ===== Quads Array =====\n // Check: non-empty array\n // Invalid: use default quads\n if (!Array.isArray(raw.quads) || raw.quads.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"quads\" missing or empty, using default`\n );\n annotation.quads = HIGHLIGHT_DEFAULTS.quads;\n } else {\n // Normalize each quad\n annotation.quads = raw.quads.map((quad, idx) => normalizeQuad(quad, base.id, warnings));\n }\n\n // ===== Style Object =====\n // Check: object with color property\n const defaultColor = HIGHLIGHT_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using default`\n );\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize text annotation\n *\n * Validates and normalizes text-specific fields: content, position (x, y),\n * dimensions (w, h), and style (bg, color). Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized text annotation\n *\n * @example\n * normalizeText(base, raw, warnings, info)\n * // Returns: { ...base, content: '...', x: 0.1, y: 0.1, w: 0.3, h: 0.1, style: {...} }\n */\nexport function normalizeText(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Content Field =====\n // Check: non-empty string\n // Invalid: default to placeholder\n if (typeof raw.content !== 'string' || raw.content.trim().length === 0) {\n warnings.push(\n `[${base.id}]: Field \"content\" missing or empty, using default \"${TEXT_DEFAULTS.content}\"`\n );\n annotation.content = TEXT_DEFAULTS.content;\n } else {\n annotation.content = raw.content;\n }\n\n // ===== Position Fields (x, y) =====\n annotation.x = normalizeCoordinate(raw.x, TEXT_DEFAULTS.x, base.id, 'x', warnings);\n annotation.y = normalizeCoordinate(raw.y, TEXT_DEFAULTS.y, base.id, 'y', warnings);\n\n // ===== Dimension Fields (w, h) =====\n annotation.w = normalizeCoordinate(raw.w, TEXT_DEFAULTS.w, base.id, 'w', warnings);\n annotation.h = normalizeCoordinate(raw.h, TEXT_DEFAULTS.h, base.id, 'h', warnings);\n\n // ===== Style Object =====\n const defaultBg = TEXT_DEFAULTS.style.bg;\n const defaultColor = TEXT_DEFAULTS.style.color;\n\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using defaults`\n );\n annotation.style = {\n bg: defaultBg,\n color: defaultColor\n };\n } else {\n annotation.style = {\n bg: normalizeColor(raw.style.bg, defaultBg, base.id, warnings),\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize underline annotation\n *\n * Validates and normalizes underline-specific fields: quads array and style.color.\n * Uses same quad structure as highlight for consistency.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized underline annotation\n */\nexport function normalizeUnderline(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Quads Array =====\n if (!Array.isArray(raw.quads) || raw.quads.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"quads\" missing or empty, using default`\n );\n annotation.quads = UNDERLINE_DEFAULTS.quads;\n } else {\n annotation.quads = raw.quads.map((quad) => normalizeQuad(quad, base.id, warnings));\n }\n\n // ===== Style Object =====\n const defaultColor = UNDERLINE_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize arrow annotation\n *\n * Validates and normalizes arrow-specific fields: from_x, from_y, to_x, to_y,\n * and style.color.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized arrow annotation\n */\nexport function normalizeArrow(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Coordinate Fields =====\n annotation.from_x = normalizeCoordinate(raw.from_x, ARROW_DEFAULTS.from_x, base.id, 'from_x', warnings);\n annotation.from_y = normalizeCoordinate(raw.from_y, ARROW_DEFAULTS.from_y, base.id, 'from_y', warnings);\n annotation.to_x = normalizeCoordinate(raw.to_x, ARROW_DEFAULTS.to_x, base.id, 'to_x', warnings);\n annotation.to_y = normalizeCoordinate(raw.to_y, ARROW_DEFAULTS.to_y, base.id, 'to_y', warnings);\n\n // ===== Style Object =====\n const defaultColor = ARROW_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize circle annotation\n *\n * Validates and normalizes circle-specific fields: cx, cy, rx, ry,\n * and style.color.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized circle annotation\n */\nexport function normalizeCircle(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Center and Radii Fields =====\n annotation.cx = normalizeCoordinate(raw.cx, CIRCLE_DEFAULTS.cx, base.id, 'cx', warnings);\n annotation.cy = normalizeCoordinate(raw.cy, CIRCLE_DEFAULTS.cy, base.id, 'cy', warnings);\n annotation.rx = normalizeCoordinate(raw.rx, CIRCLE_DEFAULTS.rx, base.id, 'rx', warnings);\n annotation.ry = normalizeCoordinate(raw.ry, CIRCLE_DEFAULTS.ry, base.id, 'ry', warnings);\n\n // ===== Style Object =====\n const defaultColor = CIRCLE_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n// ============================================================================\n// ORCHESTRATION - SINGLE ANNOTATION & ARRAY\n// ============================================================================\n\n/**\n * Normalize a single annotation\n *\n * Routes annotation to appropriate type-specific normalizer based on type field.\n * Handles critical validation errors (missing/invalid type).\n *\n * @param {Object} raw - Raw annotation object\n * @param {number} index - Position in original array (for error context)\n * @returns {Object} Result object with annotation, warnings, info, and critical error\n * @returns {Object|null} return.annotation - Normalized annotation or null if critical error\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Info messages\n * @returns {string|null} return.critical - Critical error message or null\n *\n * @example\n * normalizeAnnotation({ type: 'text', content: 'Hello' }, 0)\n * // Returns: { annotation: {...}, warnings: [], info: [], critical: null }\n */\nexport function normalizeAnnotation(raw, index) {\n const warnings = [];\n const info = [];\n\n // Validate input is object\n if (!raw || typeof raw !== 'object') {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Not a valid object`\n };\n }\n\n // Check type field (critical - cannot route without type)\n if (typeof raw.type !== 'string' || raw.type.trim().length === 0) {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Missing or invalid type field`\n };\n }\n\n const type = raw.type.trim();\n\n // Normalize base fields first\n const base = normalizeBaseFields(raw, warnings, info);\n\n // Route to type-specific normalizer\n let annotation;\n\n if (type === 'highlight') {\n annotation = normalizeHighlight(base, raw, warnings, info);\n } else if (type === 'text') {\n annotation = normalizeText(base, raw, warnings, info);\n } else if (type === 'underline') {\n annotation = normalizeUnderline(base, raw, warnings, info);\n } else if (type === 'arrow') {\n annotation = normalizeArrow(base, raw, warnings, info);\n } else if (type === 'circle') {\n annotation = normalizeCircle(base, raw, warnings, info);\n } else {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Unsupported type \"${type}\"`\n };\n }\n\n return {\n annotation,\n warnings,\n info,\n critical: null\n };\n}\n\n/**\n * Normalize array of annotations\n *\n * MAIN ENTRY POINT for annotation normalization. Processes each annotation,\n * collects warnings, and returns normalized data ready for rendering.\n *\n * @param {Array} rawAnnotations - Array of raw annotation objects\n * @param {Object} [options] - Configuration options\n * @param {boolean} [options.skipInvalid=true] - Skip critically invalid annotations\n * @param {boolean} [options.warnInConsole=true] - Log warnings to console\n * @param {Function} [options.onWarning] - Custom warning callback\n * @returns {Object} ValidationResult with normalized annotations and messages\n * @returns {Array} return.normalized - Successfully normalized annotations\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Informational messages\n * @returns {Array<Object>} return.skipped - Skipped annotations with reasons\n *\n * @example\n * const result = normalizeAnnotationArray(rawAnnotations, {\n * skipInvalid: true,\n * warnInConsole: true\n * });\n *\n * renderer.setAnnotations(result.normalized);\n */\nexport function normalizeAnnotationArray(rawAnnotations, options = {}) {\n // Default options\n const skipInvalid = options.skipInvalid !== false; // Default: true\n const warnInConsole = options.warnInConsole !== false; // Default: true\n const onWarning = options.onWarning || null;\n\n // Initialize result structure\n const result = {\n normalized: [],\n warnings: [],\n info: [],\n skipped: []\n };\n\n // Validate input is array\n if (!Array.isArray(rawAnnotations)) {\n const warning = 'normalizeAnnotationArray: Input is not an array, returning empty result';\n result.warnings.push(warning);\n\n if (warnInConsole) {\n console.warn(`[Annotation Normalizer] ${warning}`);\n }\n\n return result;\n }\n\n // Process each annotation\n rawAnnotations.forEach((raw, index) => {\n // Skip null/undefined\n if (raw == null) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: 'Annotation is null or undefined'\n });\n return;\n }\n\n // Normalize annotation\n const normalized = normalizeAnnotation(raw, index);\n\n // Check for critical error\n if (normalized.critical) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: normalized.critical\n });\n\n if (warnInConsole) {\n console.error(`[Annotation Normalizer] ${normalized.critical}`);\n }\n\n return;\n }\n\n // Add to normalized array\n result.normalized.push(normalized.annotation);\n\n // Collect warnings and info\n result.warnings.push(...normalized.warnings);\n result.info.push(...normalized.info);\n });\n\n // Console output\n if (warnInConsole) {\n if (result.warnings.length > 0 || result.info.length > 0 || result.skipped.length > 0) {\n console.group('[Annotation Normalizer] Validation Summary');\n\n if (result.normalized.length > 0) {\n console.info(`✓ Normalized ${result.normalized.length} annotation(s)`);\n }\n\n if (result.skipped.length > 0) {\n console.error(`✗ Skipped ${result.skipped.length} annotation(s)`);\n result.skipped.forEach(s => {\n console.error(` Index ${s.index}: ${s.reason}`);\n });\n }\n\n if (result.warnings.length > 0) {\n console.warn(`⚠ ${result.warnings.length} warning(s):`);\n result.warnings.forEach(w => console.warn(` ${w}`));\n }\n\n if (result.info.length > 0) {\n console.info(`ℹ ${result.info.length} info message(s):`);\n result.info.forEach(i => console.info(` ${i}`));\n }\n\n console.groupEnd();\n }\n }\n\n // Call custom warning handler\n if (onWarning && typeof onWarning === 'function') {\n onWarning(result);\n }\n\n return result;\n}\n"],"names":["normalizeCoordinate","value","defaultValue","id","fieldName","warnings","numValue","normalizeColor","trimmed","hexPattern","rgbPattern","namedColors","isHex","isRgb","isNamed","normalizePositiveNumber","normalizeBaseFields","raw","info","base","timestamp","random","BASE_DEFAULTS","normalizeQuad","quad","normalizeHighlight","annotation","HIGHLIGHT_DEFAULTS","idx","defaultColor","normalizeText","TEXT_DEFAULTS","defaultBg","normalizeUnderline","UNDERLINE_DEFAULTS","normalizeArrow","ARROW_DEFAULTS","normalizeCircle","CIRCLE_DEFAULTS","normalizeAnnotation","index","type","normalizeAnnotationArray","rawAnnotations","options","warnInConsole","onWarning","result","warning","normalized","s","w"],"mappings":"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"}
1
+ {"version":3,"file":"index9.cjs","sources":["../src/types/validators.js"],"sourcesContent":["/**\n * Annotation Data Normalization Utilities\n *\n * This module provides defensive normalization functions that validate and fix\n * annotation data. Invalid values are replaced with safe defaults and warnings\n * are collected for user feedback.\n *\n * @module types/validators\n */\n\nimport {\n BASE_DEFAULTS,\n HIGHLIGHT_DEFAULTS,\n TEXT_DEFAULTS,\n UNDERLINE_DEFAULTS,\n ARROW_DEFAULTS,\n CIRCLE_DEFAULTS\n} from './defaults.js';\n\n// ============================================================================\n// FIELD-LEVEL NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize coordinate value to 0-1 range\n *\n * Validates that a value is a number in the 0-1 range. Out-of-range values\n * are clamped. Invalid values use the provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Normalized coordinate value in range [0, 1]\n *\n * @example\n * normalizeCoordinate(0.5, 0.1, 'txt-1', 'x', warnings) // Returns: 0.5\n * normalizeCoordinate(5, 0.1, 'txt-1', 'x', warnings) // Returns: 1, adds warning\n * normalizeCoordinate('abc', 0.1, 'txt-1', 'x', warnings) // Returns: 0.1, adds warning\n */\nexport function normalizeCoordinate(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n if (!isNaN(numValue) && numValue === value) {\n // Successfully parsed - no warning needed\n }\n }\n\n // Validate is valid number\n if (typeof numValue !== 'number' || isNaN(numValue)) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n // Range check: clamp to [0, 1]\n if (numValue < 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} below range [0,1], clamping to 0`\n );\n return 0;\n }\n\n if (numValue > 1) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} exceeds range [0,1], clamping to 1`\n );\n return 1;\n }\n\n // Valid value\n return numValue;\n}\n\n/**\n * Normalize color string\n *\n * Validates that a value is a valid color string. Supports hex, rgb/rgba,\n * and named colors. Invalid colors use the provided default.\n *\n * @param {*} value - Color value to normalize\n * @param {string} defaultValue - Fallback color if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {string} Valid color string\n *\n * @example\n * normalizeColor('#fff', '#000', 'txt-1', warnings) // Returns: '#fff'\n * normalizeColor('rgba(255,0,0,0.5)', '#000', 'txt-1', warnings) // Returns: 'rgba(255,0,0,0.5)'\n * normalizeColor('notacolor', '#000', 'txt-1', warnings) // Returns: '#000', adds warning\n */\nexport function normalizeColor(value, defaultValue, id, warnings) {\n // Type check: must be non-empty string\n if (typeof value !== 'string' || value.trim().length === 0) {\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n const trimmed = value.trim();\n\n // Regex patterns for color validation (cached at module level)\n const hexPattern = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n\n // Named colors (basic set)\n const namedColors = [\n 'red', 'blue', 'green', 'yellow', 'black', 'white', 'gray',\n 'grey', 'orange', 'purple', 'pink', 'brown', 'transparent'\n ];\n\n // Validate format\n const isHex = hexPattern.test(trimmed);\n const isRgb = rgbPattern.test(trimmed);\n const isNamed = namedColors.includes(trimmed.toLowerCase());\n\n if (isHex || isRgb || isNamed) {\n return trimmed;\n }\n\n // Invalid format\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n}\n\n/**\n * Normalize positive number\n *\n * Validates that a value is a positive number. Invalid values use the\n * provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Positive number\n *\n * @example\n * normalizePositiveNumber(5, 3, 'ink-1', 'size', warnings) // Returns: 5\n * normalizePositiveNumber(-1, 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n * normalizePositiveNumber('abc', 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n */\nexport function normalizePositiveNumber(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n }\n\n // Validate is valid number and positive\n if (typeof numValue !== 'number' || isNaN(numValue) || numValue <= 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n return numValue;\n}\n\n// ============================================================================\n// BASE FIELDS NORMALIZER\n// ============================================================================\n\n/**\n * Normalize common base annotation fields\n *\n * Validates and normalizes fields common to all annotation types: id, type,\n * page, start, and end. Auto-generates ID if missing. Applies safe defaults\n * for invalid values.\n *\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Array to collect warning messages\n * @param {Array<string>} info - Array to collect info messages\n * @returns {Object} Object with normalized base fields\n *\n * @example\n * normalizeBaseFields({ type: 'text', page: 2 }, warnings, info)\n * // Returns: { id: 'anno-1234...', type: 'text', page: 2, start: 0, end: 0 }\n */\nexport function normalizeBaseFields(raw, warnings, info) {\n const base = {};\n\n // ===== ID Field =====\n // Check: non-empty string\n // Invalid: auto-generate unique ID\n if (typeof raw.id !== 'string' || raw.id.trim().length === 0) {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n base.id = `anno-${timestamp}-${random}`;\n info.push(`[${base.id}]: Auto-generated ID (original was missing or invalid)`);\n } else {\n base.id = raw.id.trim();\n }\n\n // ===== Type Field =====\n // Pass through as-is (validated in parent function)\n base.type = raw.type;\n\n // ===== Page Field =====\n // Check: positive integer\n // Invalid: default to 1\n if (typeof raw.page !== 'number' || raw.page < 1) {\n warnings.push(\n `[${base.id}]: Field \"page\" invalid value \"${raw.page}\", using default ${BASE_DEFAULTS.page}`\n );\n base.page = BASE_DEFAULTS.page;\n } else {\n // Floor to ensure integer\n base.page = Math.floor(raw.page);\n }\n\n // ===== Start Field =====\n // Check: non-negative number\n // Invalid: default to 0\n if (typeof raw.start !== 'number' || raw.start < 0) {\n warnings.push(\n `[${base.id}]: Field \"start\" invalid value \"${raw.start}\", using default ${BASE_DEFAULTS.start}`\n );\n base.start = BASE_DEFAULTS.start;\n } else {\n base.start = raw.start;\n }\n\n // ===== End Field =====\n // Check: non-negative number >= start\n // Invalid: clamp to start value\n if (typeof raw.end !== 'number' || raw.end < 0) {\n warnings.push(\n `[${base.id}]: Field \"end\" invalid value \"${raw.end}\", using start value ${base.start}`\n );\n base.end = base.start;\n } else if (raw.end < base.start) {\n warnings.push(\n `[${base.id}]: Field \"end\" (${raw.end}) less than start (${base.start}), clamping to start`\n );\n base.end = base.start;\n } else {\n base.end = raw.end;\n }\n\n return base;\n}\n\n// ============================================================================\n// TYPE-SPECIFIC NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize a single quad (rectangular region)\n *\n * @private\n * @param {Object} quad - Quad object with x, y, w, h\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized quad\n */\nfunction normalizeQuad(quad, id, warnings) {\n if (!quad || typeof quad !== 'object') {\n warnings.push(`[${id}]: Invalid quad object, using default`);\n return { x: 0.1, y: 0.1, w: 0.8, h: 0.05 };\n }\n\n return {\n x: normalizeCoordinate(quad.x, 0.1, id, 'quad.x', warnings),\n y: normalizeCoordinate(quad.y, 0.1, id, 'quad.y', warnings),\n w: normalizeCoordinate(quad.w, 0.8, id, 'quad.w', warnings),\n h: normalizeCoordinate(quad.h, 0.05, id, 'quad.h', warnings)\n };\n}\n\n/**\n * Normalize highlight annotation\n *\n * Validates and normalizes highlight-specific fields: mode, quads array,\n * and style.color. Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized highlight annotation\n *\n * @example\n * normalizeHighlight(base, raw, warnings, info)\n * // Returns: { ...base, mode: 'quads', quads: [...], style: {...} }\n */\nexport function normalizeHighlight(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Mode Field =====\n // Check: value equals \"quads\"\n // Invalid: default to \"quads\"\n if (raw.mode !== 'quads') {\n warnings.push(\n `[${base.id}]: Field \"mode\" invalid value \"${raw.mode}\", using default \"${HIGHLIGHT_DEFAULTS.mode}\"`\n );\n annotation.mode = HIGHLIGHT_DEFAULTS.mode;\n } else {\n annotation.mode = raw.mode;\n }\n\n // ===== Quads Array =====\n // Check: non-empty array\n // Invalid: use default quads\n if (!Array.isArray(raw.quads) || raw.quads.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"quads\" missing or empty, using default`\n );\n annotation.quads = HIGHLIGHT_DEFAULTS.quads;\n } else {\n // Normalize each quad\n annotation.quads = raw.quads.map((quad, idx) => normalizeQuad(quad, base.id, warnings));\n }\n\n // ===== Style Object =====\n // Check: object with color property\n const defaultColor = HIGHLIGHT_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using default`\n );\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize text annotation\n *\n * Validates and normalizes text-specific fields: content, position (x, y),\n * dimensions (w, h), and style (bg, color). Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized text annotation\n *\n * @example\n * normalizeText(base, raw, warnings, info)\n * // Returns: { ...base, content: '...', x: 0.1, y: 0.1, w: 0.3, h: 0.1, style: {...} }\n */\nexport function normalizeText(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Content Field =====\n // Check: non-empty string\n // Invalid: default to placeholder\n if (typeof raw.content !== 'string' || raw.content.trim().length === 0) {\n warnings.push(\n `[${base.id}]: Field \"content\" missing or empty, using default \"${TEXT_DEFAULTS.content}\"`\n );\n annotation.content = TEXT_DEFAULTS.content;\n } else {\n annotation.content = raw.content;\n }\n\n // ===== Position Fields (x, y) =====\n annotation.x = normalizeCoordinate(raw.x, TEXT_DEFAULTS.x, base.id, 'x', warnings);\n annotation.y = normalizeCoordinate(raw.y, TEXT_DEFAULTS.y, base.id, 'y', warnings);\n\n // ===== Dimension Fields (w, h) =====\n annotation.w = normalizeCoordinate(raw.w, TEXT_DEFAULTS.w, base.id, 'w', warnings);\n annotation.h = normalizeCoordinate(raw.h, TEXT_DEFAULTS.h, base.id, 'h', warnings);\n\n // ===== Style Object =====\n const defaultBg = TEXT_DEFAULTS.style.bg;\n const defaultColor = TEXT_DEFAULTS.style.color;\n\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using defaults`\n );\n annotation.style = {\n bg: defaultBg,\n color: defaultColor\n };\n } else {\n annotation.style = {\n bg: normalizeColor(raw.style.bg, defaultBg, base.id, warnings),\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize underline annotation\n *\n * Validates and normalizes underline-specific fields: quads array and style.color.\n * Uses same quad structure as highlight for consistency.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized underline annotation\n */\nexport function normalizeUnderline(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Quads Array =====\n if (!Array.isArray(raw.quads) || raw.quads.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"quads\" missing or empty, using default`\n );\n annotation.quads = UNDERLINE_DEFAULTS.quads;\n } else {\n annotation.quads = raw.quads.map((quad) => normalizeQuad(quad, base.id, warnings));\n }\n\n // ===== Style Object =====\n const defaultColor = UNDERLINE_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize arrow annotation\n *\n * Validates and normalizes arrow-specific fields: from_x, from_y, to_x, to_y,\n * and style.color.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized arrow annotation\n */\nexport function normalizeArrow(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Coordinate Fields =====\n annotation.from_x = normalizeCoordinate(raw.from_x, ARROW_DEFAULTS.from_x, base.id, 'from_x', warnings);\n annotation.from_y = normalizeCoordinate(raw.from_y, ARROW_DEFAULTS.from_y, base.id, 'from_y', warnings);\n annotation.to_x = normalizeCoordinate(raw.to_x, ARROW_DEFAULTS.to_x, base.id, 'to_x', warnings);\n annotation.to_y = normalizeCoordinate(raw.to_y, ARROW_DEFAULTS.to_y, base.id, 'to_y', warnings);\n\n // ===== Style Object =====\n const defaultColor = ARROW_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize circle annotation\n *\n * Validates and normalizes circle-specific fields: cx, cy, rx, ry,\n * and style.color.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized circle annotation\n */\nexport function normalizeCircle(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Center and Radii Fields =====\n annotation.cx = normalizeCoordinate(raw.cx, CIRCLE_DEFAULTS.cx, base.id, 'cx', warnings);\n annotation.cy = normalizeCoordinate(raw.cy, CIRCLE_DEFAULTS.cy, base.id, 'cy', warnings);\n annotation.rx = normalizeCoordinate(raw.rx, CIRCLE_DEFAULTS.rx, base.id, 'rx', warnings);\n annotation.ry = normalizeCoordinate(raw.ry, CIRCLE_DEFAULTS.ry, base.id, 'ry', warnings);\n\n // ===== Style Object =====\n const defaultColor = CIRCLE_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n// ============================================================================\n// ORCHESTRATION - SINGLE ANNOTATION & ARRAY\n// ============================================================================\n\n/**\n * Normalize a single annotation\n *\n * Routes annotation to appropriate type-specific normalizer based on type field.\n * Handles critical validation errors (missing/invalid type).\n *\n * @param {Object} raw - Raw annotation object\n * @param {number} index - Position in original array (for error context)\n * @returns {Object} Result object with annotation, warnings, info, and critical error\n * @returns {Object|null} return.annotation - Normalized annotation or null if critical error\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Info messages\n * @returns {string|null} return.critical - Critical error message or null\n *\n * @example\n * normalizeAnnotation({ type: 'text', content: 'Hello' }, 0)\n * // Returns: { annotation: {...}, warnings: [], info: [], critical: null }\n */\nexport function normalizeAnnotation(raw, index) {\n const warnings = [];\n const info = [];\n\n // Validate input is object\n if (!raw || typeof raw !== 'object') {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Not a valid object`\n };\n }\n\n // Check type field (critical - cannot route without type)\n if (typeof raw.type !== 'string' || raw.type.trim().length === 0) {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Missing or invalid type field`\n };\n }\n\n const type = raw.type.trim();\n\n // Normalize base fields first\n const base = normalizeBaseFields(raw, warnings, info);\n\n // Route to type-specific normalizer\n let annotation;\n\n if (type === 'highlight') {\n annotation = normalizeHighlight(base, raw, warnings, info);\n } else if (type === 'text') {\n annotation = normalizeText(base, raw, warnings, info);\n } else if (type === 'underline') {\n annotation = normalizeUnderline(base, raw, warnings, info);\n } else if (type === 'arrow') {\n annotation = normalizeArrow(base, raw, warnings, info);\n } else if (type === 'circle') {\n annotation = normalizeCircle(base, raw, warnings, info);\n } else if (type === 'ink') {\n annotation = { ...base, strokes: raw.strokes || [] };\n if (raw.style) annotation.style = raw.style;\n } else {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Unsupported type \"${type}\"`\n };\n }\n\n return {\n annotation,\n warnings,\n info,\n critical: null\n };\n}\n\n/**\n * Normalize array of annotations\n *\n * MAIN ENTRY POINT for annotation normalization. Processes each annotation,\n * collects warnings, and returns normalized data ready for rendering.\n *\n * @param {Array} rawAnnotations - Array of raw annotation objects\n * @param {Object} [options] - Configuration options\n * @param {boolean} [options.skipInvalid=true] - Skip critically invalid annotations\n * @param {boolean} [options.warnInConsole=true] - Log warnings to console\n * @param {Function} [options.onWarning] - Custom warning callback\n * @returns {Object} ValidationResult with normalized annotations and messages\n * @returns {Array} return.normalized - Successfully normalized annotations\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Informational messages\n * @returns {Array<Object>} return.skipped - Skipped annotations with reasons\n *\n * @example\n * const result = normalizeAnnotationArray(rawAnnotations, {\n * skipInvalid: true,\n * warnInConsole: true\n * });\n *\n * renderer.setAnnotations(result.normalized);\n */\nexport function normalizeAnnotationArray(rawAnnotations, options = {}) {\n // Default options\n const skipInvalid = options.skipInvalid !== false; // Default: true\n const warnInConsole = options.warnInConsole !== false; // Default: true\n const onWarning = options.onWarning || null;\n\n // Initialize result structure\n const result = {\n normalized: [],\n warnings: [],\n info: [],\n skipped: []\n };\n\n // Validate input is array\n if (!Array.isArray(rawAnnotations)) {\n const warning = 'normalizeAnnotationArray: Input is not an array, returning empty result';\n result.warnings.push(warning);\n\n if (warnInConsole) {\n console.warn(`[Annotation Normalizer] ${warning}`);\n }\n\n return result;\n }\n\n // Process each annotation\n rawAnnotations.forEach((raw, index) => {\n // Skip null/undefined\n if (raw == null) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: 'Annotation is null or undefined'\n });\n return;\n }\n\n // Normalize annotation\n const normalized = normalizeAnnotation(raw, index);\n\n // Check for critical error\n if (normalized.critical) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: normalized.critical\n });\n\n if (warnInConsole) {\n console.error(`[Annotation Normalizer] ${normalized.critical}`);\n }\n\n return;\n }\n\n // Add to normalized array\n result.normalized.push(normalized.annotation);\n\n // Collect warnings and info\n result.warnings.push(...normalized.warnings);\n result.info.push(...normalized.info);\n });\n\n // Console output\n if (warnInConsole) {\n if (result.warnings.length > 0 || result.info.length > 0 || result.skipped.length > 0) {\n console.group('[Annotation Normalizer] Validation Summary');\n\n if (result.normalized.length > 0) {\n console.info(`✓ Normalized ${result.normalized.length} annotation(s)`);\n }\n\n if (result.skipped.length > 0) {\n console.error(`✗ Skipped ${result.skipped.length} annotation(s)`);\n result.skipped.forEach(s => {\n console.error(` Index ${s.index}: ${s.reason}`);\n });\n }\n\n if (result.warnings.length > 0) {\n console.warn(`⚠ ${result.warnings.length} warning(s):`);\n result.warnings.forEach(w => console.warn(` ${w}`));\n }\n\n if (result.info.length > 0) {\n console.info(`ℹ ${result.info.length} info message(s):`);\n result.info.forEach(i => console.info(` ${i}`));\n }\n\n console.groupEnd();\n }\n }\n\n // Call custom warning handler\n if (onWarning && typeof onWarning === 'function') {\n onWarning(result);\n }\n\n return result;\n}\n"],"names":["normalizeCoordinate","value","defaultValue","id","fieldName","warnings","numValue","normalizeColor","trimmed","hexPattern","rgbPattern","namedColors","isHex","isRgb","isNamed","normalizePositiveNumber","normalizeBaseFields","raw","info","base","timestamp","random","BASE_DEFAULTS","normalizeQuad","quad","normalizeHighlight","annotation","HIGHLIGHT_DEFAULTS","idx","defaultColor","normalizeText","TEXT_DEFAULTS","defaultBg","normalizeUnderline","UNDERLINE_DEFAULTS","normalizeArrow","ARROW_DEFAULTS","normalizeCircle","CIRCLE_DEFAULTS","normalizeAnnotation","index","type","normalizeAnnotationArray","rawAnnotations","options","warnInConsole","onWarning","result","warning","normalized","s","w"],"mappings":"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"}
package/dist/index9.js CHANGED
@@ -1,4 +1,4 @@
1
- import { HIGHLIGHT_DEFAULTS as a, TEXT_DEFAULTS as u, BASE_DEFAULTS as p, UNDERLINE_DEFAULTS as m, ARROW_DEFAULTS as f, CIRCLE_DEFAULTS as y } from "./index25.js";
1
+ import { HIGHLIGHT_DEFAULTS as a, TEXT_DEFAULTS as u, BASE_DEFAULTS as p, UNDERLINE_DEFAULTS as m, ARROW_DEFAULTS as c, CIRCLE_DEFAULTS as y } from "./index26.js";
2
2
  function r(t, n, e, l, o) {
3
3
  let i = t;
4
4
  return typeof t == "string" && (i = parseFloat(t)), typeof i != "number" || isNaN(i) ? (o.push(
@@ -9,7 +9,7 @@ function r(t, n, e, l, o) {
9
9
  `[${e}]: Field "${l}" value ${i} exceeds range [0,1], clamping to 1`
10
10
  ), 1) : i;
11
11
  }
12
- function c(t, n, e, l) {
12
+ function f(t, n, e, l) {
13
13
  if (typeof t != "string" || t.trim().length === 0)
14
14
  return l.push(
15
15
  `[${e}]: Invalid color format "${t}", using default ${n}`
@@ -33,7 +33,7 @@ function c(t, n, e, l) {
33
33
  `[${e}]: Invalid color format "${t}", using default ${n}`
34
34
  ), n);
35
35
  }
36
- function I(t, n, e, l, o) {
36
+ function C(t, n, e, l, o) {
37
37
  let i = t;
38
38
  return typeof t == "string" && (i = parseFloat(t)), typeof i != "number" || isNaN(i) || i <= 0 ? (o.push(
39
39
  `[${e}]: Field "${l}" invalid value "${t}", using default ${n}`
@@ -75,7 +75,7 @@ function F(t, n, e, l) {
75
75
  return !n.style || typeof n.style != "object" ? (e.push(
76
76
  `[${t.id}]: Field "style" missing or invalid, using default`
77
77
  ), o.style = { color: i }) : o.style = {
78
- color: c(n.style.color, i, t.id, e)
78
+ color: f(n.style.color, i, t.id, e)
79
79
  }, o;
80
80
  }
81
81
  function z(t, n, e, l) {
@@ -90,8 +90,8 @@ function z(t, n, e, l) {
90
90
  bg: i,
91
91
  color: s
92
92
  }) : o.style = {
93
- bg: c(n.style.bg, i, t.id, e),
94
- color: c(n.style.color, s, t.id, e)
93
+ bg: f(n.style.bg, i, t.id, e),
94
+ color: f(n.style.color, s, t.id, e)
95
95
  }, o;
96
96
  }
97
97
  function _(t, n, e, l) {
@@ -101,15 +101,15 @@ function _(t, n, e, l) {
101
101
  ), o.quads = m.quads) : o.quads = n.quads.map((s) => g(s, t.id, e));
102
102
  const i = m.style.color;
103
103
  return !n.style || typeof n.style != "object" ? o.style = { color: i } : o.style = {
104
- color: c(n.style.color, i, t.id, e)
104
+ color: f(n.style.color, i, t.id, e)
105
105
  }, o;
106
106
  }
107
107
  function E(t, n, e, l) {
108
108
  const o = { ...t };
109
- o.from_x = r(n.from_x, f.from_x, t.id, "from_x", e), o.from_y = r(n.from_y, f.from_y, t.id, "from_y", e), o.to_x = r(n.to_x, f.to_x, t.id, "to_x", e), o.to_y = r(n.to_y, f.to_y, t.id, "to_y", e);
110
- const i = f.style.color;
109
+ o.from_x = r(n.from_x, c.from_x, t.id, "from_x", e), o.from_y = r(n.from_y, c.from_y, t.id, "from_y", e), o.to_x = r(n.to_x, c.to_x, t.id, "to_x", e), o.to_y = r(n.to_y, c.to_y, t.id, "to_y", e);
110
+ const i = c.style.color;
111
111
  return !n.style || typeof n.style != "object" ? o.style = { color: i } : o.style = {
112
- color: c(n.style.color, i, t.id, e)
112
+ color: f(n.style.color, i, t.id, e)
113
113
  }, o;
114
114
  }
115
115
  function q(t, n, e, l) {
@@ -117,7 +117,7 @@ function q(t, n, e, l) {
117
117
  o.cx = r(n.cx, y.cx, t.id, "cx", e), o.cy = r(n.cy, y.cy, t.id, "cy", e), o.rx = r(n.rx, y.rx, t.id, "rx", e), o.ry = r(n.ry, y.ry, t.id, "ry", e);
118
118
  const i = y.style.color;
119
119
  return !n.style || typeof n.style != "object" ? o.style = { color: i } : o.style = {
120
- color: c(n.style.color, i, t.id, e)
120
+ color: f(n.style.color, i, t.id, e)
121
121
  }, o;
122
122
  }
123
123
  function v(t, n) {
@@ -148,6 +148,8 @@ function v(t, n) {
148
148
  s = E(i, t, e);
149
149
  else if (o === "circle")
150
150
  s = q(i, t, e);
151
+ else if (o === "ink")
152
+ s = { ...i, strokes: t.strokes || [] }, t.style && (s.style = t.style);
151
153
  else
152
154
  return {
153
155
  annotation: null,
@@ -162,7 +164,7 @@ function v(t, n) {
162
164
  critical: null
163
165
  };
164
166
  }
165
- function k(t, n = {}) {
167
+ function I(t, n = {}) {
166
168
  n.skipInvalid;
167
169
  const e = n.warnInConsole !== !1, l = n.onWarning || null, o = {
168
170
  normalized: [],
@@ -199,14 +201,14 @@ function k(t, n = {}) {
199
201
  }
200
202
  export {
201
203
  v as normalizeAnnotation,
202
- k as normalizeAnnotationArray,
204
+ I as normalizeAnnotationArray,
203
205
  E as normalizeArrow,
204
206
  A as normalizeBaseFields,
205
207
  q as normalizeCircle,
206
- c as normalizeColor,
208
+ f as normalizeColor,
207
209
  r as normalizeCoordinate,
208
210
  F as normalizeHighlight,
209
- I as normalizePositiveNumber,
211
+ C as normalizePositiveNumber,
210
212
  z as normalizeText,
211
213
  _ as normalizeUnderline
212
214
  };