Files
mimaki/webui/static/app.js
2026-02-05 22:50:36 +01:00

382 lines
14 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.
(function () {
const fileInput = document.getElementById('fileInput');
const preview = document.getElementById('preview');
const previewPlaceholder = document.getElementById('previewPlaceholder');
const statusFile = document.getElementById('statusFile');
const statusPlotter = document.getElementById('statusPlotter');
const printMessage = document.getElementById('printMessage');
const scaleDims = document.getElementById('scaleDims');
const plotterInfo = {
port: document.getElementById('plotterPort'),
baud: document.getElementById('plotterBaud'),
winsizeUnits: document.getElementById('plotterWinsizeUnits'),
winsizeMm: document.getElementById('plotterWinsizeMm'),
bounds: document.getElementById('plotterBounds')
};
const buttons = {
flip: document.getElementById('btnFlip'),
rotate90: document.getElementById('btnRotate90'),
rotate180: document.getElementById('btnRotate180'),
scaleUp: document.getElementById('btnScaleUp'),
scaleDown: document.getElementById('btnScaleDown'),
centralize: document.getElementById('btnCentralize'),
scaleToBounds: document.getElementById('btnScaleToBounds'),
print: document.getElementById('btnPrint'),
checkPlotter: document.getElementById('btnCheckPlotter'),
generateHpgl: document.getElementById('btnGenerateHpgl'),
exportHpgl: document.getElementById('btnExportHpgl')
};
const tabFile = document.getElementById('tabFile');
const tabText = document.getElementById('tabText');
const panelFile = document.getElementById('panelFile');
const panelText = document.getElementById('panelText');
const textInput = document.getElementById('textInput');
const fontSelect = document.getElementById('fontSelect');
const textSize = document.getElementById('textSize');
const textMessage = document.getElementById('textMessage');
const hpglFolderSelect = document.getElementById('hpglFolderSelect');
function setMessage(el, text, type) {
el.textContent = text || '';
el.className = 'message' + (type ? ' ' + type : '');
}
function updatePreview() {
const w = Math.min(800, window.innerWidth - 80);
const h = Math.min(600, window.innerHeight - 120);
preview.src = '/api/svg?width=' + w + '&height=' + h + '&scale=1&_=' + Date.now();
}
function updateDimensions() {
if (!scaleDims) return;
fetch('/api/dimensions')
.then(function (r) {
if (!r.ok) throw new Error();
return r.json();
})
.then(function (d) {
scaleDims.innerHTML = d.width + ' × ' + d.height + ' <span class="unit">(≈ ' + d.width_mm + ' × ' + d.height_mm + ' mm)</span>';
})
.catch(function () {
scaleDims.innerHTML = '— × — <span class="unit">(≈ — × — mm)</span>';
});
}
function updatePlotterInfo() {
if (!plotterInfo.port) return;
fetch('/api/plotter_info')
.then(function (r) { return r.ok ? r.json() : Promise.reject(); })
.then(function (d) {
plotterInfo.port.textContent = d.port || '—';
plotterInfo.baud.textContent = d.baudrate ? d.baudrate + ' baud' : '—';
if (d.winsize_units) {
plotterInfo.winsizeUnits.textContent = d.winsize_units.width + ' × ' + d.winsize_units.height;
} else {
plotterInfo.winsizeUnits.textContent = '— × —';
}
if (d.winsize_mm) {
plotterInfo.winsizeMm.textContent = d.winsize_mm.width + ' × ' + d.winsize_mm.height + ' mm';
} else {
plotterInfo.winsizeMm.textContent = '— × —';
}
if (d.boundaries) {
var b = d.boundaries;
plotterInfo.bounds.textContent = b.xmin + ',' + b.ymin + ' … ' + b.xmax + ',' + b.ymax;
} else {
plotterInfo.bounds.textContent = '—';
}
})
.catch(function () {
plotterInfo.port.textContent = '—';
plotterInfo.baud.textContent = '—';
plotterInfo.winsizeUnits.textContent = '— × —';
plotterInfo.winsizeMm.textContent = '— × —';
plotterInfo.bounds.textContent = '—';
});
}
var transformPrintButtons = ['flip', 'rotate90', 'rotate180', 'scaleUp', 'scaleDown', 'centralize', 'scaleToBounds', 'print', 'exportHpgl'];
function setLoaded(loaded) {
if (loaded) {
preview.classList.add('loaded');
previewPlaceholder.classList.add('hidden');
transformPrintButtons.forEach(function (k) {
var b = buttons[k];
if (b) b.disabled = false;
});
} else {
preview.classList.remove('loaded');
previewPlaceholder.classList.remove('hidden');
preview.src = '';
transformPrintButtons.forEach(function (k) {
var b = buttons[k];
if (b) b.disabled = true;
});
}
}
function refreshStatus() {
fetch('/api/status')
.then(function (r) { return r.json(); })
.then(function (data) {
statusFile.textContent = data.has_file ? (data.filename || 'File loaded') : 'No file';
statusPlotter.textContent = 'Plotter: ' + (data.plotter_ready ? 'Ready' : 'Not connected');
statusPlotter.classList.toggle('ready', data.plotter_ready);
statusPlotter.classList.toggle('not-ready', !data.plotter_ready);
updatePlotterInfo();
if (data.has_file) {
setLoaded(true);
updatePreview();
updateDimensions();
} else {
setLoaded(false);
if (scaleDims) scaleDims.innerHTML = '— × — <span class="unit">(≈ — × — mm)</span>';
}
})
.catch(function () {
statusFile.textContent = 'No file';
statusPlotter.textContent = 'Plotter: —';
setLoaded(false);
if (scaleDims) scaleDims.innerHTML = '— × — <span class="unit">(≈ — × — mm)</span>';
});
}
fileInput.addEventListener('change', function () {
const file = this.files && this.files[0];
if (!file) return;
preview.src = '';
preview.classList.remove('loaded');
previewPlaceholder.classList.remove('hidden');
previewPlaceholder.textContent = 'Loading…';
setMessage(printMessage, '');
const form = new FormData();
form.append('file', file);
fetch('/api/upload', {
method: 'POST',
body: form
})
.then(function (r) {
if (!r.ok) return r.json().then(function (d) { throw new Error(d.error || 'Upload failed'); });
return r.json();
})
.then(function () {
previewPlaceholder.textContent = 'Upload an HPGL file to preview';
refreshStatus();
})
.catch(function (e) {
previewPlaceholder.textContent = 'Upload an HPGL file to preview';
setMessage(printMessage, e.message || 'Upload failed', 'error');
refreshStatus();
});
});
function transform(action, payload) {
setMessage(printMessage, '');
var body = payload || { action: action };
fetch('/api/transform', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
})
.then(function (r) {
if (!r.ok) return r.json().then(function (d) { throw new Error(d.error || 'Transform failed'); });
return r.json();
})
.then(function () {
updatePreview();
updateDimensions();
})
.catch(function (e) {
setMessage(printMessage, e.message || 'Transform failed', 'error');
});
}
buttons.flip.addEventListener('click', function () { transform('flip'); });
buttons.rotate90.addEventListener('click', function () { transform('rotate', { action: 'rotate', angle: 90 }); });
buttons.rotate180.addEventListener('click', function () { transform('rotate', { action: 'rotate', angle: 180 }); });
buttons.scaleUp.addEventListener('click', function () { transform('scale', { action: 'scale', factor: 1.25 }); });
buttons.scaleDown.addEventListener('click', function () { transform('scale', { action: 'scale', factor: 0.8 }); });
buttons.centralize.addEventListener('click', function () { transform('centralize'); });
if (buttons.scaleToBounds) {
buttons.scaleToBounds.addEventListener('click', function () {
setMessage(printMessage, '');
fetch('/api/status')
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data.plotter_ready) {
setMessage(printMessage, 'Plotter not connected.', 'error');
return;
}
transform('scale_to_bounds', { action: 'scale_to_bounds' });
})
.catch(function () {
setMessage(printMessage, 'Plotter not connected.', 'error');
});
});
}
buttons.print.addEventListener('click', function () {
setMessage(printMessage, 'Sending to plotter…');
fetch('/api/print', { method: 'POST' })
.then(function (r) {
return r.json().then(function (data) {
if (!r.ok) throw new Error(data.error || 'Print failed');
return data;
});
})
.then(function () {
setMessage(printMessage, 'Sent to plotter.', 'success');
})
.catch(function (e) {
setMessage(printMessage, e.message || 'Print failed', 'error');
});
});
if (buttons.checkPlotter) {
buttons.checkPlotter.addEventListener('click', function () {
setMessage(printMessage, 'Checking plotter…');
fetch('/api/status')
.then(function (r) { return r.json(); })
.then(function (data) {
statusFile.textContent = data.has_file ? (data.filename || 'File loaded') : 'No file';
statusPlotter.textContent = 'Plotter: ' + (data.plotter_ready ? 'Ready' : 'Not connected');
statusPlotter.classList.toggle('ready', data.plotter_ready);
statusPlotter.classList.toggle('not-ready', !data.plotter_ready);
updatePlotterInfo();
setMessage(printMessage, data.plotter_ready ? 'Plotter: Ready' : 'Plotter: Not connected', data.plotter_ready ? 'success' : 'error');
})
.catch(function () {
statusPlotter.textContent = 'Plotter: —';
statusPlotter.classList.remove('ready');
statusPlotter.classList.add('not-ready');
updatePlotterInfo();
setMessage(printMessage, 'Plotter: Not connected', 'error');
});
});
}
preview.addEventListener('load', function () {
previewPlaceholder.classList.add('hidden');
});
function showTab(name) {
var isFile = (name === 'file');
tabFile.classList.toggle('active', isFile);
tabText.classList.toggle('active', !isFile);
if (panelFile) panelFile.classList.toggle('hidden', !isFile);
if (panelText) panelText.classList.toggle('hidden', isFile);
if (isFile && hpglFolderSelect && hpglFolderSelect.options.length <= 1) loadHpglFiles();
if (!isFile && fontSelect && fontSelect.options.length <= 1) loadFonts();
}
function loadHpglFiles() {
if (!hpglFolderSelect) return;
fetch('/api/hpgl_files')
.then(function (r) { return r.json(); })
.then(function (d) {
var opts = hpglFolderSelect.querySelectorAll('option');
for (var i = opts.length - 1; i >= 1; i--) opts[i].remove();
(d.files || []).forEach(function (f) {
var o = document.createElement('option');
o.value = f;
o.textContent = f;
hpglFolderSelect.appendChild(o);
});
})
.catch(function () {});
}
if (hpglFolderSelect) {
hpglFolderSelect.addEventListener('change', function () {
var filename = (this.value || '').trim();
if (!filename) return;
setMessage(printMessage, '');
fetch('/api/load_hpgl', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filename: filename })
})
.then(function (r) {
return r.json().then(function (d) {
if (!r.ok) throw new Error(d.error || 'Load failed');
return d;
});
})
.then(function () {
refreshStatus();
})
.catch(function (e) {
setMessage(printMessage, e.message || 'Load failed', 'error');
});
});
}
function loadFonts() {
if (!fontSelect) return;
fetch('/api/fonts')
.then(function (r) { return r.json(); })
.then(function (d) {
var opts = fontSelect.querySelectorAll('option');
for (var i = opts.length - 1; i >= 1; i--) opts[i].remove();
(d.fonts || []).forEach(function (f) {
var o = document.createElement('option');
o.value = f;
o.textContent = f;
fontSelect.appendChild(o);
});
})
.catch(function () {});
}
if (tabFile) tabFile.addEventListener('click', function () { showTab('file'); });
if (tabText) tabText.addEventListener('click', function () { showTab('text'); });
if (buttons.exportHpgl) {
buttons.exportHpgl.addEventListener('click', function () {
window.location.href = '/api/download_hpgl';
});
}
if (buttons.generateHpgl && textInput && fontSelect) {
buttons.generateHpgl.addEventListener('click', function () {
var text = (textInput.value || '').trim();
var font = (fontSelect.value || '').trim();
var size = parseInt(textSize.value, 10) || 72;
setMessage(textMessage, '');
if (!text) {
setMessage(textMessage, 'Enter some text.', 'error');
return;
}
if (!font) {
setMessage(textMessage, 'Select a font.', 'error');
return;
}
setMessage(textMessage, 'Generating…');
fetch('/api/text_to_hpgl', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text, font: font, size_pt: size })
})
.then(function (r) {
return r.json().then(function (d) {
if (!r.ok) throw new Error(d.error || 'Generate failed');
return d;
});
})
.then(function () {
setMessage(textMessage, 'Generated.', 'success');
refreshStatus();
})
.catch(function (e) {
setMessage(textMessage, e.message || 'Generate failed', 'error');
});
});
}
refreshStatus();
loadHpglFiles();
updatePlotterInfo();
setInterval(updatePlotterInfo, 10000);
})();