web-annotation-renderer 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +49 -42
- package/dist/index.js.map +1 -1
- package/dist/index10.cjs +1 -1
- package/dist/index10.cjs.map +1 -1
- package/dist/index10.js +172 -17
- package/dist/index10.js.map +1 -1
- package/dist/index11.cjs +1 -1
- package/dist/index11.cjs.map +1 -1
- package/dist/index11.js +13 -20
- package/dist/index11.js.map +1 -1
- package/dist/index12.cjs +1 -1
- package/dist/index12.cjs.map +1 -1
- package/dist/index12.js +167 -124
- package/dist/index12.js.map +1 -1
- package/dist/index13.cjs +1 -1
- package/dist/index13.cjs.map +1 -1
- package/dist/index13.js +29 -198
- package/dist/index13.js.map +1 -1
- package/dist/index14.cjs +1 -1
- package/dist/index14.cjs.map +1 -1
- package/dist/index14.js +78 -15
- package/dist/index14.js.map +1 -1
- package/dist/index15.cjs +1 -1
- package/dist/index15.cjs.map +1 -1
- package/dist/index15.js +115 -120
- package/dist/index15.js.map +1 -1
- package/dist/index16.cjs +1 -1
- package/dist/index16.cjs.map +1 -1
- package/dist/index16.js +100 -212
- package/dist/index16.js.map +1 -1
- package/dist/index17.cjs +1 -1
- package/dist/index17.cjs.map +1 -1
- package/dist/index17.js +55 -37
- package/dist/index17.js.map +1 -1
- package/dist/index18.cjs +1 -1
- package/dist/index18.cjs.map +1 -1
- package/dist/index18.js +139 -35
- package/dist/index18.js.map +1 -1
- package/dist/index19.cjs +1 -1
- package/dist/index19.cjs.map +1 -1
- package/dist/index19.js +37 -37
- package/dist/index19.js.map +1 -1
- package/dist/index2.cjs +1 -1
- package/dist/index2.cjs.map +1 -1
- package/dist/index2.js +95 -73
- package/dist/index2.js.map +1 -1
- package/dist/index20.cjs +1 -1
- package/dist/index20.cjs.map +1 -1
- package/dist/index20.js +29 -39
- package/dist/index20.js.map +1 -1
- package/dist/index21.cjs +1 -1
- package/dist/index21.cjs.map +1 -1
- package/dist/index21.js +38 -32
- package/dist/index21.js.map +1 -1
- package/dist/index22.cjs +1 -1
- package/dist/index22.cjs.map +1 -1
- package/dist/index22.js +22 -5
- package/dist/index22.js.map +1 -1
- package/dist/index23.cjs +2 -0
- package/dist/index23.cjs.map +1 -0
- package/dist/index23.js +8 -0
- package/dist/index23.js.map +1 -0
- package/dist/index24.cjs +2 -0
- package/dist/index24.cjs.map +1 -0
- package/dist/index24.js +8 -0
- package/dist/index24.js.map +1 -0
- package/dist/index3.cjs +1 -1
- package/dist/index3.cjs.map +1 -1
- package/dist/index3.js +1 -1
- package/dist/index4.cjs +1 -1
- package/dist/index4.cjs.map +1 -1
- package/dist/index4.js +72 -71
- package/dist/index4.js.map +1 -1
- package/dist/index5.cjs +1 -1
- package/dist/index5.cjs.map +1 -1
- package/dist/index5.js +217 -65
- package/dist/index5.js.map +1 -1
- package/dist/index6.cjs +1 -1
- package/dist/index6.cjs.map +1 -1
- package/dist/index6.js +60 -114
- package/dist/index6.js.map +1 -1
- package/dist/index7.cjs +1 -1
- package/dist/index7.cjs.map +1 -1
- package/dist/index7.js +19 -91
- package/dist/index7.js.map +1 -1
- package/dist/index8.cjs +1 -1
- package/dist/index8.cjs.map +1 -1
- package/dist/index8.js +19 -105
- package/dist/index8.js.map +1 -1
- package/dist/index9.cjs +1 -1
- package/dist/index9.cjs.map +1 -1
- package/dist/index9.js +123 -98
- package/dist/index9.js.map +1 -1
- package/package.json +4 -3
package/dist/index13.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index13.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 INK_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 a single ink point\n *\n * @private\n * @param {Object} point - Point object with t, x, y\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized point\n */\nfunction normalizePoint(point, id, warnings) {\n if (!point || typeof point !== 'object') {\n warnings.push(`[${id}]: Invalid point object, using default`);\n return { t: 0, x: 0.1, y: 0.1 };\n }\n\n return {\n t: normalizeCoordinate(point.t, 0, id, 'point.t', warnings),\n x: normalizeCoordinate(point.x, 0.1, id, 'point.x', warnings),\n y: normalizeCoordinate(point.y, 0.1, id, 'point.y', warnings)\n };\n}\n\n/**\n * Normalize a single ink stroke\n *\n * @private\n * @param {Object} stroke - Stroke object with color, size, points\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized stroke\n */\nfunction normalizeStroke(stroke, id, warnings) {\n if (!stroke || typeof stroke !== 'object') {\n warnings.push(`[${id}]: Invalid stroke object, using default`);\n return INK_DEFAULTS.strokes[0];\n }\n\n const normalized = {\n color: normalizeColor(stroke.color, INK_DEFAULTS.strokes[0].color, id, warnings),\n size: normalizePositiveNumber(stroke.size, INK_DEFAULTS.strokes[0].size, id, 'stroke.size', warnings)\n };\n\n // ===== Points Array =====\n if (!Array.isArray(stroke.points) || stroke.points.length === 0) {\n warnings.push(`[${id}]: Stroke missing points array, using default`);\n normalized.points = INK_DEFAULTS.strokes[0].points;\n } else {\n normalized.points = stroke.points.map(point => normalizePoint(point, id, warnings));\n }\n\n return normalized;\n}\n\n/**\n * Normalize ink annotation\n *\n * Validates and normalizes ink-specific fields: strokes array with color,\n * size, and points. 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 ink annotation\n *\n * @example\n * normalizeInk(base, raw, warnings, info)\n * // Returns: { ...base, strokes: [{ color: '...', size: 3, points: [...] }] }\n */\nexport function normalizeInk(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Strokes Array =====\n // Check: non-empty array\n // Invalid: use default single stroke\n if (!Array.isArray(raw.strokes) || raw.strokes.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"strokes\" missing or empty, using default`\n );\n annotation.strokes = INK_DEFAULTS.strokes;\n } else {\n // Normalize each stroke\n annotation.strokes = raw.strokes.map(stroke => normalizeStroke(stroke, base.id, warnings));\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 === 'ink') {\n annotation = normalizeInk(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","normalizePoint","point","normalizeStroke","stroke","INK_DEFAULTS","normalized","normalizeInk","normalizeAnnotation","index","type","normalizeAnnotationArray","rawAnnotations","options","warnInConsole","onWarning","result","warning","s","w"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index13.cjs","sources":["../src/converters/highlight.js"],"sourcesContent":["/**\n * Highlight Converter - Converts highlight annotations to stroke commands\n *\n * Transforms rectangular quads into horizontal stroke paths that can be\n * rendered progressively on canvas.\n *\n * @module converters/highlight\n */\n\nimport { applyJitter, applyPressure } from '../pen/effects.js';\n\n/**\n * Converts a highlight annotation to stroke commands\n *\n * Each quad in the annotation becomes a horizontal stroke at the\n * vertical center of the quad. Multiple quads are staggered in timing.\n *\n * @param {Object} annotation - Highlight annotation object\n * @param {string} annotation.id - Unique identifier\n * @param {number} annotation.start - Start time in seconds\n * @param {number} annotation.end - End time in seconds\n * @param {Array<{x: number, y: number, w: number, h: number}>} annotation.quads - Array of quads\n * @param {Object} [annotation.style] - Optional style overrides\n * @param {Object} style - Resolved style configuration\n * @param {string} style.color - Stroke color\n * @param {number} style.width - Stroke width in pixels\n * @param {string} [style.lineCap='butt'] - Line cap style\n * @param {Object} [style.jitter] - Jitter configuration\n * @param {Object} [style.pressure] - Pressure configuration\n * @returns {Array<Object>} Array of stroke commands\n */\nexport function highlightToStrokes(annotation, style) {\n const { id, start, end, quads } = annotation;\n\n if (!quads || quads.length === 0) {\n return [];\n }\n\n const strokes = [];\n const totalDuration = end - start;\n const quadCount = quads.length;\n\n // Calculate timing for each quad (staggered)\n const quadDuration = totalDuration / quadCount;\n\n for (let i = 0; i < quads.length; i++) {\n const quad = quads[i];\n const { x, y, w, h } = quad;\n\n // Calculate center-line Y position\n const yCenter = y + h / 2;\n\n // Create stroke points (left to right horizontal line)\n let points = [\n [x, yCenter],\n [x + w, yCenter]\n ];\n\n // Apply jitter if configured\n if (style.jitter?.amplitude > 0) {\n points = applyJitter(points, style.jitter, `${id}-${i}`);\n }\n\n // Calculate pressure values if configured\n let pressures = null;\n if (style.pressure?.taperIn > 0 || style.pressure?.taperOut > 0) {\n pressures = applyPressure(points, style.pressure);\n }\n\n // Calculate timing for this quad\n const quadStart = start + i * quadDuration;\n const quadEnd = quadStart + quadDuration;\n\n strokes.push({\n id: `${id}-${i}`,\n points,\n start: quadStart,\n end: quadEnd,\n color: style.color || 'rgba(255, 255, 0, 0.3)',\n width: style.width || 24,\n lineCap: style.lineCap || 'butt',\n pressures\n });\n }\n\n return strokes;\n}\n\nexport default highlightToStrokes;\n"],"names":["highlightToStrokes","annotation","style","id","start","end","quads","strokes","totalDuration","quadCount","quadDuration","i","quad","x","y","w","h","yCenter","points","applyJitter","pressures","applyPressure","quadStart","quadEnd"],"mappings":"4IA+BO,SAASA,EAAmBC,EAAYC,EAAO,CACpD,KAAM,CAAE,GAAAC,EAAI,MAAAC,EAAO,IAAAC,EAAK,MAAAC,CAAK,EAAKL,EAElC,GAAI,CAACK,GAASA,EAAM,SAAW,EAC7B,MAAO,CAAA,EAGT,MAAMC,EAAU,CAAA,EACVC,EAAgBH,EAAMD,EACtBK,EAAYH,EAAM,OAGlBI,EAAeF,EAAgBC,EAErC,QAASE,EAAI,EAAGA,EAAIL,EAAM,OAAQK,IAAK,CACrC,MAAMC,EAAON,EAAMK,CAAC,EACd,CAAE,EAAAE,EAAG,EAAAC,EAAG,EAAAC,EAAG,EAAAC,CAAC,EAAKJ,EAGjBK,EAAUH,EAAIE,EAAI,EAGxB,IAAIE,EAAS,CACX,CAACL,EAAGI,CAAO,EACX,CAACJ,EAAIE,EAAGE,CAAO,CACrB,EAGQf,EAAM,QAAQ,UAAY,IAC5BgB,EAASC,EAAAA,YAAYD,EAAQhB,EAAM,OAAQ,GAAGC,CAAE,IAAIQ,CAAC,EAAE,GAIzD,IAAIS,EAAY,MACZlB,EAAM,UAAU,QAAU,GAAKA,EAAM,UAAU,SAAW,KAC5DkB,EAAYC,EAAAA,cAAcH,EAAQhB,EAAM,QAAQ,GAIlD,MAAMoB,EAAYlB,EAAQO,EAAID,EACxBa,EAAUD,EAAYZ,EAE5BH,EAAQ,KAAK,CACX,GAAI,GAAGJ,CAAE,IAAIQ,CAAC,GACd,OAAAO,EACA,MAAOI,EACP,IAAKC,EACL,MAAOrB,EAAM,OAAS,yBACtB,MAAOA,EAAM,OAAS,GACtB,QAASA,EAAM,SAAW,OAC1B,UAAAkB,CACN,CAAK,CACH,CAEA,OAAOb,CACT"}
|
package/dist/index13.js
CHANGED
|
@@ -1,203 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"purple",
|
|
28
|
-
"pink",
|
|
29
|
-
"brown",
|
|
30
|
-
"transparent"
|
|
31
|
-
], m = i.test(e), y = l.test(e), g = u.includes(e.toLowerCase());
|
|
32
|
-
return m || y || g ? e : (s.push(
|
|
33
|
-
`[${o}]: Invalid color format "${t}", using default ${n}`
|
|
34
|
-
), n);
|
|
35
|
-
}
|
|
36
|
-
function h(t, n, o, s, e) {
|
|
37
|
-
let i = t;
|
|
38
|
-
return typeof t == "string" && (i = parseFloat(t)), typeof i != "number" || isNaN(i) || i <= 0 ? (e.push(
|
|
39
|
-
`[${o}]: Field "${s}" invalid value "${t}", using default ${n}`
|
|
40
|
-
), n) : i;
|
|
41
|
-
}
|
|
42
|
-
function $(t, n, o) {
|
|
43
|
-
const s = {};
|
|
44
|
-
if (typeof t.id != "string" || t.id.trim().length === 0) {
|
|
45
|
-
const e = Date.now(), i = Math.random().toString(36).substr(2, 9);
|
|
46
|
-
s.id = `anno-${e}-${i}`, o.push(`[${s.id}]: Auto-generated ID (original was missing or invalid)`);
|
|
47
|
-
} else
|
|
48
|
-
s.id = t.id.trim();
|
|
49
|
-
return s.type = t.type, typeof t.page != "number" || t.page < 1 ? (n.push(
|
|
50
|
-
`[${s.id}]: Field "page" invalid value "${t.page}", using default ${p.page}`
|
|
51
|
-
), s.page = p.page) : s.page = Math.floor(t.page), typeof t.start != "number" || t.start < 0 ? (n.push(
|
|
52
|
-
`[${s.id}]: Field "start" invalid value "${t.start}", using default ${p.start}`
|
|
53
|
-
), s.start = p.start) : s.start = t.start, typeof t.end != "number" || t.end < 0 ? (n.push(
|
|
54
|
-
`[${s.id}]: Field "end" invalid value "${t.end}", using start value ${s.start}`
|
|
55
|
-
), s.end = s.start) : t.end < s.start ? (n.push(
|
|
56
|
-
`[${s.id}]: Field "end" (${t.end}) less than start (${s.start}), clamping to start`
|
|
57
|
-
), s.end = s.start) : s.end = t.end, s;
|
|
58
|
-
}
|
|
59
|
-
function z(t, n, o) {
|
|
60
|
-
return !t || typeof t != "object" ? (o.push(`[${n}]: Invalid quad object, using default`), { x: 0.1, y: 0.1, w: 0.8, h: 0.05 }) : {
|
|
61
|
-
x: r(t.x, 0.1, n, "quad.x", o),
|
|
62
|
-
y: r(t.y, 0.1, n, "quad.y", o),
|
|
63
|
-
w: r(t.w, 0.8, n, "quad.w", o),
|
|
64
|
-
h: r(t.h, 0.05, n, "quad.h", o)
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function A(t, n, o, s) {
|
|
68
|
-
const e = { ...t };
|
|
69
|
-
n.mode !== "quads" ? (o.push(
|
|
70
|
-
`[${t.id}]: Field "mode" invalid value "${n.mode}", using default "${f.mode}"`
|
|
71
|
-
), e.mode = f.mode) : e.mode = n.mode, !Array.isArray(n.quads) || n.quads.length === 0 ? (o.push(
|
|
72
|
-
`[${t.id}]: Field "quads" missing or empty, using default`
|
|
73
|
-
), e.quads = f.quads) : e.quads = n.quads.map((l, u) => z(l, t.id, o));
|
|
74
|
-
const i = f.style.color;
|
|
75
|
-
return !n.style || typeof n.style != "object" ? (o.push(
|
|
76
|
-
`[${t.id}]: Field "style" missing or invalid, using default`
|
|
77
|
-
), e.style = { color: i }) : e.style = {
|
|
78
|
-
color: c(n.style.color, i, t.id, o)
|
|
79
|
-
}, e;
|
|
80
|
-
}
|
|
81
|
-
function F(t, n, o, s) {
|
|
82
|
-
const e = { ...t };
|
|
83
|
-
typeof n.content != "string" || n.content.trim().length === 0 ? (o.push(
|
|
84
|
-
`[${t.id}]: Field "content" missing or empty, using default "${a.content}"`
|
|
85
|
-
), e.content = a.content) : e.content = n.content, e.x = r(n.x, a.x, t.id, "x", o), e.y = r(n.y, a.y, t.id, "y", o), e.w = r(n.w, a.w, t.id, "w", o), e.h = r(n.h, a.h, t.id, "h", o);
|
|
86
|
-
const i = a.style.bg, l = a.style.color;
|
|
87
|
-
return !n.style || typeof n.style != "object" ? (o.push(
|
|
88
|
-
`[${t.id}]: Field "style" missing or invalid, using defaults`
|
|
89
|
-
), e.style = {
|
|
90
|
-
bg: i,
|
|
91
|
-
color: l
|
|
92
|
-
}) : e.style = {
|
|
93
|
-
bg: c(n.style.bg, i, t.id, o),
|
|
94
|
-
color: c(n.style.color, l, t.id, o)
|
|
95
|
-
}, e;
|
|
96
|
-
}
|
|
97
|
-
function k(t, n, o) {
|
|
98
|
-
return !t || typeof t != "object" ? (o.push(`[${n}]: Invalid point object, using default`), { t: 0, x: 0.1, y: 0.1 }) : {
|
|
99
|
-
t: r(t.t, 0, n, "point.t", o),
|
|
100
|
-
x: r(t.x, 0.1, n, "point.x", o),
|
|
101
|
-
y: r(t.y, 0.1, n, "point.y", o)
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function x(t, n, o) {
|
|
105
|
-
if (!t || typeof t != "object")
|
|
106
|
-
return o.push(`[${n}]: Invalid stroke object, using default`), d.strokes[0];
|
|
107
|
-
const s = {
|
|
108
|
-
color: c(t.color, d.strokes[0].color, n, o),
|
|
109
|
-
size: h(t.size, d.strokes[0].size, n, "stroke.size", o)
|
|
110
|
-
};
|
|
111
|
-
return !Array.isArray(t.points) || t.points.length === 0 ? (o.push(`[${n}]: Stroke missing points array, using default`), s.points = d.strokes[0].points) : s.points = t.points.map((e) => k(e, n, o)), s;
|
|
112
|
-
}
|
|
113
|
-
function v(t, n, o, s) {
|
|
114
|
-
const e = { ...t };
|
|
115
|
-
return !Array.isArray(n.strokes) || n.strokes.length === 0 ? (o.push(
|
|
116
|
-
`[${t.id}]: Field "strokes" missing or empty, using default`
|
|
117
|
-
), e.strokes = d.strokes) : e.strokes = n.strokes.map((i) => x(i, t.id, o)), e;
|
|
118
|
-
}
|
|
119
|
-
function b(t, n) {
|
|
120
|
-
const o = [], s = [];
|
|
121
|
-
if (!t || typeof t != "object")
|
|
122
|
-
return {
|
|
123
|
-
annotation: null,
|
|
124
|
-
warnings: [],
|
|
125
|
-
info: [],
|
|
126
|
-
critical: `Annotation at index ${n}: Not a valid object`
|
|
127
|
-
};
|
|
128
|
-
if (typeof t.type != "string" || t.type.trim().length === 0)
|
|
129
|
-
return {
|
|
130
|
-
annotation: null,
|
|
131
|
-
warnings: [],
|
|
132
|
-
info: [],
|
|
133
|
-
critical: `Annotation at index ${n}: Missing or invalid type field`
|
|
134
|
-
};
|
|
135
|
-
const e = t.type.trim(), i = $(t, o, s);
|
|
136
|
-
let l;
|
|
137
|
-
if (e === "highlight")
|
|
138
|
-
l = A(i, t, o);
|
|
139
|
-
else if (e === "text")
|
|
140
|
-
l = F(i, t, o);
|
|
141
|
-
else if (e === "ink")
|
|
142
|
-
l = v(i, t, o);
|
|
143
|
-
else
|
|
144
|
-
return {
|
|
145
|
-
annotation: null,
|
|
146
|
-
warnings: [],
|
|
147
|
-
info: [],
|
|
148
|
-
critical: `Annotation at index ${n}: Unsupported type "${e}"`
|
|
149
|
-
};
|
|
150
|
-
return {
|
|
151
|
-
annotation: l,
|
|
152
|
-
warnings: o,
|
|
153
|
-
info: s,
|
|
154
|
-
critical: null
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function E(t, n = {}) {
|
|
158
|
-
n.skipInvalid;
|
|
159
|
-
const o = n.warnInConsole !== !1, s = n.onWarning || null, e = {
|
|
160
|
-
normalized: [],
|
|
161
|
-
warnings: [],
|
|
162
|
-
info: [],
|
|
163
|
-
skipped: []
|
|
164
|
-
};
|
|
165
|
-
if (!Array.isArray(t)) {
|
|
166
|
-
const i = "normalizeAnnotationArray: Input is not an array, returning empty result";
|
|
167
|
-
return e.warnings.push(i), o && console.warn(`[Annotation Normalizer] ${i}`), e;
|
|
1
|
+
import { applyJitter as b, applyPressure as j } from "./index6.js";
|
|
2
|
+
function x(l, t) {
|
|
3
|
+
const { id: o, start: s, end: h, quads: n } = l;
|
|
4
|
+
if (!n || n.length === 0)
|
|
5
|
+
return [];
|
|
6
|
+
const u = [], f = h - s, g = n.length, a = f / g;
|
|
7
|
+
for (let r = 0; r < n.length; r++) {
|
|
8
|
+
const q = n[r], { x: i, y: C, w: $, h: m } = q, p = C + m / 2;
|
|
9
|
+
let e = [
|
|
10
|
+
[i, p],
|
|
11
|
+
[i + $, p]
|
|
12
|
+
];
|
|
13
|
+
t.jitter?.amplitude > 0 && (e = b(e, t.jitter, `${o}-${r}`));
|
|
14
|
+
let d = null;
|
|
15
|
+
(t.pressure?.taperIn > 0 || t.pressure?.taperOut > 0) && (d = j(e, t.pressure));
|
|
16
|
+
const c = s + r * a, w = c + a;
|
|
17
|
+
u.push({
|
|
18
|
+
id: `${o}-${r}`,
|
|
19
|
+
points: e,
|
|
20
|
+
start: c,
|
|
21
|
+
end: w,
|
|
22
|
+
color: t.color || "rgba(255, 255, 0, 0.3)",
|
|
23
|
+
width: t.width || 24,
|
|
24
|
+
lineCap: t.lineCap || "butt",
|
|
25
|
+
pressures: d
|
|
26
|
+
});
|
|
168
27
|
}
|
|
169
|
-
return
|
|
170
|
-
if (i == null) {
|
|
171
|
-
e.skipped.push({
|
|
172
|
-
index: l,
|
|
173
|
-
annotation: i,
|
|
174
|
-
reason: "Annotation is null or undefined"
|
|
175
|
-
});
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
const u = b(i, l);
|
|
179
|
-
if (u.critical) {
|
|
180
|
-
e.skipped.push({
|
|
181
|
-
index: l,
|
|
182
|
-
annotation: i,
|
|
183
|
-
reason: u.critical
|
|
184
|
-
}), o && console.error(`[Annotation Normalizer] ${u.critical}`);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
e.normalized.push(u.annotation), e.warnings.push(...u.warnings), e.info.push(...u.info);
|
|
188
|
-
}), o && (e.warnings.length > 0 || e.info.length > 0 || e.skipped.length > 0) && (console.group("[Annotation Normalizer] Validation Summary"), e.normalized.length > 0 && console.info(`✓ Normalized ${e.normalized.length} annotation(s)`), e.skipped.length > 0 && (console.error(`✗ Skipped ${e.skipped.length} annotation(s)`), e.skipped.forEach((i) => {
|
|
189
|
-
console.error(` Index ${i.index}: ${i.reason}`);
|
|
190
|
-
})), e.warnings.length > 0 && (console.warn(`⚠ ${e.warnings.length} warning(s):`), e.warnings.forEach((i) => console.warn(` ${i}`))), e.info.length > 0 && (console.info(`ℹ ${e.info.length} info message(s):`), e.info.forEach((i) => console.info(` ${i}`))), console.groupEnd()), s && typeof s == "function" && s(e), e;
|
|
28
|
+
return u;
|
|
191
29
|
}
|
|
192
30
|
export {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
$ as normalizeBaseFields,
|
|
196
|
-
c as normalizeColor,
|
|
197
|
-
r as normalizeCoordinate,
|
|
198
|
-
A as normalizeHighlight,
|
|
199
|
-
v as normalizeInk,
|
|
200
|
-
h as normalizePositiveNumber,
|
|
201
|
-
F as normalizeText
|
|
31
|
+
x as default,
|
|
32
|
+
x as highlightToStrokes
|
|
202
33
|
};
|
|
203
34
|
//# sourceMappingURL=index13.js.map
|
package/dist/index13.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index13.js","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 INK_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 a single ink point\n *\n * @private\n * @param {Object} point - Point object with t, x, y\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized point\n */\nfunction normalizePoint(point, id, warnings) {\n if (!point || typeof point !== 'object') {\n warnings.push(`[${id}]: Invalid point object, using default`);\n return { t: 0, x: 0.1, y: 0.1 };\n }\n\n return {\n t: normalizeCoordinate(point.t, 0, id, 'point.t', warnings),\n x: normalizeCoordinate(point.x, 0.1, id, 'point.x', warnings),\n y: normalizeCoordinate(point.y, 0.1, id, 'point.y', warnings)\n };\n}\n\n/**\n * Normalize a single ink stroke\n *\n * @private\n * @param {Object} stroke - Stroke object with color, size, points\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized stroke\n */\nfunction normalizeStroke(stroke, id, warnings) {\n if (!stroke || typeof stroke !== 'object') {\n warnings.push(`[${id}]: Invalid stroke object, using default`);\n return INK_DEFAULTS.strokes[0];\n }\n\n const normalized = {\n color: normalizeColor(stroke.color, INK_DEFAULTS.strokes[0].color, id, warnings),\n size: normalizePositiveNumber(stroke.size, INK_DEFAULTS.strokes[0].size, id, 'stroke.size', warnings)\n };\n\n // ===== Points Array =====\n if (!Array.isArray(stroke.points) || stroke.points.length === 0) {\n warnings.push(`[${id}]: Stroke missing points array, using default`);\n normalized.points = INK_DEFAULTS.strokes[0].points;\n } else {\n normalized.points = stroke.points.map(point => normalizePoint(point, id, warnings));\n }\n\n return normalized;\n}\n\n/**\n * Normalize ink annotation\n *\n * Validates and normalizes ink-specific fields: strokes array with color,\n * size, and points. 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 ink annotation\n *\n * @example\n * normalizeInk(base, raw, warnings, info)\n * // Returns: { ...base, strokes: [{ color: '...', size: 3, points: [...] }] }\n */\nexport function normalizeInk(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Strokes Array =====\n // Check: non-empty array\n // Invalid: use default single stroke\n if (!Array.isArray(raw.strokes) || raw.strokes.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"strokes\" missing or empty, using default`\n );\n annotation.strokes = INK_DEFAULTS.strokes;\n } else {\n // Normalize each stroke\n annotation.strokes = raw.strokes.map(stroke => normalizeStroke(stroke, base.id, warnings));\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 === 'ink') {\n annotation = normalizeInk(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","normalizePoint","point","normalizeStroke","stroke","INK_DEFAULTS","normalized","normalizeInk","normalizeAnnotation","index","type","normalizeAnnotationArray","rawAnnotations","options","warnInConsole","onWarning","result","warning","s","w"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index13.js","sources":["../src/converters/highlight.js"],"sourcesContent":["/**\n * Highlight Converter - Converts highlight annotations to stroke commands\n *\n * Transforms rectangular quads into horizontal stroke paths that can be\n * rendered progressively on canvas.\n *\n * @module converters/highlight\n */\n\nimport { applyJitter, applyPressure } from '../pen/effects.js';\n\n/**\n * Converts a highlight annotation to stroke commands\n *\n * Each quad in the annotation becomes a horizontal stroke at the\n * vertical center of the quad. Multiple quads are staggered in timing.\n *\n * @param {Object} annotation - Highlight annotation object\n * @param {string} annotation.id - Unique identifier\n * @param {number} annotation.start - Start time in seconds\n * @param {number} annotation.end - End time in seconds\n * @param {Array<{x: number, y: number, w: number, h: number}>} annotation.quads - Array of quads\n * @param {Object} [annotation.style] - Optional style overrides\n * @param {Object} style - Resolved style configuration\n * @param {string} style.color - Stroke color\n * @param {number} style.width - Stroke width in pixels\n * @param {string} [style.lineCap='butt'] - Line cap style\n * @param {Object} [style.jitter] - Jitter configuration\n * @param {Object} [style.pressure] - Pressure configuration\n * @returns {Array<Object>} Array of stroke commands\n */\nexport function highlightToStrokes(annotation, style) {\n const { id, start, end, quads } = annotation;\n\n if (!quads || quads.length === 0) {\n return [];\n }\n\n const strokes = [];\n const totalDuration = end - start;\n const quadCount = quads.length;\n\n // Calculate timing for each quad (staggered)\n const quadDuration = totalDuration / quadCount;\n\n for (let i = 0; i < quads.length; i++) {\n const quad = quads[i];\n const { x, y, w, h } = quad;\n\n // Calculate center-line Y position\n const yCenter = y + h / 2;\n\n // Create stroke points (left to right horizontal line)\n let points = [\n [x, yCenter],\n [x + w, yCenter]\n ];\n\n // Apply jitter if configured\n if (style.jitter?.amplitude > 0) {\n points = applyJitter(points, style.jitter, `${id}-${i}`);\n }\n\n // Calculate pressure values if configured\n let pressures = null;\n if (style.pressure?.taperIn > 0 || style.pressure?.taperOut > 0) {\n pressures = applyPressure(points, style.pressure);\n }\n\n // Calculate timing for this quad\n const quadStart = start + i * quadDuration;\n const quadEnd = quadStart + quadDuration;\n\n strokes.push({\n id: `${id}-${i}`,\n points,\n start: quadStart,\n end: quadEnd,\n color: style.color || 'rgba(255, 255, 0, 0.3)',\n width: style.width || 24,\n lineCap: style.lineCap || 'butt',\n pressures\n });\n }\n\n return strokes;\n}\n\nexport default highlightToStrokes;\n"],"names":["highlightToStrokes","annotation","style","id","start","end","quads","strokes","totalDuration","quadCount","quadDuration","i","quad","x","y","w","h","yCenter","points","applyJitter","pressures","applyPressure","quadStart","quadEnd"],"mappings":";AA+BO,SAASA,EAAmBC,GAAYC,GAAO;AACpD,QAAM,EAAE,IAAAC,GAAI,OAAAC,GAAO,KAAAC,GAAK,OAAAC,EAAK,IAAKL;AAElC,MAAI,CAACK,KAASA,EAAM,WAAW;AAC7B,WAAO,CAAA;AAGT,QAAMC,IAAU,CAAA,GACVC,IAAgBH,IAAMD,GACtBK,IAAYH,EAAM,QAGlBI,IAAeF,IAAgBC;AAErC,WAASE,IAAI,GAAGA,IAAIL,EAAM,QAAQK,KAAK;AACrC,UAAMC,IAAON,EAAMK,CAAC,GACd,EAAE,GAAAE,GAAG,GAAAC,GAAG,GAAAC,GAAG,GAAAC,EAAC,IAAKJ,GAGjBK,IAAUH,IAAIE,IAAI;AAGxB,QAAIE,IAAS;AAAA,MACX,CAACL,GAAGI,CAAO;AAAA,MACX,CAACJ,IAAIE,GAAGE,CAAO;AAAA,IACrB;AAGI,IAAIf,EAAM,QAAQ,YAAY,MAC5BgB,IAASC,EAAYD,GAAQhB,EAAM,QAAQ,GAAGC,CAAE,IAAIQ,CAAC,EAAE;AAIzD,QAAIS,IAAY;AAChB,KAAIlB,EAAM,UAAU,UAAU,KAAKA,EAAM,UAAU,WAAW,OAC5DkB,IAAYC,EAAcH,GAAQhB,EAAM,QAAQ;AAIlD,UAAMoB,IAAYlB,IAAQO,IAAID,GACxBa,IAAUD,IAAYZ;AAE5B,IAAAH,EAAQ,KAAK;AAAA,MACX,IAAI,GAAGJ,CAAE,IAAIQ,CAAC;AAAA,MACd,QAAAO;AAAA,MACA,OAAOI;AAAA,MACP,KAAKC;AAAA,MACL,OAAOrB,EAAM,SAAS;AAAA,MACtB,OAAOA,EAAM,SAAS;AAAA,MACtB,SAASA,EAAM,WAAW;AAAA,MAC1B,WAAAkB;AAAA,IACN,CAAK;AAAA,EACH;AAEA,SAAOb;AACT;"}
|
package/dist/index14.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const M=require("./index6.cjs"),P=require("./index23.cjs");function X(t,e=2){if(t.length<2||e<1)return t;const n=[];for(let r=0;r<t.length-1;r++){const[a,o]=t[r],[g,S]=t[r+1];n.push([a,o]);for(let s=1;s<=e;s++){const u=s/(e+1);n.push([a+(g-a)*u,o+(S-o)*u])}}return n.push(t[t.length-1]),n}function _(t){return P.default.glyphs&&P.default.glyphs[t]?P.default.glyphs[t]:t===" "?{paths:[],width:.35}:null}function F(t,e,n){return t.map(([r,a])=>[(e+r)*n,a*n])}function z(t,e){const{id:n,start:r,end:a,content:o,x:g,y:S,fontSize:s}=t;if(!o||o.length===0)return[];const u=[],q=a-r,v=s||e.fontSize||16,k=e.subdivisions??2,I=v/1e3;let h=0;const O=o.length,x=q/O;for(let c=0;c<o.length;c++){const $=o[c],l=_($);if(!l){h+=.5+.18;continue}const m=l.width||.5,f=l.paths||[],j=l.pathTiming||"sequential";if(f.length===0){h+=m+.18;continue}const b=r+c*x,y=b+x,E=f.length;for(let i=0;i<f.length;i++){let p=f[i].points||[];if(p.length<2)continue;k>0&&(p=X(p,k));let w=F(p,h,I),C=null;(e.pressure?.taperIn>0||e.pressure?.taperOut>0)&&(C=M.applyPressure(w,e.pressure));let d,D;if(j==="parallel")d=b,D=y;else{const T=x/E;d=b+i*T,D=d+T}u.push({id:`${n}-${c}-${i}`,points:w,baseX:g,baseY:S,start:d,end:D,color:e.color||"rgba(220, 20, 60, 1.0)",width:e.width||2,lineCap:e.lineCap||"round",pressures:C,uniformScale:!0})}h+=m+.18}return u}exports.default=z;exports.textToStrokes=z;
|
|
2
2
|
//# sourceMappingURL=index14.cjs.map
|
package/dist/index14.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index14.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index14.cjs","sources":["../src/converters/text.js"],"sourcesContent":["/**\n * Text Converter - Converts text annotations to stroke commands\n *\n * Transforms text content into stroke paths for each character,\n * using single-stroke font glyphs for smooth writing animation.\n *\n * @module converters/text\n */\n\nimport { applyPressure } from \"../pen/effects.js\";\nimport singleStrokeFont from \"../strokes/single-stroke.json\";\n\n/**\n * Subdivide a path by adding intermediate points between existing points.\n * This creates smoother interpolation during progressive rendering.\n *\n * @param {Array<[number, number]>} points - Original path points\n * @param {number} subdivisions - Number of points to add between each pair (default: 2)\n * @returns {Array<[number, number]>} Subdivided path with more points\n */\nfunction subdividePath(points, subdivisions = 2) {\n if (points.length < 2 || subdivisions < 1) {\n return points;\n }\n\n const result = [];\n\n for (let i = 0; i < points.length - 1; i++) {\n const [x1, y1] = points[i];\n const [x2, y2] = points[i + 1];\n\n // Add the start point\n result.push([x1, y1]);\n\n // Add intermediate points\n for (let j = 1; j <= subdivisions; j++) {\n const t = j / (subdivisions + 1);\n result.push([x1 + (x2 - x1) * t, y1 + (y2 - y1) * t]);\n }\n }\n\n // Add the final point\n result.push(points[points.length - 1]);\n\n return result;\n}\n\n/**\n * Looks up character glyph from the single-stroke font library\n *\n * @param {string} char - Single character to look up\n * @returns {Object|null} Character data with paths and width, or null if not found\n */\nfunction lookupCharacter(char) {\n // Check single-stroke font library\n if (singleStrokeFont.glyphs && singleStrokeFont.glyphs[char]) {\n return singleStrokeFont.glyphs[char];\n }\n\n // Space character - return empty with width\n if (char === \" \") {\n return { paths: [], width: 0.35 };\n }\n\n // Fallback: return null (character will be skipped)\n return null;\n}\n\n/**\n * Scales glyph points by fontSize scale factor\n *\n * Glyph points are in normalized space where:\n * - X is 0 to charWidth (already scaled within the glyph)\n * - Y is 0 to ~1.0 (baseline at 0.8, cap height at 0)\n *\n * This scales them to the target size, but does NOT add the base position.\n * The base position is stored separately to allow correct rendering with\n * mixed coordinate systems (position in page coords, offsets in uniform space).\n *\n * @param {Array<[number, number]>} points - Glyph points in normalized space\n * @param {number} offsetX - X offset from base position (character offset within text)\n * @param {number} scale - Scale factor based on fontSize\n * @returns {Array<[number, number]>} Scaled offset points (not absolute positions)\n */\nfunction scaleGlyphPoints(points, offsetX, scale) {\n // Scale points and add character offset (in uniform space)\n return points.map(([px, py]) => [(offsetX + px) * scale, py * scale]);\n}\n\n/**\n * Converts a text annotation to stroke commands\n *\n * Each character in the content becomes one or more strokes.\n * Characters are staggered in timing to create a writing effect.\n * Multi-path characters (like 'i', 'j', '!') use pathTiming to\n * control whether paths are drawn sequentially or in parallel.\n *\n * @param {Object} annotation - Text annotation object\n * @param {string} annotation.id - Unique identifier\n * @param {number} annotation.start - Start time in seconds\n * @param {number} annotation.end - End time in seconds\n * @param {string} annotation.content - Text content to render\n * @param {number} annotation.x - X position (normalized 0-1)\n * @param {number} annotation.y - Y position (normalized 0-1)\n * @param {number} [annotation.fontSize=16] - Font size in pixels\n * @param {Object} [annotation.style] - Optional style overrides\n * @param {Object} style - Resolved style configuration\n * @param {string} style.color - Stroke color\n * @param {number} style.width - Stroke width in pixels\n * @param {number} [style.fontSize=16] - Default font size\n * @param {string} [style.lineCap='round'] - Line cap style\n * @param {Object} [style.jitter] - Jitter configuration\n * @param {Object} [style.pressure] - Pressure configuration\n * @param {number} [style.subdivisions=2] - Path subdivision level\n * @returns {Array<Object>} Array of stroke commands\n */\nexport function textToStrokes(annotation, style) {\n const { id, start, end, content, x, y, fontSize: annotFontSize } = annotation;\n\n if (!content || content.length === 0) {\n return [];\n }\n\n const strokes = [];\n const totalDuration = end - start;\n const fontSize = annotFontSize || style.fontSize || 16;\n const subdivisions = style.subdivisions ?? 2;\n\n // Scale factor: convert fontSize (pixels) to normalized coordinates\n // Assuming a reference viewport of ~1000px\n const scale = fontSize / 1000;\n\n // Track character offset from base position (in glyph units, not page coords)\n let charOffsetX = 0;\n\n // Calculate timing per character\n const charCount = content.length;\n const charDuration = totalDuration / charCount;\n\n for (let charIndex = 0; charIndex < content.length; charIndex++) {\n const char = content[charIndex];\n const charData = lookupCharacter(char);\n\n if (!charData) {\n // Skip unknown characters, but advance position with default width\n charOffsetX += 0.5 + 0.18; // default width + spacing (in glyph units)\n continue;\n }\n\n const charWidth = charData.width || 0.5;\n const charPaths = charData.paths || [];\n const pathTiming = charData.pathTiming || \"sequential\";\n\n // Skip if no paths (e.g., space character)\n if (charPaths.length === 0) {\n charOffsetX += charWidth + 0.18;\n continue;\n }\n\n // Calculate timing for this character's paths\n const charStart = start + charIndex * charDuration;\n const charEnd = charStart + charDuration;\n\n // Determine path timing based on pathTiming mode\n const pathCount = charPaths.length;\n\n for (let pathIndex = 0; pathIndex < charPaths.length; pathIndex++) {\n const pathData = charPaths[pathIndex];\n let rawPoints = pathData.points || [];\n\n if (rawPoints.length < 2) continue;\n\n // Apply path subdivision for smoother interpolation\n if (subdivisions > 0) {\n rawPoints = subdividePath(rawPoints, subdivisions);\n }\n\n // Scale glyph points (offset coordinates, not absolute)\n let points = scaleGlyphPoints(rawPoints, charOffsetX, scale);\n\n // Calculate pressure values if configured\n let pressures = null;\n if (style.pressure?.taperIn > 0 || style.pressure?.taperOut > 0) {\n pressures = applyPressure(points, style.pressure);\n }\n\n // Calculate path timing based on pathTiming mode\n let pathStart, pathEnd;\n\n if (pathTiming === \"parallel\") {\n // All paths drawn simultaneously during character duration\n pathStart = charStart;\n pathEnd = charEnd;\n } else {\n // Sequential: each path gets a portion of character duration\n const pathDuration = charDuration / pathCount;\n pathStart = charStart + pathIndex * pathDuration;\n pathEnd = pathStart + pathDuration;\n }\n\n strokes.push({\n id: `${id}-${charIndex}-${pathIndex}`,\n points, // Offset coordinates from baseX/baseY (uniform space)\n baseX: x, // Base X position (width-normalized page coords)\n baseY: y, // Base Y position (height-normalized page coords)\n start: pathStart,\n end: pathEnd,\n color: style.color || \"rgba(220, 20, 60, 1.0)\",\n width: style.width || 2,\n lineCap: style.lineCap || \"round\",\n pressures,\n uniformScale: true, // Preserve aspect ratio when rendering\n });\n }\n\n // Advance offset for next character (in glyph units)\n charOffsetX += charWidth + 0.18; // Add small spacing\n }\n\n return strokes;\n}\n\nexport default textToStrokes;\n"],"names":["subdividePath","points","subdivisions","result","i","x1","y1","x2","y2","j","t","lookupCharacter","char","singleStrokeFont","scaleGlyphPoints","offsetX","scale","px","py","textToStrokes","annotation","style","id","start","end","content","x","y","annotFontSize","strokes","totalDuration","fontSize","charOffsetX","charCount","charDuration","charIndex","charData","charWidth","charPaths","pathTiming","charStart","charEnd","pathCount","pathIndex","rawPoints","pressures","applyPressure","pathStart","pathEnd","pathDuration"],"mappings":"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"}
|
package/dist/index14.js
CHANGED
|
@@ -1,18 +1,81 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { applyPressure as q } from "./index6.js";
|
|
2
|
+
import w from "./index23.js";
|
|
3
|
+
function v(t, n = 2) {
|
|
4
|
+
if (t.length < 2 || n < 1)
|
|
5
|
+
return t;
|
|
6
|
+
const e = [];
|
|
7
|
+
for (let r = 0; r < t.length - 1; r++) {
|
|
8
|
+
const [a, o] = t[r], [g, S] = t[r + 1];
|
|
9
|
+
e.push([a, o]);
|
|
10
|
+
for (let s = 1; s <= n; s++) {
|
|
11
|
+
const h = s / (n + 1);
|
|
12
|
+
e.push([a + (g - a) * h, o + (S - o) * h]);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return e.push(t[t.length - 1]), e;
|
|
16
|
+
}
|
|
17
|
+
function y(t) {
|
|
18
|
+
return w.glyphs && w.glyphs[t] ? w.glyphs[t] : t === " " ? { paths: [], width: 0.35 } : null;
|
|
19
|
+
}
|
|
20
|
+
function G(t, n, e) {
|
|
21
|
+
return t.map(([r, a]) => [(n + r) * e, a * e]);
|
|
22
|
+
}
|
|
23
|
+
function B(t, n) {
|
|
24
|
+
const { id: e, start: r, end: a, content: o, x: g, y: S, fontSize: s } = t;
|
|
25
|
+
if (!o || o.length === 0)
|
|
26
|
+
return [];
|
|
27
|
+
const h = [], I = a - r, T = s || n.fontSize || 16, C = n.subdivisions ?? 2, $ = T / 1e3;
|
|
28
|
+
let u = 0;
|
|
29
|
+
const E = o.length, m = I / E;
|
|
30
|
+
for (let c = 0; c < o.length; c++) {
|
|
31
|
+
const F = o[c], l = y(F);
|
|
32
|
+
if (!l) {
|
|
33
|
+
u += 0.5 + 0.18;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const P = l.width || 0.5, p = l.paths || [], O = l.pathTiming || "sequential";
|
|
37
|
+
if (p.length === 0) {
|
|
38
|
+
u += P + 0.18;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const x = r + c * m, X = x + m, j = p.length;
|
|
42
|
+
for (let i = 0; i < p.length; i++) {
|
|
43
|
+
let f = p[i].points || [];
|
|
44
|
+
if (f.length < 2) continue;
|
|
45
|
+
C > 0 && (f = v(f, C));
|
|
46
|
+
let b = G(f, u, $), k = null;
|
|
47
|
+
(n.pressure?.taperIn > 0 || n.pressure?.taperOut > 0) && (k = q(b, n.pressure));
|
|
48
|
+
let d, D;
|
|
49
|
+
if (O === "parallel")
|
|
50
|
+
d = x, D = X;
|
|
51
|
+
else {
|
|
52
|
+
const z = m / j;
|
|
53
|
+
d = x + i * z, D = d + z;
|
|
54
|
+
}
|
|
55
|
+
h.push({
|
|
56
|
+
id: `${e}-${c}-${i}`,
|
|
57
|
+
points: b,
|
|
58
|
+
// Offset coordinates from baseX/baseY (uniform space)
|
|
59
|
+
baseX: g,
|
|
60
|
+
// Base X position (width-normalized page coords)
|
|
61
|
+
baseY: S,
|
|
62
|
+
// Base Y position (height-normalized page coords)
|
|
63
|
+
start: d,
|
|
64
|
+
end: D,
|
|
65
|
+
color: n.color || "rgba(220, 20, 60, 1.0)",
|
|
66
|
+
width: n.width || 2,
|
|
67
|
+
lineCap: n.lineCap || "round",
|
|
68
|
+
pressures: k,
|
|
69
|
+
uniformScale: !0
|
|
70
|
+
// Preserve aspect ratio when rendering
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
u += P + 0.18;
|
|
74
|
+
}
|
|
75
|
+
return h;
|
|
76
|
+
}
|
|
3
77
|
export {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
L as INK_DEFAULTS,
|
|
7
|
-
S as TEXT_DEFAULTS,
|
|
8
|
-
e as normalizeAnnotation,
|
|
9
|
-
i as normalizeAnnotationArray,
|
|
10
|
-
n as normalizeBaseFields,
|
|
11
|
-
a as normalizeColor,
|
|
12
|
-
l as normalizeCoordinate,
|
|
13
|
-
m as normalizeHighlight,
|
|
14
|
-
t as normalizeInk,
|
|
15
|
-
z as normalizePositiveNumber,
|
|
16
|
-
A as normalizeText
|
|
78
|
+
B as default,
|
|
79
|
+
B as textToStrokes
|
|
17
80
|
};
|
|
18
81
|
//# sourceMappingURL=index14.js.map
|
package/dist/index14.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index14.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
1
|
+
{"version":3,"file":"index14.js","sources":["../src/converters/text.js"],"sourcesContent":["/**\n * Text Converter - Converts text annotations to stroke commands\n *\n * Transforms text content into stroke paths for each character,\n * using single-stroke font glyphs for smooth writing animation.\n *\n * @module converters/text\n */\n\nimport { applyPressure } from \"../pen/effects.js\";\nimport singleStrokeFont from \"../strokes/single-stroke.json\";\n\n/**\n * Subdivide a path by adding intermediate points between existing points.\n * This creates smoother interpolation during progressive rendering.\n *\n * @param {Array<[number, number]>} points - Original path points\n * @param {number} subdivisions - Number of points to add between each pair (default: 2)\n * @returns {Array<[number, number]>} Subdivided path with more points\n */\nfunction subdividePath(points, subdivisions = 2) {\n if (points.length < 2 || subdivisions < 1) {\n return points;\n }\n\n const result = [];\n\n for (let i = 0; i < points.length - 1; i++) {\n const [x1, y1] = points[i];\n const [x2, y2] = points[i + 1];\n\n // Add the start point\n result.push([x1, y1]);\n\n // Add intermediate points\n for (let j = 1; j <= subdivisions; j++) {\n const t = j / (subdivisions + 1);\n result.push([x1 + (x2 - x1) * t, y1 + (y2 - y1) * t]);\n }\n }\n\n // Add the final point\n result.push(points[points.length - 1]);\n\n return result;\n}\n\n/**\n * Looks up character glyph from the single-stroke font library\n *\n * @param {string} char - Single character to look up\n * @returns {Object|null} Character data with paths and width, or null if not found\n */\nfunction lookupCharacter(char) {\n // Check single-stroke font library\n if (singleStrokeFont.glyphs && singleStrokeFont.glyphs[char]) {\n return singleStrokeFont.glyphs[char];\n }\n\n // Space character - return empty with width\n if (char === \" \") {\n return { paths: [], width: 0.35 };\n }\n\n // Fallback: return null (character will be skipped)\n return null;\n}\n\n/**\n * Scales glyph points by fontSize scale factor\n *\n * Glyph points are in normalized space where:\n * - X is 0 to charWidth (already scaled within the glyph)\n * - Y is 0 to ~1.0 (baseline at 0.8, cap height at 0)\n *\n * This scales them to the target size, but does NOT add the base position.\n * The base position is stored separately to allow correct rendering with\n * mixed coordinate systems (position in page coords, offsets in uniform space).\n *\n * @param {Array<[number, number]>} points - Glyph points in normalized space\n * @param {number} offsetX - X offset from base position (character offset within text)\n * @param {number} scale - Scale factor based on fontSize\n * @returns {Array<[number, number]>} Scaled offset points (not absolute positions)\n */\nfunction scaleGlyphPoints(points, offsetX, scale) {\n // Scale points and add character offset (in uniform space)\n return points.map(([px, py]) => [(offsetX + px) * scale, py * scale]);\n}\n\n/**\n * Converts a text annotation to stroke commands\n *\n * Each character in the content becomes one or more strokes.\n * Characters are staggered in timing to create a writing effect.\n * Multi-path characters (like 'i', 'j', '!') use pathTiming to\n * control whether paths are drawn sequentially or in parallel.\n *\n * @param {Object} annotation - Text annotation object\n * @param {string} annotation.id - Unique identifier\n * @param {number} annotation.start - Start time in seconds\n * @param {number} annotation.end - End time in seconds\n * @param {string} annotation.content - Text content to render\n * @param {number} annotation.x - X position (normalized 0-1)\n * @param {number} annotation.y - Y position (normalized 0-1)\n * @param {number} [annotation.fontSize=16] - Font size in pixels\n * @param {Object} [annotation.style] - Optional style overrides\n * @param {Object} style - Resolved style configuration\n * @param {string} style.color - Stroke color\n * @param {number} style.width - Stroke width in pixels\n * @param {number} [style.fontSize=16] - Default font size\n * @param {string} [style.lineCap='round'] - Line cap style\n * @param {Object} [style.jitter] - Jitter configuration\n * @param {Object} [style.pressure] - Pressure configuration\n * @param {number} [style.subdivisions=2] - Path subdivision level\n * @returns {Array<Object>} Array of stroke commands\n */\nexport function textToStrokes(annotation, style) {\n const { id, start, end, content, x, y, fontSize: annotFontSize } = annotation;\n\n if (!content || content.length === 0) {\n return [];\n }\n\n const strokes = [];\n const totalDuration = end - start;\n const fontSize = annotFontSize || style.fontSize || 16;\n const subdivisions = style.subdivisions ?? 2;\n\n // Scale factor: convert fontSize (pixels) to normalized coordinates\n // Assuming a reference viewport of ~1000px\n const scale = fontSize / 1000;\n\n // Track character offset from base position (in glyph units, not page coords)\n let charOffsetX = 0;\n\n // Calculate timing per character\n const charCount = content.length;\n const charDuration = totalDuration / charCount;\n\n for (let charIndex = 0; charIndex < content.length; charIndex++) {\n const char = content[charIndex];\n const charData = lookupCharacter(char);\n\n if (!charData) {\n // Skip unknown characters, but advance position with default width\n charOffsetX += 0.5 + 0.18; // default width + spacing (in glyph units)\n continue;\n }\n\n const charWidth = charData.width || 0.5;\n const charPaths = charData.paths || [];\n const pathTiming = charData.pathTiming || \"sequential\";\n\n // Skip if no paths (e.g., space character)\n if (charPaths.length === 0) {\n charOffsetX += charWidth + 0.18;\n continue;\n }\n\n // Calculate timing for this character's paths\n const charStart = start + charIndex * charDuration;\n const charEnd = charStart + charDuration;\n\n // Determine path timing based on pathTiming mode\n const pathCount = charPaths.length;\n\n for (let pathIndex = 0; pathIndex < charPaths.length; pathIndex++) {\n const pathData = charPaths[pathIndex];\n let rawPoints = pathData.points || [];\n\n if (rawPoints.length < 2) continue;\n\n // Apply path subdivision for smoother interpolation\n if (subdivisions > 0) {\n rawPoints = subdividePath(rawPoints, subdivisions);\n }\n\n // Scale glyph points (offset coordinates, not absolute)\n let points = scaleGlyphPoints(rawPoints, charOffsetX, scale);\n\n // Calculate pressure values if configured\n let pressures = null;\n if (style.pressure?.taperIn > 0 || style.pressure?.taperOut > 0) {\n pressures = applyPressure(points, style.pressure);\n }\n\n // Calculate path timing based on pathTiming mode\n let pathStart, pathEnd;\n\n if (pathTiming === \"parallel\") {\n // All paths drawn simultaneously during character duration\n pathStart = charStart;\n pathEnd = charEnd;\n } else {\n // Sequential: each path gets a portion of character duration\n const pathDuration = charDuration / pathCount;\n pathStart = charStart + pathIndex * pathDuration;\n pathEnd = pathStart + pathDuration;\n }\n\n strokes.push({\n id: `${id}-${charIndex}-${pathIndex}`,\n points, // Offset coordinates from baseX/baseY (uniform space)\n baseX: x, // Base X position (width-normalized page coords)\n baseY: y, // Base Y position (height-normalized page coords)\n start: pathStart,\n end: pathEnd,\n color: style.color || \"rgba(220, 20, 60, 1.0)\",\n width: style.width || 2,\n lineCap: style.lineCap || \"round\",\n pressures,\n uniformScale: true, // Preserve aspect ratio when rendering\n });\n }\n\n // Advance offset for next character (in glyph units)\n charOffsetX += charWidth + 0.18; // Add small spacing\n }\n\n return strokes;\n}\n\nexport default textToStrokes;\n"],"names":["subdividePath","points","subdivisions","result","i","x1","y1","x2","y2","j","t","lookupCharacter","char","singleStrokeFont","scaleGlyphPoints","offsetX","scale","px","py","textToStrokes","annotation","style","id","start","end","content","x","y","annotFontSize","strokes","totalDuration","fontSize","charOffsetX","charCount","charDuration","charIndex","charData","charWidth","charPaths","pathTiming","charStart","charEnd","pathCount","pathIndex","rawPoints","pressures","applyPressure","pathStart","pathEnd","pathDuration"],"mappings":"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"}
|
package/dist/index15.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("./index16.cjs");class o{constructor(t,s){this.canvas=t,this.dimensions={...s},this.ctx=null,this.strokeDrawer=null,this.strokeCommands=[],this.currentTime=0,this.isDestroyed=!1,this._setupCanvas()}_setupCanvas(){const t=window.devicePixelRatio||1,{width:s,height:e}=this.dimensions;this.canvas.width=Math.round(s*t),this.canvas.height=Math.round(e*t),this.canvas.style.width=`${s}px`,this.canvas.style.height=`${e}px`,this.ctx=this.canvas.getContext("2d"),this.ctx.setTransform(t,0,0,t,0,0),this.strokeDrawer=new n.default(this.ctx,this.dimensions)}setStrokeCommands(t){this.isDestroyed||(this.strokeCommands=t||[],this.strokeCommands.sort((s,e)=>{const r=s.start??0,i=e.start??0;return r-i}))}setTime(t){this.isDestroyed||(this.currentTime=t)}setDimensions(t){this.isDestroyed||(this.dimensions={...t},this._setupCanvas())}render(){if(!(this.isDestroyed||!this.ctx)){this.strokeDrawer.clear();for(const t of this.strokeCommands){const s=t.start??0,e=t.end??s+1;if(this.currentTime<s)continue;const r=this._calculateProgress(s,e);this.strokeDrawer.drawStroke(t,r)}}}_calculateProgress(t,s){if(this.currentTime>=s)return 1;const e=s-t;if(e<=0)return 1;const r=this.currentTime-t;return Math.max(0,Math.min(1,r/e))}clear(){this.isDestroyed||!this.strokeDrawer||this.strokeDrawer.clear()}getVisibleStrokeCount(){let t=0;for(const s of this.strokeCommands){const e=s.start??0;this.currentTime>=e&&t++}return t}destroy(){this.isDestroyed||(this.strokeCommands=[],this.strokeDrawer=null,this.ctx=null,this.canvas=null,this.isDestroyed=!0)}}exports.default=o;
|
|
2
2
|
//# sourceMappingURL=index15.cjs.map
|