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()