diff --git a/meshview/templates/api-packets.html b/meshview/templates/api-packets.html
new file mode 100644
index 0000000..df9e627
--- /dev/null
+++ b/meshview/templates/api-packets.html
@@ -0,0 +1,167 @@
+
+
+
+
+ API Documentation - Packets
+
+
+
+
+
+
+
+
+
+
diff --git a/meshview/templates/nodegraph.html b/meshview/templates/nodegraph.html
index 78129b0..082bd5f 100644
--- a/meshview/templates/nodegraph.html
+++ b/meshview/templates/nodegraph.html
@@ -111,7 +111,7 @@
value: `{{ node.long_name | tojson }}`,
symbol: 'circle',
symbolSize: 15,
- itemStyle: { color: '#007bff' },
+ itemStyle: { color: '#007bff', opacity: 1},
label: {
show: true,
position: 'right',
@@ -138,7 +138,8 @@
originalColor: `{{ edge.originalColor }}`,
lineStyle: {
color: '#d3d3d3',
- width: 2
+ width: 2,
+ opacity: 1
}
}{% if not loop.last %},{% endif %}
{% endfor %}
@@ -148,7 +149,6 @@
let filteredEdges = [];
let selectedChannel = 'LongFast';
let lastSelectedNode = null;
- let currentZoom = 1;
function populateChannelDropdown() {
const channelSelect = document.getElementById('channel-select');
@@ -176,25 +176,43 @@
}
function updateChart() {
- const baseSize = 15;
- const adjustedSize = baseSize / currentZoom;
-
- const updatedNodes = filteredNodes.map(node => ({
- ...node,
- symbolSize: node.name === lastSelectedNode ? adjustedSize : adjustedSize,
- itemStyle: {
- color: node.name === lastSelectedNode ? '#ff8c00' : '#007bff'
+ const updatedNodes = filteredNodes.map(node => {
+ let opacity = 1;
+ let color = '#007bff';
+ if (lastSelectedNode) {
+ const connected = filteredEdges.some(e =>
+ (e.source === node.name && e.target === lastSelectedNode) ||
+ (e.target === node.name && e.source === lastSelectedNode)
+ );
+ if (node.name === lastSelectedNode) {
+ color = '#ff8c00'; // selected node orange
+ opacity = 1;
+ } else if (connected) {
+ opacity = 1; // keep neighbors visible
+ } else {
+ opacity = 0.4; // dim unrelated
+ }
}
- }));
+ return {
+ ...node,
+ itemStyle: { color, opacity }
+ };
+ });
const updatedEdges = filteredEdges.map(edge => {
- const connected = edge.source === lastSelectedNode || edge.target === lastSelectedNode;
+ let opacity = .1;
+ let width = 2;
+ if (lastSelectedNode) {
+ const connected = edge.source === lastSelectedNode || edge.target === lastSelectedNode;
+ opacity = connected ? 1 : 0.05;
+ width = connected ? 2 : 1;
+ }
return {
...edge,
lineStyle: {
- color: connected ? edge.originalColor : '#ccc',
- width: connected ? 4 : 2,
- opacity: connected ? 1 : 0.2
+ color: edge.originalColor || '#d3d3d3',
+ width,
+ opacity
}
};
});
@@ -211,16 +229,17 @@
});
}
- chart.on('roam', function () {
- const option = chart.getOption();
- const zoom = option.series?.[0]?.zoom || 1;
- currentZoom = zoom;
- updateChart();
- });
-
chart.on('click', function (params) {
if (params.dataType === 'node') {
updateSelectedNode(params.data.name);
+ } else {
+ // background click -> reset
+ lastSelectedNode = null;
+ updateChart();
+ document.getElementById('node-long-name').innerText = '';
+ document.getElementById('node-short-name').innerText = '';
+ document.getElementById('node-role').innerText = '';
+ document.getElementById('node-hw-model').innerText = '';
}
});
diff --git a/meshview/web.py b/meshview/web.py
index 782843d..145baad 100644
--- a/meshview/web.py
+++ b/meshview/web.py
@@ -1466,17 +1466,7 @@ async def get_config(request):
return web.json_response({"error": "Invalid configuration format"}, status=500)
-@routes.get("/api-stats")
-async def packet_details(request):
- template = env.get_template("api-stats.html")
- return web.Response(
- text=template.render(
- site_config = CONFIG,
- SOFTWARE_RELEASE=SOFTWARE_RELEASE,
- ),
- content_type="text/html",
- )
# API Section
#######################################################################
# How this works
@@ -1707,6 +1697,31 @@ async def api_stats(request):
return web.json_response(stats)
+@routes.get("/api-stats")
+async def packet_details(request):
+
+ template = env.get_template("api-stats.html")
+ return web.Response(
+ text=template.render(
+ site_config = CONFIG,
+ SOFTWARE_RELEASE=SOFTWARE_RELEASE,
+ ),
+ content_type="text/html",
+ )
+
+
+@routes.get("/api-packets")
+async def packet_details(request):
+
+ template = env.get_template("api-packets.html")
+ return web.Response(
+ text=template.render(
+ site_config = CONFIG,
+ SOFTWARE_RELEASE=SOFTWARE_RELEASE,
+ ),
+ content_type="text/html",
+ )
+
async def run_server():
app = web.Application()