Enhance BT Locate with smoothing, confidence, strongest signal, and export

This commit is contained in:
Smittix
2026-02-19 12:51:25 +00:00
parent 0346d154c4
commit 16fa2b4270
3 changed files with 1124 additions and 224 deletions
+154 -24
View File
@@ -163,12 +163,29 @@
margin-top: 2px; margin-top: 2px;
} }
.btl-hud-controls { .btl-hud-controls {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
flex-shrink: 0; flex-shrink: 0;
} }
.btl-hud-export-row {
display: flex;
gap: 5px;
align-items: center;
}
.btl-hud-export-format {
min-width: 62px;
padding: 3px 6px;
font-size: 10px;
font-family: var(--font-mono);
color: var(--text-secondary);
background: rgba(0, 0, 0, 0.45);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 4px;
}
.btl-hud-audio-toggle { .btl-hud-audio-toggle {
display: flex; display: flex;
@@ -253,19 +270,108 @@
padding: 8px; padding: 8px;
} }
.btl-map-container { .btl-map-container {
flex: 1; flex: 1;
min-height: 250px; min-height: 250px;
border-radius: 8px; position: relative;
overflow: hidden; border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1); overflow: hidden;
} border: 1px solid rgba(255, 255, 255, 0.1);
}
#btLocateMap { #btLocateMap {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: #1a1a2e; background: #1a1a2e;
} }
.btl-map-overlay-controls {
position: absolute;
top: 10px;
right: 10px;
z-index: 450;
display: flex;
flex-direction: column;
gap: 4px;
padding: 7px 8px;
border-radius: 7px;
background: rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255, 255, 255, 0.15);
backdrop-filter: blur(4px);
}
.btl-map-overlay-toggle {
display: flex;
align-items: center;
gap: 5px;
font-size: 10px;
color: var(--text-secondary);
font-family: var(--font-mono);
cursor: pointer;
white-space: nowrap;
}
.btl-map-overlay-toggle input[type="checkbox"] {
margin: 0;
}
.btl-map-overlay-toggle input[type="checkbox"]:disabled + span {
opacity: 0.45;
}
.btl-map-heat-legend {
position: absolute;
left: 10px;
bottom: 10px;
z-index: 430;
min-width: 120px;
padding: 6px 8px;
border-radius: 7px;
background: rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255, 255, 255, 0.14);
backdrop-filter: blur(4px);
}
.btl-map-heat-label {
display: block;
font-size: 9px;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.7px;
margin-bottom: 4px;
}
.btl-map-heat-bar {
height: 7px;
border-radius: 4px;
background: linear-gradient(90deg, #2563eb 0%, #16a34a 40%, #f59e0b 70%, #ef4444 100%);
border: 1px solid rgba(255, 255, 255, 0.15);
}
.btl-map-heat-scale {
display: flex;
justify-content: space-between;
margin-top: 3px;
font-size: 8px;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.btl-map-track-stats {
position: absolute;
right: 10px;
bottom: 10px;
z-index: 430;
padding: 5px 8px;
border-radius: 7px;
background: rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255, 255, 255, 0.14);
color: var(--text-secondary);
font-size: 10px;
font-family: var(--font-mono);
backdrop-filter: blur(4px);
}
.btl-rssi-chart-container { .btl-rssi-chart-container {
height: 100px; height: 100px;
@@ -405,7 +511,7 @@
RESPONSIVE — stack HUD vertically on narrow RESPONSIVE — stack HUD vertically on narrow
============================================ */ ============================================ */
@media (max-width: 900px) { @media (max-width: 900px) {
.btl-hud { .btl-hud {
flex-wrap: wrap; flex-wrap: wrap;
gap: 10px; gap: 10px;
@@ -422,9 +528,33 @@
justify-content: space-around; justify-content: space-around;
} }
.btl-hud-controls { .btl-hud-controls {
flex-direction: row; flex-direction: row;
width: 100%; width: 100%;
justify-content: center; justify-content: center;
} flex-wrap: wrap;
} }
.btl-hud-export-row {
width: 100%;
justify-content: center;
}
.btl-map-overlay-controls {
top: 8px;
right: 8px;
gap: 3px;
padding: 6px 7px;
}
.btl-map-heat-legend {
left: 8px;
bottom: 8px;
}
.btl-map-track-stats {
right: 8px;
bottom: 8px;
font-size: 9px;
}
}
File diff suppressed because it is too large Load Diff
+43 -2
View File
@@ -35,9 +35,11 @@
{% if offline_settings.assets_source == 'local' %} {% if offline_settings.assets_source == 'local' %}
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
<script src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script> <script src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
<script src="{{ url_for('static', filename='vendor/leaflet-heat/leaflet-heat.js') }}"></script>
{% else %} {% else %}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin="" /> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
{% endif %} {% endif %}
<!-- Chart.js for signal strength graphs - Conditional CDN/Local loading --> <!-- Chart.js for signal strength graphs - Conditional CDN/Local loading -->
{% if offline_settings.assets_source == 'local' %} {% if offline_settings.assets_source == 'local' %}
@@ -65,7 +67,7 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/sstv-general.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/sstv-general.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/gps.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/gps.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/subghz.css') }}?v={{ version }}&r=subghz_layout9"> <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/subghz.css') }}?v={{ version }}&r=subghz_layout9">
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/bt_locate.css') }}?v={{ version }}&r=btlocate2"> <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/bt_locate.css') }}?v={{ version }}&r=btlocate4">
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/space-weather.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/space-weather.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/components/function-strip.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/components/function-strip.css') }}">
@@ -2240,6 +2242,14 @@
<input type="checkbox" id="btLocateAudioEnable" onchange="BtLocate.toggleAudio()"> <input type="checkbox" id="btLocateAudioEnable" onchange="BtLocate.toggleAudio()">
<span>Audio</span> <span>Audio</span>
</label> </label>
<div class="btl-hud-export-row">
<select id="btLocateExportFormat" class="btl-hud-export-format">
<option value="csv">CSV</option>
<option value="gpx">GPX</option>
<option value="kml">KML</option>
</select>
<button class="btl-hud-clear-btn" onclick="BtLocate.exportTrail()">Export</button>
</div>
<button class="btl-hud-clear-btn" onclick="BtLocate.clearTrail()">Clear Trail</button> <button class="btl-hud-clear-btn" onclick="BtLocate.clearTrail()">Clear Trail</button>
</div> </div>
</div> </div>
@@ -2252,12 +2262,43 @@
<span class="btl-hud-info-item" id="btLocateGpsStatus">GPS: --</span> <span class="btl-hud-info-item" id="btLocateGpsStatus">GPS: --</span>
<span class="btl-hud-info-sep">&middot;</span> <span class="btl-hud-info-sep">&middot;</span>
<span class="btl-hud-info-item" id="btLocateLastSeen">Last: --</span> <span class="btl-hud-info-item" id="btLocateLastSeen">Last: --</span>
<span class="btl-hud-info-sep">&middot;</span>
<span class="btl-hud-info-item" id="btLocateConfidenceInfo">Confidence: --</span>
<span class="btl-hud-info-sep">&middot;</span>
<span class="btl-hud-info-item" id="btLocateBestSignal">Best: --</span>
</div> </div>
<div id="btLocateDiag" class="btl-hud-diag"></div> <div id="btLocateDiag" class="btl-hud-diag"></div>
</div> </div>
</div> </div>
<div class="btl-map-container"> <div class="btl-map-container">
<div id="btLocateMap"></div> <div id="btLocateMap"></div>
<div class="btl-map-overlay-controls">
<label class="btl-map-overlay-toggle">
<input type="checkbox" id="btLocateHeatmapEnable" onchange="BtLocate.toggleHeatmap()">
<span>Heatmap</span>
</label>
<label class="btl-map-overlay-toggle">
<input type="checkbox" id="btLocateMovementEnable" onchange="BtLocate.toggleMovement()">
<span>Movement</span>
</label>
<label class="btl-map-overlay-toggle">
<input type="checkbox" id="btLocateFollowEnable" onchange="BtLocate.toggleFollow()">
<span>Auto follow</span>
</label>
<label class="btl-map-overlay-toggle">
<input type="checkbox" id="btLocateSmoothEnable" onchange="BtLocate.toggleSmoothing()">
<span>Smooth path</span>
</label>
</div>
<div class="btl-map-heat-legend" id="btLocateHeatLegend">
<span class="btl-map-heat-label">Signal Heat</span>
<div class="btl-map-heat-bar"></div>
<div class="btl-map-heat-scale">
<span>Weak</span>
<span>Strong</span>
</div>
</div>
<div class="btl-map-track-stats" id="btLocateTrackStats">Track: 0 m | 0 pts</div>
</div> </div>
<div class="btl-rssi-chart-container"> <div class="btl-rssi-chart-container">
<span class="btl-chart-label">RSSI History</span> <span class="btl-chart-label">RSSI History</span>
@@ -3181,7 +3222,7 @@
<script src="{{ url_for('static', filename='js/modes/dmr.js') }}"></script> <script src="{{ url_for('static', filename='js/modes/dmr.js') }}"></script>
<script src="{{ url_for('static', filename='js/modes/websdr.js') }}"></script> <script src="{{ url_for('static', filename='js/modes/websdr.js') }}"></script>
<script src="{{ url_for('static', filename='js/modes/subghz.js') }}?v={{ version }}&r=subghz_layout9"></script> <script src="{{ url_for('static', filename='js/modes/subghz.js') }}?v={{ version }}&r=subghz_layout9"></script>
<script src="{{ url_for('static', filename='js/modes/bt_locate.js') }}?v={{ version }}&r=btlocate2"></script> <script src="{{ url_for('static', filename='js/modes/bt_locate.js') }}?v={{ version }}&r=btlocate4"></script>
<script src="{{ url_for('static', filename='js/modes/analytics.js') }}"></script> <script src="{{ url_for('static', filename='js/modes/analytics.js') }}"></script>
<script src="{{ url_for('static', filename='js/modes/space-weather.js') }}"></script> <script src="{{ url_for('static', filename='js/modes/space-weather.js') }}"></script>