Skip to content

Commit ea75cc7

Browse files
authored
[feature] Added Node Clients #153
Closes #153
1 parent 2cceb11 commit ea75cc7

13 files changed

+733
-37
lines changed

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,72 @@ For map, you need to configure `mapOptions`. The [`mapOptions`](https://leafletj
377377

378378
You can also customize some global properties with [`echartsOption`](https://echarts.apache.org/en/option.html) in echarts.
379379

380+
## Circle Markers in Graph Mode
381+
382+
It's possible to render small colored circles around each node to represent the amount of connected WiFi clients. The overlay counts WiFi clients as a single total. This helper draws on the same ZRender layer as the graph, so the markers follow pan/zoom/force layout without extra work and do not call `setOption` during the main render.
383+
384+
### Configuration
385+
386+
- **Example**: See `public/example_templates/netjsongraph-wifi-clients.html` with dataset `public/assets/data/netjsongraph-wifi-clients.json`
387+
388+
#### Example Usage
389+
390+
```javascript
391+
const graph = new NetJSONGraph("../assets/data/netjsongraph-wifi-clients.json", {
392+
render: "graph",
393+
onReady() {
394+
// Attach the client overlay once the graph is ready
395+
this.attachClientsOverlay({
396+
// --- Optional configuration ---
397+
radius: 5, // Radius of each client dot in pixels
398+
gap: 3, // Distance from the node's edge to the first ring of dots
399+
colors: {
400+
wifi: "#d35454",
401+
},
402+
minZoomLevel: 1, // Only show dots when zoom level is at or above this value
403+
});
404+
},
405+
});
406+
graph.render();
407+
```
408+
409+
For a live demo, see the [WiFi Clients Graph example](https://openwisp.github.io/netjsongraph.js/examples/netjsongraph-wifi-clients.html).
410+
411+
#### Data Format
412+
413+
The number of dots rendered around a node is determined by the `clients` field in your NetJSON `nodes` data:
414+
415+
- `clients` (Number or Array)
416+
- If it's an Array, its length is used as the client count (and the sidebar lists Client [i] entries, e.g., MAC addresses).
417+
- If it's a Number, the value is used directly as the count.
418+
419+
**Example Node Data**:
420+
421+
```javascript
422+
{
423+
"nodes": [
424+
{
425+
"id": "A",
426+
"label": "Node A",
427+
// Shows 1 primary client dot. Displays details in the sidebar.
428+
"clients": [{"mac": "d8:5d:4c:f1:aa:62"}]
429+
},
430+
{
431+
"id": "B",
432+
"label": "Node B",
433+
// Shows 2 primary client dots.
434+
"clients": [{"mac": "..."}, {"mac": "..."}]
435+
},
436+
{
437+
"id": "C",
438+
"label": "Node C",
439+
// Shows 1 primary client dot.
440+
"clients": 1
441+
}
442+
]
443+
}
444+
```
445+
380446
### GeoJSON handling
381447

382448
netjsongraph.js will now **always** convert GeoJSON input into an internal
@@ -822,6 +888,9 @@ Similiar to the first method, but easier.
822888
The demo shows the clustering of nodes.
823889
[ Clustering demo](https://openwisp.github.io/netjsongraph.js/examples/netjson-clustering.html)
824890

891+
The demo shows how to display connected WiFi clients around nodes.
892+
[WiFi Clients Graph demo](https://openwisp.github.io/netjsongraph.js/examples/netjsongraph-wifi-clients.html)
893+
825894
### Upgrading from 0.1.x versions to 0.2.x
826895

827896
We advise all users of netjsongraph.js who are using the 0.1.x version to

index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ <h1>NetJSONGraph.js Example Demos</h1>
236236
>Clustering</a
237237
>
238238
</div>
239+
<div class="cards">
240+
<a href="./examples/netjsongraph-wifi-clients.html" target="_blank"
241+
>WiFi Clients Graph</a
242+
>
243+
</div>
239244
</main>
240245

241246
<script>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"label": "WiFi Clients of the Mesh Nodes",
3+
"nodes": [
4+
{
5+
"id": "A",
6+
"label": "Node A",
7+
"clients": [{"mac": "d8:5d:4c:f1:aa:62"}]
8+
},
9+
{
10+
"id": "B",
11+
"label": "Node B",
12+
"clients": [{"mac": "d8:5d:4c:f1:aa:61"}, {"mac": "2a:9a:fb:12:11:77"}]
13+
},
14+
{
15+
"id": "C",
16+
"label": "Node C",
17+
"clients": 3
18+
},
19+
{
20+
"id": "D",
21+
"label": "Node D",
22+
"clients": 0
23+
}
24+
],
25+
"links": [
26+
{"source": "A", "target": "B"},
27+
{"source": "B", "target": "C"},
28+
{"source": "C", "target": "D"}
29+
]
30+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>netjsongraph.js: WiFi Clients Graph</title>
5+
<meta charset="utf-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<link href="../lib/css/netjsongraph-theme.css" rel="stylesheet" />
8+
<link href="../lib/css/netjsongraph.css" rel="stylesheet" />
9+
<style>
10+
body, html { height: 100%; }
11+
body { margin: 0; }
12+
#container { width: 100%; height: 100vh; }
13+
14+
#legend {
15+
position: absolute;
16+
top: auto;
17+
right: 15px;
18+
bottom: 15px;
19+
width: auto;
20+
height: auto;
21+
max-width: 250px;
22+
padding: 0 15px;
23+
background: #fbfbfb;
24+
border-radius: 8px;
25+
border: 1px solid #ccc;
26+
color: #6d6357;
27+
font-family: Arial, sans-serif;
28+
font-size: 14px;
29+
z-index: 2;
30+
}
31+
32+
#legend h4 {
33+
margin: 10px 0;
34+
text-align: center;
35+
}
36+
37+
#legend p {
38+
margin: 10px 0;
39+
display: flex;
40+
align-items: center;
41+
}
42+
43+
#legend span {
44+
width: 16px;
45+
margin-right: 5px;
46+
}
47+
48+
#legend span.circle {
49+
display: inline-block;
50+
border-radius: 50%;
51+
height: 16px;
52+
}
53+
54+
@media only screen and (max-width: 850px) {
55+
#legend {
56+
right: 15px;
57+
}
58+
}
59+
</style>
60+
</head>
61+
<body>
62+
<div id="legend">
63+
<h4>Legend</h4>
64+
<p><span class="circle" style="background-color: #bdc3c7;">&nbsp;</span> Mesh nodes</p>
65+
<p><span class="circle" style="background-color: #d35454;">&nbsp;</span> WiFi clients</p>
66+
<p><span style="display:inline-block; width:16px; height:6px; background-color:#00ff04; margin-right:5px;"></span> Links</p>
67+
</div>
68+
<div id="container"></div>
69+
<script type="text/javascript">
70+
const data = "../assets/data/netjsongraph-wifi-clients.json";
71+
72+
const graph = new NetJSONGraph(data, {
73+
el: "#container",
74+
render: "graph",
75+
metadata: true,
76+
graphConfig: {
77+
series: {
78+
force: {
79+
gravity: 0.1,
80+
edgeLength: [80, 100],
81+
repulsion: 700,
82+
},
83+
emphasis: {
84+
disabled: true,
85+
},
86+
layout: "force",
87+
roam: true,
88+
label: { show: true, color: "#fff" },
89+
nodeStyle: { color: "#fff", opacity: "0.9" },
90+
linkStyle: { color: "#38a91a", width: 7, opacity: "1" },
91+
nodeSize: 30,
92+
},
93+
baseOptions: {
94+
backgroundColor: "#222"
95+
}
96+
},
97+
onReady() {
98+
// Attach reusable overlay plugin shipped with the bundle
99+
this.attachClientsOverlay({
100+
radius: 5,
101+
gap: 3,
102+
minZoomLevel: 1,
103+
});
104+
}
105+
});
106+
107+
graph.render();
108+
</script>
109+
</body>
110+
</html>

0 commit comments

Comments
 (0)