Improve calibration UI: animated config sections, always-visible tick labels, zoom-independent fonts, smooth line selection

- Replace <details> with grid-template-rows animated expand for template config sections
- Always show edge boundary tick labels in both simple and advanced calibration
- Make tick labels, monitor names, and tick marks zoom-independent in advanced calibration
- Place new monitors next to existing ones and fit view on add
- Fix layout jump on line selection: toggle class in-place instead of DOM rebuild
- Use transparent border-left on all line items to prevent content shift

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 15:10:29 +03:00
parent 353a1c2d85
commit 32e0f0eb5c
5 changed files with 1086 additions and 57 deletions

View File

@@ -238,7 +238,8 @@ export async function showCSSCalibration(cssId) {
if (!cssResp.ok) { showToast(t('calibration.error.css_load_failed'), 'error'); return; }
const source = await cssResp.json();
const calibration = source.calibration || {};
const calibration = source.calibration || {
}
// Set CSS mode — clear device-id, set css-id
document.getElementById('calibration-device-id').value = '';
@@ -527,7 +528,6 @@ export function renderCalibrationCanvas() {
}
const labelsToShow = new Set([...specialTicks]);
const tickLinesOnly = new Set();
if (count > 2) {
const edgeLen = geo.horizontal ? (geo.x2 - geo.x1) : (geo.y2 - geo.y1);
@@ -563,13 +563,8 @@ export function renderCalibrationCanvas() {
edgeBounds.forEach(bi => {
if (labelsToShow.has(bi) || specialTicks.has(bi)) return;
const px = tickPx(bi);
if (placed.some(p => Math.abs(px - p) < minSpacing)) {
tickLinesOnly.add(bi);
} else {
labelsToShow.add(bi);
placed.push(px);
}
labelsToShow.add(bi);
placed.push(tickPx(bi));
});
} else {
edgeBounds.forEach(i => labelsToShow.add(i));
@@ -607,22 +602,6 @@ export function renderCalibrationCanvas() {
}
});
tickLinesOnly.forEach(i => {
const fraction = count > 1 ? i / (count - 1) : 0.5;
const displayFraction = seg.reverse ? (1 - fraction) : fraction;
if (geo.horizontal) {
const tx = geo.x1 + displayFraction * (geo.x2 - geo.x1);
const axisY = axisPos[seg.edge];
const tickDir = seg.edge === 'top' ? 1 : -1;
ctx.beginPath(); ctx.moveTo(tx, axisY); ctx.lineTo(tx, axisY + tickDir * tickLenLong); ctx.stroke();
} else {
const ty = geo.y1 + displayFraction * (geo.y2 - geo.y1);
const axisX = axisPos[seg.edge];
const tickDir = seg.edge === 'left' ? 1 : -1;
ctx.beginPath(); ctx.moveTo(axisX, ty); ctx.lineTo(axisX + tickDir * tickLenLong, ty); ctx.stroke();
}
});
const s = 7;
let mx, my, angle;
if (geo.horizontal) {
@@ -934,6 +913,7 @@ export async function saveCalibration() {
const spans = window.edgeSpans || {};
const calibration = {
mode: 'simple',
layout, start_position: startPosition, offset,
leds_top: topLeds, leds_right: rightLeds, leds_bottom: bottomLeds, leds_left: leftLeds,
span_top_start: spans.top?.start ?? 0, span_top_end: spans.top?.end ?? 1,