Add manual pick on Board Control. Closes #26
This commit is contained in:
@@ -13,6 +13,7 @@ let bounds = { xMin: -150, xMax: 150, yMin: -30, yMax: 145 };
|
|||||||
let currentBg = localStorage.getItem('wiji_bg') || 'default';
|
let currentBg = localStorage.getItem('wiji_bg') || 'default';
|
||||||
let steps1 = 0;
|
let steps1 = 0;
|
||||||
let steps2 = 0;
|
let steps2 = 0;
|
||||||
|
let isManualPickMode = false;
|
||||||
|
|
||||||
function syncStateFromStorage() {
|
function syncStateFromStorage() {
|
||||||
isHomed = localStorage.getItem('wiji_homed') === 'true';
|
isHomed = localStorage.getItem('wiji_homed') === 'true';
|
||||||
@@ -86,7 +87,12 @@ function buildHTML() {
|
|||||||
<div class="board-grid">
|
<div class="board-grid">
|
||||||
<!-- ── Map Area ─────────────────────────────────────── -->
|
<!-- ── Map Area ─────────────────────────────────────── -->
|
||||||
<div class="card" style="display:flex; flex-direction:column; padding: 12px; position:relative;">
|
<div class="card" style="display:flex; flex-direction:column; padding: 12px; position:relative;">
|
||||||
<div class="card-header"><span class="card-title">Interactive Map</span></div>
|
<div class="card-header" style="display:flex; justify-content:space-between; align-items:center;">
|
||||||
|
<span class="card-title">Interactive Map</span>
|
||||||
|
<button id="btn-manual-pick" class="btn btn-secondary" style="padding: 4px 8px; font-size: 0.8rem; display:flex; align-items:center; gap:4px; border-radius: var(--radius-sm);">
|
||||||
|
<span style="font-size: 1.1rem;">⌖</span> Manual Pick
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="flex:1; display:flex; align-items:flex-start; justify-content:center; overflow:hidden;">
|
<div style="flex:1; display:flex; align-items:flex-start; justify-content:center; overflow:hidden;">
|
||||||
<div id="map-container" style="position: relative; width: 100%; max-width: 800px; background: #111; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.5);">
|
<div id="map-container" style="position: relative; width: 100%; max-width: 800px; background: #111; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.5);">
|
||||||
@@ -430,6 +436,59 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Manual Pick Mode ──────────────────────────────────────
|
||||||
|
const btnManualPick = document.getElementById('btn-manual-pick');
|
||||||
|
const mapContainer = document.getElementById('map-container');
|
||||||
|
|
||||||
|
if (btnManualPick && mapContainer) {
|
||||||
|
btnManualPick.addEventListener('click', () => {
|
||||||
|
isManualPickMode = !isManualPickMode;
|
||||||
|
if (isManualPickMode) {
|
||||||
|
btnManualPick.classList.add('btn-success');
|
||||||
|
btnManualPick.classList.remove('btn-secondary');
|
||||||
|
mapContainer.style.cursor = 'crosshair';
|
||||||
|
} else {
|
||||||
|
btnManualPick.classList.remove('btn-success');
|
||||||
|
btnManualPick.classList.add('btn-secondary');
|
||||||
|
mapContainer.style.cursor = 'default';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mapContainer.addEventListener('click', (e) => {
|
||||||
|
if (!isManualPickMode) return;
|
||||||
|
// Ignore clicks on existing markers
|
||||||
|
if (e.target.classList.contains('spot-marker')) return;
|
||||||
|
|
||||||
|
const rect = mapContainer.getBoundingClientRect();
|
||||||
|
const xClick = e.clientX - rect.left;
|
||||||
|
const yClick = e.clientY - rect.top;
|
||||||
|
|
||||||
|
const w = bounds.xMax - bounds.xMin;
|
||||||
|
const h = bounds.yMax - bounds.yMin;
|
||||||
|
|
||||||
|
const x = bounds.xMin + (xClick / rect.width) * w;
|
||||||
|
const y = bounds.yMax - (yClick / rect.height) * h;
|
||||||
|
|
||||||
|
const check = IK.checkWorkspace(x, y);
|
||||||
|
if (!check.valid) {
|
||||||
|
UI.log(check.reason, 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute move
|
||||||
|
if (listEl) listEl.value = ''; // Deselect predefined spots
|
||||||
|
goBtn.disabled = true;
|
||||||
|
|
||||||
|
executeMove({ id: 'manual', label: `Manual [${x.toFixed(1)}, ${y.toFixed(1)}]`, x, y });
|
||||||
|
|
||||||
|
// Turn off mode automatically (one-shot)
|
||||||
|
isManualPickMode = false;
|
||||||
|
btnManualPick.classList.remove('btn-success');
|
||||||
|
btnManualPick.classList.add('btn-secondary');
|
||||||
|
mapContainer.style.cursor = 'default';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ── Sync Steps from BLE ───────────────────────────────────
|
// ── Sync Steps from BLE ───────────────────────────────────
|
||||||
const onBLEStatus = (e) => {
|
const onBLEStatus = (e) => {
|
||||||
const msg = e.detail;
|
const msg = e.detail;
|
||||||
|
|||||||
Reference in New Issue
Block a user