Skip to content

Commit 9b1f760

Browse files
authored
Merge branch 'master' into issues/454-fix-redundant-labels
2 parents 3da29d0 + e065cce commit 9b1f760

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1767
-507
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
run: echo "::set-output name=dir::$(yarn cache dir)"
2424

2525
- name: Cache yarn
26-
uses: actions/cache@v4
26+
uses: actions/cache@v5
2727
id: yarn-cache
2828
with:
2929
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@@ -55,7 +55,7 @@ jobs:
5555
run: echo "::set-output name=dir::$(yarn cache dir)"
5656

5757
- name: Cache yarn
58-
uses: actions/cache@v4
58+
uses: actions/cache@v5
5959
id: yarn-cache
6060
with:
6161
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

AGENTS.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# AGENTS.md
2+
3+
## Project Overview
4+
5+
NetJSON NetworkGraph visualizer: A JavaScript library for visualizing network data using NetJSON format, built with echarts, leaflet, and related dependencies.
6+
7+
## Development Setup
8+
9+
- Install dependencies: `yarn install`.
10+
- Set up Python environment for QA tools: `pip install "openwisp-utils[qa]~=1.2.0"` (required for openwisp-qa-format and openwisp-qa-check).
11+
- For browser tests, ensure Chrome and ChromeDriver are available (CI handles this automatically).
12+
13+
## Code Formatting
14+
15+
To format code, run:
16+
17+
```bash
18+
openwisp-qa-format # python virtualenv needs to be enabled for this command to work, if not, install openwisp-utils as done in .github/workflows/ci.yml
19+
yarn lint:fix # runs eslint --fix and prettier via lint-staged
20+
```
21+
22+
## QA Checks
23+
24+
Run QA checks with:
25+
26+
```bash
27+
./run-qa-checks
28+
```
29+
30+
This runs yarn lint, openwisp-qa-check (with CSS/JS linting, skipping Python checks), and fails if issues are found.
31+
32+
## Testing
33+
34+
- Unit tests (Jest with jsdom): `yarn test`.
35+
- Browser tests (requires dev server): Start server with `yarn start &`, then run `yarn test test/netjsongraph.browser.test.js` (uses Chrome/ChromeDriver).
36+
- Coverage: `yarn coverage` (excludes browser test file).
37+
- CI runs unit tests with coverage, then browser tests separately (see `.github/workflows/ci.yml`, ignore "build-and-deploy" job).
38+
39+
## Building and Running
40+
41+
- Development server: `yarn dev` (opens browser at localhost:8080).
42+
- Production build: `yarn build`.
43+
- Pre-commit hooks: husky runs lint-staged (prettier on `src/\*_/_.js`).
44+
45+
## General Guidelines
46+
47+
- Avoid other arbitrary formatting changes.
48+
- Check for dependency vulnerabilities: `npm audit` or `yarn audit`.
49+
50+
## Code Review Checklist
51+
52+
When reviewing changes, always watch out for:
53+
54+
- Missing tests (especially browser tests for UI‑intensive features).
55+
- Performance penalties.
56+
- Inconsistencies and duplication which can lead to maintenance overhead.
57+
- Security issues (e.g., no secrets in code, safe dep usage).
58+
- Usability issues.
59+
60+
## Contributing Guidelines
61+
62+
- [Follow OpenWISP contributing guidelines](https://openwisp.io/docs/stable/developer/contributing.html).
63+
64+
## Troubleshooting
65+
66+
- QA/format commands fail: Ensure Python env is active and openwisp-utils is installed.
67+
- Browser tests fail: Check Chrome/ChromeDriver setup; server must be running on `localhost:8080`.
68+
- Deps not found: Run `yarn install` first.
69+
- CI issues: Refer to .github/workflows/ci.yml (ignore install steps if deps are cached locally).

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ Plot nodes by geographic coordinates on a Leaflet basemap; pan/zoom with markers
3232
Use a 2D floorplan (Leaflet CRS.Simple) to place and connect indoor nodes.
3333
This example demonstrates the visualization of a mesh network topology graph on a 2D floorplan image.
3434

35+
### Indoor map as overlay of Geographic Map
36+
37+
[![Indoor map as overlay of Geographic Map](docs/gifs/netjsonmap-indoormap-overlay.gif)](https://openwisp.github.io/netjsongraph.js/examples/netjsonmap-indoormap-overlay.html)
38+
39+
Overlay an indoor map on top of a geographic map. Click on a node to open the indoor map as a modal overlay.
40+
3541
### Network Graph with custom attributes and legend
3642

3743
[![Custom attributes](docs/gifs/netjsongraph-elementsLegend.gif)](https://openwisp.github.io/netjsongraph.js/examples/netjsongraph-elementsLegend.html)
@@ -465,6 +471,39 @@ NetJSON format used internally is based on [networkgraph](http://netjson.org/rfc
465471

466472
You can customize the style of GeoJSON features using `style` property. The list of all available properties can be found in the [Leaflet documentation](https://leafletjs.com/reference.html#geojson).
467473

474+
- `bookmarkableActions`
475+
476+
Configuration for adding url fragments when a node/link is clicked.
477+
478+
```javascript
479+
bookmarkableActions: {
480+
enabled: boolean,
481+
id: string,
482+
zoomOnRestore: boolean,
483+
zoomLevel: number,
484+
}
485+
```
486+
487+
**Note: This feature is disabled by default.**
488+
489+
You can see this feature in action in the following example: [Indoor Map as Overlay of Geographic Map](https://openwisp.github.io/netjsongraph.js/examples/netjsonmap-indoormap-overlay.html).
490+
491+
You can enable or disable adding url fragments by setting enabled to true or false. When enabled, the following parameters are added to the URL:
492+
1. id – A prefix used to uniquely identify the map.
493+
2. nodeId – The ID of the selected node, or sourceNodeId~targetNodeId in case of a link.
494+
495+
The `zoomOnRestore` option determines whether the map should automatically adjust its zoom level when the state is applied, and `zoomLevel` specifies the zoom level to use when this behavior is enabled. These options are relevant for Leaflet-based maps and allow finer control over how the map view is restored from a bookmarked URL.
496+
497+
This feature allows you to create shareable and restorable map or graph states using URL fragments. When this feature is enabled, the URL updates automatically whenever you click a node or a link in your NetJSONGraph visualization. This makes it easy to share a specific view, restore it later, or navigate between different states using the browser’s back and forward buttons.
498+
499+
This feature works across all ECharts graphs, as well as Leaflet-based maps including geographic and indoor floorplan maps and it supports multiple maps or graphs on the same page. The id parameter is used to uniquely identify which visualization the URL fragment belongs to (for example: `#id=map1&nodeId=device-1;id=map2&nodeId=device-2`).
500+
501+
For nodes, the behavior depends on the type of visualization. In Leaflet maps, clicking a node updates the URL, and when applying the state from the URL, it automatically centers the map on that node in addition to triggering its click event. In ECharts graphs, it only triggers the click event for the node.
502+
503+
For links, the URL fragment uses the format `source~target` as the `nodeId`. Opening such a URL restores the initial map or graph view and triggers the corresponding link click event.
504+
505+
If you need to manually remove the URL fragment, you can call the built-in utility method: `netjsongraphInstance.utils.removeUrlFragment(bookmarkableActions.id);` where you pass the value of your `bookmarkableActions.id` configuration.
506+
468507
- `onInit`
469508

470509
The callback function executed on initialization of `NetJSONGraph` instance.
2.27 MB
Loading

index.html

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html lang="en">
33
<head>
4-
<title>netjsongraph.js: Examples</title>
4+
<title>Netjsongraph.js: Examples</title>
55
<meta charset="utf-8" />
66
<link rel="preconnect" href="https://fonts.googleapis.com" />
77
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -141,64 +141,74 @@ <h1>NetJSONGraph.js Example Demos</h1>
141141

142142
<main>
143143
<div class="cards">
144-
<a href="./examples/netjsongraph.html" target="_blank">Basic usage</a>
144+
<a href="./examples/netjsongraph.html" target="_blank">Standard graph</a>
145+
</div>
146+
<div class="cards">
147+
<a href="./examples/netjsongraph-elementsLegend.html" target="_blank"
148+
>Graph with custom attributes &amp; legend</a
149+
>
150+
</div>
151+
<div class="cards">
152+
<a href="./examples/netjsongraph-wifi-clients.html" target="_blank"
153+
>WiFi clients graph</a
154+
>
145155
</div>
146156
<div class="cards">
147157
<a href="./examples/netjsonmap.html" target="_blank">Geographic map</a>
148158
</div>
149159
<div class="cards">
150-
<a href="./examples/netjson-multipleInterfaces.html" target="_blank"
151-
>Multiple interfaces</a
160+
<a href="./examples/netjson-clustering.html" target="_blank"
161+
>Geo map with clusters</a
152162
>
153163
</div>
154164
<div class="cards">
155-
<a href="./examples/netjson-searchElements.html" target="_blank"
156-
>Search elements</a
165+
<a href="./examples/njg-geojson.html" target="_blank"
166+
>Geo map GeoJSON</a
157167
>
158168
</div>
159169
<div class="cards">
160-
<a href="./examples/netjson-dateParse.html" target="_blank"
161-
>Date parse</a
170+
<a href="./examples/netjsonmap-multipleTiles.html" target="_blank"
171+
>Geo map with tile switch</a
162172
>
163173
</div>
164174
<div class="cards">
165175
<a href="./examples/netjson-switchRenderMode.html" target="_blank"
166-
>Switch render mode</a
176+
>Switch render mode (Canvas/SVG)</a
167177
>
168178
</div>
169179
<div class="cards">
170180
<a href="./examples/netjson-switchGraphMode.html" target="_blank"
171-
>Switch graph mode</a
181+
>Switch graph mode (Geographic/Graph)</a
172182
>
173183
</div>
174184
<div class="cards">
175-
<a href="./examples/netjsongraph-nodeExpand.html" target="_blank"
176-
>Nodes expand or fold</a
185+
<a href="./examples/netjsonmap-indoormap.html" target="_blank"
186+
>Indoor map (simple)</a
177187
>
178188
</div>
179189
<div class="cards">
180-
<a href="./examples/netjsonmap-indoormap.html" target="_blank"
181-
>Indoor map</a
190+
<a href="./examples/netjsonmap-indoormap-overlay.html" target="_blank"
191+
>Geo map and drill down to indoor maps</a
182192
>
183193
</div>
184194
<div class="cards">
185195
<a href="./examples/netjsonmap-plugins.html" target="_blank"
186-
>Leaflet plugins</a
196+
>Geo map &amp; leaflet plugins</a
187197
>
188198
</div>
189199
<div class="cards">
190-
<a href="./examples/netjsongraph-graphGL.html" target="_blank"
191-
>GraphGL render for big data</a
200+
<a href="./examples/netjson-multipleInterfaces.html" target="_blank"
201+
>Multiple interfaces</a
192202
>
193203
</div>
194204
<div class="cards">
195-
<a href="./examples/netjsongraph-elementsLegend.html" target="_blank"
196-
>Custom attributes</a
205+
<a href="./examples/netjson-searchElements.html" target="_blank"
206+
>Search elements</a
197207
>
198208
</div>
199209
<div class="cards">
200-
<a href="./examples/netjsongraph-multipleLinks.html" target="_blank"
201-
>Multiple links render</a
210+
<a href="./examples/netjson-dateParse.html" target="_blank"
211+
>Date parse</a
202212
>
203213
</div>
204214
<div class="cards">
@@ -212,33 +222,28 @@ <h1>NetJSONGraph.js Example Demos</h1>
212222
>
213223
</div>
214224
<div class="cards">
215-
<a href="./examples/netjsonmap-multipleTiles.html" target="_blank"
216-
>Multiple tiles render</a
217-
>
218-
</div>
219-
<div class="cards">
220-
<a href="./examples/netjsonmap-animation.html" target="_blank"
221-
>Geographic map animated links</a
225+
<a href="./examples/netjsonmap-appendData2.html" target="_blank"
226+
>Append data using arrays</a
222227
>
223228
</div>
224229
<div class="cards">
225-
<a href="./examples/netjsonmap-appendData2.html" target="_blank"
226-
>Append data using arrays</a
230+
<a href="./examples/netjsongraph-multipleLinks.html" target="_blank"
231+
>Multiple links render</a
227232
>
228233
</div>
229234
<div class="cards">
230-
<a href="./examples/njg-geojson.html" target="_blank"
231-
>Geographic map with GeoJSON data</a
235+
<a href="./examples/netjsongraph-graphGL.html" target="_blank"
236+
>GraphGL render for big data</a
232237
>
233238
</div>
234239
<div class="cards">
235-
<a href="./examples/netjson-clustering.html" target="_blank"
236-
>Clustering</a
240+
<a href="./examples/netjsonmap-animation.html" target="_blank"
241+
>Geographic map animated links</a
237242
>
238243
</div>
239244
<div class="cards">
240-
<a href="./examples/netjsongraph-wifi-clients.html" target="_blank"
241-
>WiFi Clients Graph</a
245+
<a href="./examples/netjsongraph-nodeExpand.html" target="_blank"
246+
>Nodes expand or fold</a
242247
>
243248
</div>
244249
</main>
@@ -257,7 +262,7 @@ <h1>NetJSONGraph.js Example Demos</h1>
257262

258263
themeToggle.addEventListener('click', () => {
259264
htmlElement.classList.toggle('dark-mode');
260-
265+
261266
// Save theme preference
262267
const currentTheme = htmlElement.classList.contains('dark-mode') ? 'dark' : 'light';
263268
localStorage.setItem('theme', currentTheme);

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
"src/**/*.js": [
1919
"prettier --write",
2020
"git add"
21+
],
22+
"public/example_templates/**/*.html": [
23+
"prettier --write",
24+
"git add"
2125
]
2226
},
2327
"jest": {

public/example_templates/netjson-clustering.html

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -70,32 +70,33 @@
7070
</head>
7171
<body>
7272
<script type="text/javascript">
73-
const map = new NetJSONGraph(
74-
"../assets/data/netjson-clustering.json",
75-
{
76-
render: "map",
77-
clustering: true,
78-
clusteringThreshold: 2,
79-
clusterRadius: 80,
80-
disableClusteringAtLevel: 18,
81-
clusteringAttribute: "status",
82-
clusterSeparation: 20,
83-
mapOptions: {
84-
center: [55.98, 11.54],
85-
zoom: 4,
86-
minZoom: 3,
87-
maxZoom: 18,
88-
// No label configuration to keep the view clean
89-
},
90-
// defaults categories and colors
91-
// shown here to make customization easier
92-
// nodeCategories: [
93-
// {name: "ok", nodeStyle: {color: "#1ba619"}},
94-
// {name: "problem", nodeStyle: {color: "#ffa500"}},
95-
// {name: "critical", nodeStyle: {color: "#c92517"}},
96-
// ]
97-
}
98-
);
73+
const map = new NetJSONGraph("../assets/data/netjson-clustering.json", {
74+
render: "map",
75+
clustering: true,
76+
clusteringThreshold: 2,
77+
clusterRadius: 80,
78+
disableClusteringAtLevel: 18,
79+
clusteringAttribute: "status",
80+
clusterSeparation: 20,
81+
bookmarkableActions: {
82+
enabled: true,
83+
id: "clustering",
84+
},
85+
mapOptions: {
86+
center: [55.98, 11.54],
87+
zoom: 4,
88+
minZoom: 3,
89+
maxZoom: 18,
90+
// No label configuration to keep the view clean
91+
},
92+
// defaults categories and colors
93+
// shown here to make customization easier
94+
// nodeCategories: [
95+
// {name: "ok", nodeStyle: {color: "#1ba619"}},
96+
// {name: "problem", nodeStyle: {color: "#ffa500"}},
97+
// {name: "critical", nodeStyle: {color: "#c92517"}},
98+
// ]
99+
});
99100

100101
// Build legend UI
101102
const createLegend = (key, className) => {

public/example_templates/netjson-dateParse.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
44
<title>netjsongraph.js: basic example</title>

public/example_templates/netjson-multipleInterfaces.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
44
<title>netjsongraph.js: basic example</title>

public/example_templates/netjson-searchElements.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
44
<title>netjsongraph.js: basic example</title>
@@ -29,11 +29,6 @@
2929
right: 0;
3030
}
3131

32-
.njg-searchBtn {
33-
border: none;
34-
border-radius: 5px;
35-
}
36-
3732
@media only screen and (max-width: 500px) {
3833
.njg-searchInput {
3934
width: 40%;

0 commit comments

Comments
 (0)