math-tasks/tasks/space-route/scripts/apply-edits.mjs

123 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Apply editor JSON edits to space-route HTML.
* Usage: node src/scripts/apply-route-edits.mjs output/html/space-route-edits.json
*/
import { readFileSync, writeFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..', '..');
const editsPath = process.argv[2] || join(ROOT, 'output', 'html', 'space-route-edits.json');
const edits = JSON.parse(readFileSync(editsPath, 'utf-8'));
const htmlPath = join(ROOT, 'output', 'html', edits.file);
let html = readFileSync(htmlPath, 'utf-8');
// Split HTML into pages
const pageRegex = /<div class="w-\[210mm\] h-\[297mm\][^>]*>/g;
const pageStarts = [];
let m;
while ((m = pageRegex.exec(html)) !== null) {
pageStarts.push(m.index);
}
pageStarts.push(html.length);
function getPageHtml(pageIndex) {
return html.slice(pageStarts[pageIndex], pageStarts[pageIndex + 1]);
}
function setPageHtml(pageIndex, newPageHtml) {
html = html.slice(0, pageStarts[pageIndex]) + newPageHtml + html.slice(pageStarts[pageIndex + 1]);
// Recalculate starts
const diff = newPageHtml.length - (pageStarts[pageIndex + 1] - pageStarts[pageIndex]);
for (let i = pageIndex + 1; i < pageStarts.length; i++) {
pageStarts[i] += diff;
}
}
for (const pageEdit of edits.pages) {
const pi = pageEdit.page - 1;
let pageHtml = getPageHtml(pi);
console.log(`Applying page ${pageEdit.page}...`);
// Apply object edits
if (pageEdit.objects) {
for (const obj of pageEdit.objects) {
// Find the img with matching data-node-id and data-type on this page
const nodeId = obj.nodeId;
const type = obj.type;
// Build transform string
let transform = '';
if (obj.rotate) transform += `rotate(${obj.rotate}deg)`;
if (obj.flipH) transform += ` scaleX(-1)`;
transform = transform.trim();
const transformAttr = transform ? `transform:${transform};` : '';
const w = parseFloat(obj.w);
const h = parseFloat(obj.h);
const left = parseFloat(obj.left);
const top = parseFloat(obj.top);
// Match the img element by data-node-id and data-type
const imgRegex = new RegExp(
`(<img[^>]*data-node-id="${nodeId}"[^>]*data-type="${type}"[^>]*style=")([^"]*)(")`,
'g'
);
const newStyle = `left:${left.toFixed(1)}mm;top:${top.toFixed(1)}mm;width:${w}mm;height:${h}mm;margin-left:-${w/2}mm;margin-top:-${h/2}mm;z-index:4;${transformAttr}`;
const before = pageHtml;
pageHtml = pageHtml.replace(imgRegex, `$1${newStyle}$3`);
if (pageHtml === before) {
// Try alternate order (data-type before data-node-id)
const imgRegex2 = new RegExp(
`(<img[^>]*data-type="${type}"[^>]*data-node-id="${nodeId}"[^>]*style=")([^"]*)(")`,
'g'
);
pageHtml = pageHtml.replace(imgRegex2, `$1${newStyle}$3`);
}
console.log(` obj node:${nodeId} type:${type}${left.toFixed(1)},${top.toFixed(1)} ${w}×${h}mm${obj.rotate ? ' rot:'+obj.rotate+'°' : ''}${obj.flipH ? ' FLIP' : ''}`);
}
}
// Apply node edits
if (pageEdit.nodes) {
for (const nd of pageEdit.nodes) {
const nodeId = nd.nodeId;
const left = parseFloat(nd.left);
const top = parseFloat(nd.top);
// Update node div position
const nodeRegex = new RegExp(
`(<div[^>]*data-node-id="${nodeId}"[^>]*style=")(left:[^;]*;top:[^;]*)`,
'g'
);
pageHtml = pageHtml.replace(nodeRegex, `$1left:${left.toFixed(1)}mm;top:${top.toFixed(1)}mm`);
// Update all edges connected to this node
// Edge format: data-edge="A-B" where A or B matches nodeId
// Update x1,y1 if nodeId is the first, x2,y2 if second
const edgeRegex1 = new RegExp(
`(<line data-edge="${nodeId}-\\d+"[^>]*)(x1="[^"]*")(\\s*)(y1="[^"]*")`,
'g'
);
pageHtml = pageHtml.replace(edgeRegex1, `$1x1="${left.toFixed(1)}mm"$3y1="${top.toFixed(1)}mm"`);
const edgeRegex2 = new RegExp(
`(<line data-edge="\\d+-${nodeId}"[^>]*)(x2="[^"]*")(\\s*)(y2="[^"]*")`,
'g'
);
pageHtml = pageHtml.replace(edgeRegex2, `$1x2="${left.toFixed(1)}mm"$3y2="${top.toFixed(1)}mm"`);
}
console.log(` ${pageEdit.nodes.length} nodes updated`);
}
setPageHtml(pi, pageHtml);
}
writeFileSync(htmlPath, html, 'utf-8');
console.log(`\nWritten to ${htmlPath}`);