-
-
Notifications
You must be signed in to change notification settings - Fork 98
[feature] Update URL with node click of map interactions #238 #417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
nemesifier
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed in our weekly meeting, the result doesn't seem to match the specs described in #238.
Please read again the specs and ask any question if not clear.
6fa8c24 to
591ed33
Compare
4c6fdfb to
751d759
Compare
Screencast.from.2025-09-12.02-47-39.webm |
0b32122 to
5bfbddc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work @Deepanshu! This is going to be a very user feature in the library. 💪🏼
I found a corner case while going back through the history of the browser using the back button. I expected the map to update when the URL fragment updates, but that is not the case here.
I also explored about enabling this feature by default. If ID is not provided in the config, we can generate a hash based on the HTML element. This can have side-effects, so let's think before going ahead in this direction.
Maybe, auto-generating ID is a bad idea. If the hash will change if the user changed the HTML element. This will render old URLs useless.
diff --git a/src/js/netjsongraph.config.js b/src/js/netjsongraph.config.js
index b4fcc67..444d813 100644
--- a/src/js/netjsongraph.config.js
+++ b/src/js/netjsongraph.config.js
@@ -285,7 +285,7 @@ const NetJSONGraphDefaultConfig = {
],
linkCategories: [],
urlFragments: {
- show: false,
+ show: true,
id: null,
},
diff --git a/src/js/netjsongraph.core.js b/src/js/netjsongraph.core.js
index 1d448d1..1758e0b 100644
--- a/src/js/netjsongraph.core.js
+++ b/src/js/netjsongraph.core.js
@@ -57,6 +57,19 @@ class NetJSONGraph {
console.error("Can't change el again!");
}
+ if (!this.config.urlFragments.id) {
+ // The config does not specify a an ID, we assign one by creating
+ // a hash of the HTML element using FNV-1a algorithm
+ let str = this.el.outerHTML
+ let hash = 0x811c9dc5; // FNV offset basis
+ for (let i = 0; i < str.length; i++) {
+ hash ^= str.charCodeAt(i);
+ hash = (hash * 0x01000193) >>> 0; // FNV prime
+
+ }
+ this.config.urlFragments.id = hash.toString();
+ }
+
return this.config;
}
Maybe, this is a bad idea. What if the user updates the HTML element? Then, the old URLs will no longer work. |
32eb321 to
0883e25
Compare
19c0860 to
a628752
Compare
pandafy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work @dee077! 👏🏼 👏🏼 👏🏼
It works as expected.
We need to add a lot of comments in the code to explain our design decision. Otherwise, we will forget about why we chose to implement the feature this way and then search for the details in issues.
c076184 to
d65b3ac
Compare
9c90edb to
463ed3b
Compare
Updates
|
d730eef to
1c0bbda
Compare
39c68f4 to
6866b9b
Compare
nemesifier
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good @dee077, I have a few comments.
The left side in the nested indoor map overlayed on the geo map doesn't look right:
White background on the white background of the image doesn't work well from the point of view of UX, something like this would work slightly better (feel free to improve if you want):
#netjson-indoormap .njg-sideBar {
background: #f4f4f4;
border-right: 1px solid rgba(0, 0, 0, 0.2);
}
I will do more testing and reviewing tomorrow.
nemesifier
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far it's behaving pretty well, we just need to do some polishing.
Here's something weird which I found:
- I keep clicking on nodes and some times the zoom changes. Is this on purpose?
- Some times the zoom changes also when going back, but most of the time it doesn't, this looks incosistent
- When openinig a URL fragment on a new tab, the map doesn't really zoom in much
See:
What do you think about the following and can it be done?
- When the map is already open and the user is clicking around or going back and forth in the history, we shouldn't interfere with the zoom level has set (if they zoomed up to that level it means they're happy with that)
- When the map opens with a fragment we can zoom in at a specific configurable level (eg:
urlFragmentZoomLevel), which by default can fallback toshowLabelsAtZoomLevel, so we have a reasonable default for this but can be tweaked if needed.
| ``` | ||
|
|
||
| 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: | ||
| 1. id – A prefix used to uniquely identify the map. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this an arbitrary identifier or what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is an arbitrary identifier
| 1. id – A prefix used to uniquely identify the map. | ||
| 2. nodeId – The id of the selected node. | ||
| When a URL containing these fragments is opened, the click event associated with the given nodeId is triggered, and if the map is based on Leaflet, the view will automatically center on that node. | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this whole docs section is not user friendly and needs to be improved.
- Explain what the feature does in general terms
- Be specific, eg: link a few examples and suggest to click on nodes and link while observing the URL bar, then try to go back and forward with the browser history or copy and paste a URL in a new browser tab/window.
- State whether this feature is enabled by default or not (I think it's not right?)
- Show an example of how to enable it, be specific in what
idmeans (it's the ID of the HTML container of the netjsongraph.js target right?)
Please do this yourself: do not ask LLM to generate this for you, but once you have a good draft feel free to ask LLMs to improve grammar to ensure correct use of the English language which is consistent with the rest of the text in this document.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated!
| }, | ||
| bookmarkableActions:{ | ||
| enabled: true, | ||
| id: "indoorMap", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to speecify an ID when we already have an HTML id in el?
My question is not rethoric, I am not sure el MUST be an HTML id, I don't remember right now, can you please check? If el MUST be an HTML id, then we do not need to ask the user to specify the ID, it could be optional, which makes the setup easier. Let's keep in mind we must strive to make our work easy to use which is a common pain points across new openwisp features added in gsoc projects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In openwisp-monitoring we need to open the floorplan overlay before applying the state from url fragments.
So we make the indoor map id as locationId:floor so that we can open the overlay using these values for a specific location and floor, and then the state can be applied.
6866b9b to
0ef49db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work Deepanshu! I just found this minor adjustments to make before we merge.
Can you also rebase it on the current master?
Implemented query param updates on node click, zoom and interaction with map. Visiting a URL with query params of map bounds to auto-focuses the node. Fixes #238
Fixed CRS conflict in indoor map example and added a new parameter 'zoomLevel' in bookmarkableActions. Added support for link interactions, fix tests and update docs. Fixes #397
0ef49db to
ba4f267
Compare
|
Feel free to update the Readme if you want some additional details to mention or want to remove something. |
| - `bookmarkableActions` | ||
|
|
||
| Configuration for adding url fragments when a node is clicked. | ||
|
|
||
| ```javascript | ||
| bookmarkableActions: { | ||
| enabled: boolean, | ||
| id: string, | ||
| zoomLevel: number | ||
| } | ||
| ``` | ||
|
|
||
| **Note: This feature is disabled by default.** | ||
|
|
||
| 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: | ||
| 1. id – A prefix used to uniquely identify the map. | ||
| 2. nodeId – The id of the selected node. | ||
| 3. zoomLevel – The zoom level applied when restoring the state from the URL fragments. | ||
|
|
||
| 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. | ||
|
|
||
| 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: `#map1-node=device-1;#map2-node=device-2` ). | ||
|
|
||
| For nodes, the behavior depends on the type of visualization in Leaflet maps, clicking a node updates the URL and on apllying the state from url it automatically centers the map on that node, in addition to triggering its click event. In ECharts graphs, only triggers the click event for the node. | ||
|
|
||
| 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. | ||
|
|
||
| If you need to manually remove the URL fragment, you can call the built-in utility method: `netjsongraphInstance.utils.removeUrlFragment('id');` where id is `bookmarkableActions.id`. | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about changing the section with following:
-
bookmarkableActionsEnables shareable URLs that capture the current NetJSONGraph state.
When a graph element is clicked, the browser URL updates with a fragment identifying the selected element.
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.The following examples demonstrate how selected nodes can be shared across different types of maps:
bookmarkableActions: { // Enables or disables the feature (default: false) enabled: boolean, // Arbitrary unique identifier for the NetJSONGraph instance. id: string, // Zoom level to apply when restoring from the URL fragment. zoomLevel: number }
The URL fragment format depends on the selected element:
- Node:
#<id>-node=<nodeId> - Link:
#<id>-node=<source>~<target>
Where:
<id>is the value ofbookmarkableActions.id, identifying each NetJSONGraph instance.<nodeId>is the ID of the selected node.<source>and<target>are the IDs of the nodes connected by the selected link.
When multiple visualizations are present, fragments are separated by semicolons:
#map1-node=device-1;#map2-node=device-2Note: When restoring a view from a URL, the corresponding element is automatically clicked. Due to technical limitations, only Geographic maps also zoom in to the selected node during this process.
- Node:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The links currently don't work, but will work once the PR is merged.
I am not in favour of sharing the structure of URL fragments in the README. I just added it here for completeness.

Checklist
Reference to Existing Issue
Closes #238 .
Description of Changes