feat: move sensor details to sheet, implement placement on floor plan

This commit is contained in:
2026-05-14 17:22:26 +02:00
parent 90c946d710
commit 52605f1390
12 changed files with 655 additions and 218 deletions
+34 -73
View File
@@ -1,7 +1,4 @@
/* globals: Konva, preact, preactHooks, htm */
const { h, render } = preact;
const { useState } = preactHooks;
const html = htm.bind(h);
/* globals: Konva */
// ---------------------------------------------------------------------------
// Constants & mutable state
@@ -20,9 +17,6 @@ let _dragging = false; // true while any room group is being dragged
let _dimRoom = null;
let _dimGroup = null;
// Exposed so the Preact overlay can update its tooltip imperatively.
let _setTooltip = (_v) => {};
// ---------------------------------------------------------------------------
// Stage & layers
// ---------------------------------------------------------------------------
@@ -365,27 +359,23 @@ function renderSensors() {
listening: false,
}));
group.on('click tap', () => _onSensorTap(sensor, group, label));
group.on('dragend', () => _onSensorDragEnd(sensor, group, room));
let pressTimer = null;
group.on('mousedown touchstart', () => {
pressTimer = setTimeout(() => {
notifyFlutter({ type: 'sensorTapped', id: String(sensor.id) });
pressTimer = null;
}, 500);
});
group.on('mouseup touchend touchcancel dragstart', () => {
clearTimeout(pressTimer);
pressTimer = null;
});
group.on('dragend', () => _onSensorDragEnd(sensor, group, room));
sensorsLayer.add(group);
});
sensorsLayer.batchDraw();
}
function _onSensorTap(sensor, group, label) {
if (mode === 'view') {
const scale = stage.scaleX();
_setTooltip({
id: String(sensor.id),
name: label,
x: group.x() * scale + stage.x(),
y: group.y() * scale + stage.y(),
});
} else {
notifyFlutter({ type: 'sensorTapped', id: String(sensor.id) });
}
}
function _onSensorDragEnd(sensor, group, originalRoom) {
const newAbsX = group.x() / PPM;
const newAbsY = group.y() / PPM;
@@ -461,57 +451,9 @@ function _fitToRooms() {
});
}
// ---------------------------------------------------------------------------
// Preact overlay — sensor tooltip
// ---------------------------------------------------------------------------
function Tooltip({ id, name, x, y, onClose }) {
return html`
<div style=${{
position: 'absolute',
left: `${x + 14}px`,
top: `${y - 48}px`,
background: '#ffffff',
borderRadius: '8px',
padding: '8px 12px',
boxShadow: '0 2px 12px rgba(0,0,0,0.18)',
pointerEvents: 'auto',
minWidth: '130px',
fontFamily: 'Roboto, sans-serif',
}}>
<div style=${{ fontSize: '13px', fontWeight: '500', color: '#212121', marginBottom: '6px' }}>
${name}
</div>
<div style=${{ display: 'flex', gap: '10px' }}>
<button
style=${{ fontSize: '12px', border: 'none', background: 'none', color: '#1565C0', cursor: 'pointer', padding: 0 }}
onClick=${() => { notifyFlutter({ type: 'sensorTapped', id }); onClose(); }}>
View details
</button>
<button
style=${{ fontSize: '12px', border: 'none', background: 'none', color: '#9e9e9e', cursor: 'pointer', padding: 0 }}
onClick=${onClose}>
</button>
</div>
</div>
`;
}
function App() {
const [tooltip, setTip] = useState(null);
_setTooltip = setTip;
return tooltip
? html`<${Tooltip} ...${tooltip} onClose=${() => setTip(null)} />`
: null;
}
render(html`<${App} />`, document.getElementById('overlay'));
// Dismiss tooltip and dimensions when tapping the stage background.
// Dismiss dimensions when tapping the stage background.
stage.on('click tap', (e) => {
if (e.target === stage) {
_setTooltip(null);
_clearDimensions();
notifyFlutter({ type: 'selectionCleared' });
}
@@ -572,7 +514,6 @@ window.companion = {
tagsLayer.visible(!edit);
particlesLayer.visible(!edit);
_clearDimensions();
_setTooltip(null);
stage.batchDraw();
},
@@ -602,4 +543,24 @@ window.companion = {
fitToRooms() {
_fitToRooms();
},
getPositionAtCenter() {
const s = stage.scaleX();
const cx = (stage.width() / 2 - stage.x()) / s / PPM;
const cy = (stage.height() / 2 - stage.y()) / s / PPM;
let result = { type: 'positionAtCenter', roomId: null };
for (const room of rooms) {
if (cx >= room.x && cx <= room.x + room.width &&
cy >= room.y && cy <= room.y + room.height) {
result = {
type: 'positionAtCenter',
roomId: room.id,
x: cx - room.x,
y: cy - room.y,
};
break;
}
}
FlutterBridge.postMessage(JSON.stringify(result));
},
};