Add smart tick labels and move direction arrows inside screen
Some checks failed
Validate / validate (push) Failing after 8s
Some checks failed
Validate / validate (push) Failing after 8s
- Add intermediate tick labels at nice intervals (5, 10, 25, 50, 100, 250, 500) with max 5 labels per edge and pixel-based overlap prevention - Move direction chevrons from outside edge bars to inside the screen area - Make chevrons filled with green fill and white outline for better contrast Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1219,12 +1219,13 @@ function renderCalibrationCanvas() {
|
|||||||
right: ox + cW + 3, // labels right of right edge
|
right: ox + cW + 3, // labels right of right edge
|
||||||
};
|
};
|
||||||
|
|
||||||
// Arrow positions (further out than tick labels)
|
// Arrow positions (inside the screen area, near each edge bar)
|
||||||
|
const arrowInset = 12;
|
||||||
const arrowPos = {
|
const arrowPos = {
|
||||||
top: oy - 10,
|
top: oy + ch + arrowInset,
|
||||||
bottom: oy + cH + 10,
|
bottom: oy + cH - ch - arrowInset,
|
||||||
left: ox - 10,
|
left: ox + cw + arrowInset,
|
||||||
right: ox + cW + 10,
|
right: ox + cW - cw - arrowInset,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Draw ticks and direction arrows for each segment
|
// Draw ticks and direction arrows for each segment
|
||||||
@@ -1235,17 +1236,55 @@ function renderCalibrationCanvas() {
|
|||||||
const count = seg.led_count;
|
const count = seg.led_count;
|
||||||
if (count === 0) return;
|
if (count === 0) return;
|
||||||
|
|
||||||
// Show only first and last LED index per edge, plus LED 0 if offset > 0
|
// Mandatory ticks: first and last LED index per edge, plus LED 0 if offset > 0
|
||||||
const labelsToShow = new Set();
|
const labelsToShow = new Set();
|
||||||
labelsToShow.add(0);
|
labelsToShow.add(0);
|
||||||
if (count > 1) labelsToShow.add(count - 1);
|
if (count > 1) labelsToShow.add(count - 1);
|
||||||
|
|
||||||
// Add LED 0 tick on the edge where it wraps
|
|
||||||
if (offset > 0 && totalLeds > 0) {
|
if (offset > 0 && totalLeds > 0) {
|
||||||
const zeroPos = (totalLeds - seg.led_start % totalLeds) % totalLeds;
|
const zeroPos = (totalLeds - seg.led_start % totalLeds) % totalLeds;
|
||||||
if (zeroPos < count) labelsToShow.add(zeroPos);
|
if (zeroPos < count) labelsToShow.add(zeroPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add intermediate ticks at "nice" intervals (max 5 labels per edge)
|
||||||
|
if (count > 2) {
|
||||||
|
const edgeLen = geo.horizontal ? (geo.x2 - geo.x1) : (geo.y2 - geo.y1);
|
||||||
|
const maxDigits = String(totalLeds > 0 ? totalLeds - 1 : count - 1).length;
|
||||||
|
const minSpacing = geo.horizontal ? maxDigits * 7 + 8 : 22;
|
||||||
|
|
||||||
|
const maxIntermediate = Math.max(0, 5 - labelsToShow.size);
|
||||||
|
const niceSteps = [5, 10, 25, 50, 100, 250, 500];
|
||||||
|
let step = niceSteps[niceSteps.length - 1];
|
||||||
|
for (const s of niceSteps) {
|
||||||
|
if (Math.floor(count / s) <= maxIntermediate) {
|
||||||
|
step = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pixel position helper (0..edgeLen along the edge)
|
||||||
|
const tickPx = i => {
|
||||||
|
const f = i / (count - 1);
|
||||||
|
return (seg.reverse ? (1 - f) : f) * edgeLen;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collect pixel positions of mandatory ticks
|
||||||
|
const placed = [];
|
||||||
|
labelsToShow.forEach(i => placed.push(tickPx(i)));
|
||||||
|
|
||||||
|
// Add ticks at LED indices divisible by step
|
||||||
|
for (let i = 1; i < count - 1; i++) {
|
||||||
|
const idx = totalLeds > 0 ? (seg.led_start + i) % totalLeds : seg.led_start + i;
|
||||||
|
if (idx % step === 0) {
|
||||||
|
const px = tickPx(i);
|
||||||
|
if (!placed.some(p => Math.abs(px - p) < minSpacing)) {
|
||||||
|
labelsToShow.add(i);
|
||||||
|
placed.push(px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tick styling
|
// Tick styling
|
||||||
const tickLen = 5;
|
const tickLen = 5;
|
||||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
|
ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
|
||||||
@@ -1291,8 +1330,8 @@ function renderCalibrationCanvas() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw direction chevron at midpoint, outside the edge bar
|
// Draw direction chevron at midpoint, inside the screen area
|
||||||
const s = 5;
|
const s = 7;
|
||||||
let mx, my, angle;
|
let mx, my, angle;
|
||||||
if (geo.horizontal) {
|
if (geo.horizontal) {
|
||||||
mx = (geo.x1 + geo.x2) / 2;
|
mx = (geo.x1 + geo.x2) / 2;
|
||||||
@@ -1307,14 +1346,17 @@ function renderCalibrationCanvas() {
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(mx, my);
|
ctx.translate(mx, my);
|
||||||
ctx.rotate(angle);
|
ctx.rotate(angle);
|
||||||
ctx.strokeStyle = '#4CAF50';
|
ctx.fillStyle = 'rgba(76, 175, 80, 0.85)';
|
||||||
ctx.lineWidth = 1.5;
|
ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
ctx.lineCap = 'round';
|
ctx.lineCap = 'round';
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(-s * 0.4, -s * 0.5);
|
ctx.moveTo(-s * 0.5, -s * 0.6);
|
||||||
ctx.lineTo(s * 0.4, 0);
|
ctx.lineTo(s * 0.5, 0);
|
||||||
ctx.lineTo(-s * 0.4, s * 0.5);
|
ctx.lineTo(-s * 0.5, s * 0.6);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user