feat: add distinct scanner markers on map and radar
- Scanner positions shown as magenta stars (this scanner) - Peer scanners shown as cyan stars - Clear visual distinction from WiFi (orange circles) and BT (blue circles) - Radar view also shows scanner as star shape Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -45,6 +45,9 @@ data/scan_*.json
|
|||||||
data/*.db
|
data/*.db
|
||||||
data/profiles/
|
data/profiles/
|
||||||
data/logs/
|
data/logs/
|
||||||
|
data/rf-mapper.log
|
||||||
|
data/rf-mapper.pid
|
||||||
|
data/rf-mapper.started
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -413,15 +413,23 @@ function drawRadar() {
|
|||||||
ctx.lineTo(w - 20, cy);
|
ctx.lineTo(w - 20, cy);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// Draw center point (you)
|
// Draw center point (scanner) - magenta star-like
|
||||||
ctx.fillStyle = APP_CONFIG.colors.wifi;
|
ctx.fillStyle = '#ff0080';
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(cx, cy, 8, 0, Math.PI * 2);
|
// Draw a star shape
|
||||||
|
const starRadius = 10;
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const angle = (i * 144 - 90) * Math.PI / 180;
|
||||||
|
const x = cx + starRadius * Math.cos(angle);
|
||||||
|
const y = cy + starRadius * Math.sin(angle);
|
||||||
|
if (i === 0) ctx.moveTo(x, y);
|
||||||
|
else ctx.lineTo(x, y);
|
||||||
|
}
|
||||||
|
ctx.closePath();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.fillStyle = '#1a1a2e';
|
ctx.strokeStyle = 'white';
|
||||||
ctx.font = 'bold 8px sans-serif';
|
ctx.lineWidth = 1.5;
|
||||||
ctx.textAlign = 'center';
|
ctx.stroke();
|
||||||
ctx.fillText('YOU', cx, cy + 3);
|
|
||||||
|
|
||||||
if (!scanData) return;
|
if (!scanData) return;
|
||||||
|
|
||||||
@@ -578,17 +586,49 @@ function updateMapMarkers() {
|
|||||||
const lat = parseFloat(document.getElementById('lat-input').value);
|
const lat = parseFloat(document.getElementById('lat-input').value);
|
||||||
const lon = parseFloat(document.getElementById('lon-input').value);
|
const lon = parseFloat(document.getElementById('lon-input').value);
|
||||||
|
|
||||||
// Add center marker
|
// Add center marker (this scanner) - distinct star shape
|
||||||
|
const scannerIcon = `
|
||||||
|
<div style="position:relative;width:24px;height:24px;">
|
||||||
|
<svg viewBox="0 0 24 24" style="width:24px;height:24px;filter:drop-shadow(0 0 4px rgba(255,0,128,0.8));">
|
||||||
|
<polygon points="12,2 15,9 22,9 17,14 19,22 12,17 5,22 7,14 2,9 9,9" fill="#ff0080" stroke="white" stroke-width="1.5"/>
|
||||||
|
</svg>
|
||||||
|
</div>`;
|
||||||
const centerMarker = L.marker([lat, lon], {
|
const centerMarker = L.marker([lat, lon], {
|
||||||
icon: L.divIcon({
|
icon: L.divIcon({
|
||||||
className: 'center-marker',
|
className: 'center-marker scanner-marker',
|
||||||
html: `<div style="background:${APP_CONFIG.colors.wifi};width:16px;height:16px;border-radius:50%;border:3px solid white;box-shadow:0 0 10px rgba(0,255,136,0.5);"></div>`,
|
html: scannerIcon,
|
||||||
iconSize: [16, 16],
|
iconSize: [24, 24],
|
||||||
iconAnchor: [8, 8]
|
iconAnchor: [12, 12]
|
||||||
})
|
})
|
||||||
}).addTo(map).bindPopup('📍 Your Position');
|
}).addTo(map).bindPopup('📍 This Scanner');
|
||||||
markers.push(centerMarker);
|
markers.push(centerMarker);
|
||||||
|
|
||||||
|
// Add peer scanner markers (async, won't block)
|
||||||
|
fetch('/api/peers')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
(data.peers || []).forEach(peer => {
|
||||||
|
if (peer.latitude && peer.longitude) {
|
||||||
|
const peerIcon = `
|
||||||
|
<div style="position:relative;width:20px;height:20px;">
|
||||||
|
<svg viewBox="0 0 24 24" style="width:20px;height:20px;filter:drop-shadow(0 0 3px rgba(0,200,255,0.8));">
|
||||||
|
<polygon points="12,2 15,9 22,9 17,14 19,22 12,17 5,22 7,14 2,9 9,9" fill="#00c8ff" stroke="white" stroke-width="1.5"/>
|
||||||
|
</svg>
|
||||||
|
</div>`;
|
||||||
|
const peerMarker = L.marker([peer.latitude, peer.longitude], {
|
||||||
|
icon: L.divIcon({
|
||||||
|
className: 'peer-marker scanner-marker',
|
||||||
|
html: peerIcon,
|
||||||
|
iconSize: [20, 20],
|
||||||
|
iconAnchor: [10, 10]
|
||||||
|
})
|
||||||
|
}).addTo(map).bindPopup(`📡 ${peer.name || peer.scanner_id}<br>Floor: ${peer.floor ?? '?'}`);
|
||||||
|
markers.push(peerMarker);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {}); // Ignore errors
|
||||||
|
|
||||||
const wifi = filters.wifi ? (scanData.wifi_networks || []) : [];
|
const wifi = filters.wifi ? (scanData.wifi_networks || []) : [];
|
||||||
const bt = filters.bluetooth ? (scanData.bluetooth_devices || []) : [];
|
const bt = filters.bluetooth ? (scanData.bluetooth_devices || []) : [];
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@
|
|||||||
colors: {
|
colors: {
|
||||||
wifi: '#f59f00', // Orange for WiFi
|
wifi: '#f59f00', // Orange for WiFi
|
||||||
bluetooth: '#4dabf7', // Blue for Bluetooth
|
bluetooth: '#4dabf7', // Blue for Bluetooth
|
||||||
|
scanner: '#ff0080', // Magenta for scanner positions
|
||||||
|
peerScanner: '#00c8ff', // Cyan for peer scanners
|
||||||
warning: '#ffd93d',
|
warning: '#ffd93d',
|
||||||
danger: '#ff6b6b'
|
danger: '#ff6b6b'
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user