mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-06-11 01:34:52 +02:00
5f97274e80
- Now the database process and the web process are separate. - Added Map - Added new graphing tools
191 lines
5.9 KiB
HTML
191 lines
5.9 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block head %}
|
|
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
|
|
{% endblock %}
|
|
|
|
{% block css %}
|
|
#mynetwork {
|
|
width: 100%;
|
|
height: 100vh;
|
|
max-width: 2000px;
|
|
max-height: 2000px;
|
|
border: 1px solid lightgray;
|
|
background-color: white;
|
|
}
|
|
|
|
.legend {
|
|
position: absolute;
|
|
bottom: 10px;
|
|
left: 10px;
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
padding: 5px;
|
|
border-radius: 5px;
|
|
border: 1px solid #ccc;
|
|
font-size: 12px;
|
|
color: #333;
|
|
}
|
|
|
|
#node-info {
|
|
position: absolute;
|
|
bottom: 10px;
|
|
right: 10px;
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
border: 1px solid #ccc;
|
|
font-size: 14px;
|
|
color: #333;
|
|
width: 250px;
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
}
|
|
{% endblock %}
|
|
|
|
{% block body %}
|
|
<div id="mynetwork"></div>
|
|
|
|
<!-- Legend -->
|
|
<div class="legend">
|
|
<div><span style="background-color: #ff5733; width: 20px; height: 20px; display: inline-block; border-radius: 50%; margin-right: 5px;"></span> Traceroute</div>
|
|
<div><span style="background-color: #3388ff; width: 20px; height: 20px; display: inline-block; border-radius: 50%; margin-right: 5px;"></span> NeighborInfo</div>
|
|
</div>
|
|
|
|
<!-- Node Information Panel -->
|
|
<div id="node-info">
|
|
<b>Long Name: </b> <span id="node-long-name"></span></br>
|
|
<b>Short Name: </b><span id="node-short-name"></span></br>
|
|
<b>Role: </b><span id="node-role"></span></br>
|
|
<b>Hardware Model: </b><span id="node-hw-model"></span>
|
|
</div>
|
|
|
|
<<script type="text/javascript">
|
|
// Initialize chart
|
|
var chart = echarts.init(document.getElementById('mynetwork'));
|
|
|
|
|
|
var nodes = [
|
|
{% for node in nodes %}
|
|
{
|
|
name: '{{ node.node_id }}',
|
|
value: '{{ node.long_name | escape }}',
|
|
symbol: 'rect',
|
|
symbolSize: [null, 40],
|
|
label: {
|
|
show: true,
|
|
position: 'inside',
|
|
color: '#000',
|
|
padding: [5, 10],
|
|
formatter: function(params) { return params.data.value; },
|
|
backgroundColor: '#f0f0f0',
|
|
borderColor: '#999',
|
|
borderWidth: 1,
|
|
borderRadius: 5
|
|
},
|
|
long_name: '{{ node.long_name | escape }}', // Add long name
|
|
short_name: '{{ node.short_name | escape }}', // Add short name
|
|
role: '{{ node.role | escape }}', // Add role
|
|
hw_model: '{{ node.hw_model | escape }}' // Add hardware model
|
|
}{% if not loop.last %},{% endif %}
|
|
{% endfor %}
|
|
];
|
|
|
|
// Sample edge data (this will be passed from Python backend)
|
|
var edges = [
|
|
{% for edge in edges %}
|
|
{
|
|
source: '{{ edge.from }}',
|
|
target: '{{ edge.to }}',
|
|
originalColor: '{{ edge.originalColor }}', // Store original color
|
|
lineStyle: {
|
|
color: '#d3d3d3', // Set all edges to light gray by default
|
|
width: 2, // Default width for all edges
|
|
opacity: 0.5 // Dim edges by default
|
|
}
|
|
}{% if not loop.last %},{% endif %}
|
|
{% endfor %}
|
|
];
|
|
|
|
var option = {
|
|
backgroundColor: 'white',
|
|
tooltip: {
|
|
formatter: function(params) {
|
|
// Only show long_name on hover
|
|
return params.data.long_name + ' - ' + params.data.short_name;
|
|
|
|
}
|
|
},
|
|
animationDurationUpdate: 1500,
|
|
animationEasingUpdate: 'quinticInOut',
|
|
legend: {
|
|
data: ['Traceroute', 'NeighborInfo'],
|
|
selectedMode: false, // Disable item selection
|
|
left: 'center',
|
|
bottom: '5%',
|
|
orient: 'vertical', // Stack legend vertically
|
|
textStyle: {
|
|
fontSize: 12,
|
|
color: '#333'
|
|
},
|
|
itemWidth: 10,
|
|
itemHeight: 10,
|
|
padding: [5, 15]
|
|
},
|
|
series: [
|
|
{
|
|
type: 'graph',
|
|
layout: 'force',
|
|
data: nodes,
|
|
links: edges,
|
|
roam: true,
|
|
force: {
|
|
repulsion: 500,
|
|
edgeLength: [100, 200],
|
|
gravity: 0.05
|
|
},
|
|
lineStyle: {
|
|
width: 2,
|
|
curveness: 0
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
chart.setOption(option);
|
|
|
|
// Event listener for node clicks
|
|
chart.on('click', function(params) {
|
|
if (params.dataType === 'node') {
|
|
var selectedNode = params.data.name;
|
|
|
|
// Update edges for the selected node: highlight connected edges
|
|
var updatedEdges = edges.map(edge => {
|
|
if (edge.source === selectedNode || edge.target === selectedNode) {
|
|
return {
|
|
...edge,
|
|
lineStyle: {
|
|
color: edge.originalColor, // Use original color for selected edges (blue or red)
|
|
width: 2, // Thinner width for highlighted edges
|
|
opacity: 1 // Full opacity for selected edges
|
|
}
|
|
};
|
|
} else {
|
|
return edge; // Keep the non-selected edges in light gray
|
|
}
|
|
});
|
|
|
|
// Update the chart with highlighted edges
|
|
chart.setOption({
|
|
series: [{ links: updatedEdges }]
|
|
});
|
|
|
|
// Update the node information panel
|
|
document.getElementById('node-long-name').innerText = params.data.long_name;
|
|
document.getElementById('node-short-name').innerText = params.data.short_name;
|
|
document.getElementById('node-role').innerText = params.data.role;
|
|
document.getElementById('node-hw-model').innerText = params.data.hw_model;
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|