Skip to content
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

[feature] Implement clustering feature #114 #162

Merged
merged 10 commits into from
Oct 18, 2022
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,34 @@ NetJSON format used internally is based on [networkgraph](http://netjson.org/rfc

The zoom level at which more nodes are loaded from the server when the total number of nodes are greater than `maxPointsFetched`. These nodes are loaded based on the geographic extent of the map.

- `clustering`

**Default**: `false`

Whether to enable clustering of nodes or not. You can also set it `true` to enable it.

- `clusteringThreshold`

**Default**: `100`

The threshold of clustering. When the number of nodes is greater than this value, the clustering will be enabled.

- `disableClusteringAtLevel`

**Default**: `8`

The zoom level at which clustering is disabled. When the zoom level is greater than this value, all the clusters will be expanded.

- `clusterRadius`

**Default**: `80`

The maximum radius that a cluster will cover. Decreasing will make more, smaller clusters and vice versa.

- `clusteringAttribute`

The property used to cluster the nodes. The nodes with the same properties will be clustered together.

- `dealDataByWorker`

The url to the worker file if you want to deal the data by a worker.
Expand Down Expand Up @@ -174,6 +202,9 @@ NetJSON format used internally is based on [networkgraph](http://netjson.org/rfc
// The style of the links
},
},
clusterConfig:{
// The configuration for the clusters
},
baseOptions:{
// The global configuration for Echarts specifically for the map.
}
Expand All @@ -190,6 +221,8 @@ NetJSON format used internally is based on [networkgraph](http://netjson.org/rfc

The `nodeSize` property is used to customize the size of the nodes.

The `clusterConfig` property is used to customize the clusters. You can pass any valid [Echarts options](https://echarts.apache.org/en/option.html#series-scatter.data) in `clusterConfig`. If you are using GeoJSON data, you can customize the cluster styles by using the CSS class`marker-cluster`. You can also use property values when clustering based on data properties as class names.

`linkConfig` deals with the configuration of the links. You can pass any valid [Echarts options](https://echarts.apache.org/en/option.html#series-lines) in `linkConfig`.

The `linkStyle` property is used to customize the style of the links. The list of all available style properties can be found in the [Echarts documentation](https://echarts.apache.org/en/option.html#series-lines.lineStyle).
Expand Down Expand Up @@ -569,6 +602,10 @@ yarn start
});
```

- `makeCluster`

Accepts NetJSONGraph instance as parameter and returns an object containing the cluster nodes, other individual nodes and links.

- `isObject`

Check if the param is object.
Expand Down Expand Up @@ -734,6 +771,9 @@ Using array files to append data step by step at start.
Similiar to the first method, but easier.
[ Append data using arrays demo](https://openwisp.github.io/netjsongraph.js/examples/netjsonmap-appendData2.html)

The demo shows the clustering of nodes.
[ Clustering demo](https://openwisp.github.io/netjsongraph.js/examples/netjson-clustering.html)

### Contributing

1. Fork it!
Expand Down
8 changes: 4 additions & 4 deletions dist/netjsongraph.min.js

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions examples/netjson-clustering.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>netjsongraph.js: basic example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""
/>
<!-- theme can be easily customized via css -->
<link href="../src/css/netjsongraph-theme.css" rel="stylesheet" />
<link href="../src/css/netjsongraph.css" rel="stylesheet" />
<style type="text/css">
#legend h4 {
margin: 10px 0;
text-align: center;
}
#legend {
position: absolute;
right: 25px;
bottom: 25px;
width: auto;
height: auto;
max-width: 250px;
padding: 8px 15px;
background: #fbfbfb;
border-radius: 8px;
color: #000;
font-family: Arial, sans-serif;
font-family: sans-serif;
font-size: 14px;
z-index: 1000;
user-select: text;
}
#legend p {
margin: 10px 0;
display: flex;
align-items: center;
}
#legend span {
width: 16px;
margin-right: 5px;
}
#legend .link-up,
#legend .link-down {
display: inline-block;
height: 5px;
border-bottom-width: 6px;
border-bottom-style: solid;
}
#legend .link-up {
color: #3acc38;
margin-right: 10px;
}
#legend .link-down {
color: red;
margin-right: 10px;
}

@media only screen and (max-width: 850px) {
#legend {
right: 15px;
}
}
</style>
</head>
<body>
<script type="text/javascript" src="../dist/netjsongraph.min.js"></script>
<script type="text/javascript">
const map = new NetJSONGraph("./data/netjsonmap.json", {
render: "map",
clustering: true,
clusteringThreshold: 50,
// set map initial state.
mapOptions: {
center: [46.86764405052012, 19.675998687744144],
zoom: 4,
nodeConfig: {
label: {
offset: [0, -10],
},
},
},
linkCategories: [
{
name: "down",
linkStyle: {
color: "#c92517",
width: 5,
},
emphasis: {
linkStyle: {
color: "#FD0101",
opacity: 1,
},
},
},
],
// Convert to internal json format
prepareData: (data) => {
data.nodes.map((node) => {
node.label = node.name;
node.properties = Object.assign(node.properties || {}, {
location: node.location,
});
});

data.links.map((link) => {
link.properties = link.properties || {};
if (link.properties.status) {
link.category = link.properties.status;
}
});
},
});

const createLegend = (key, name) => {
const legendItem = document.createElement("p");
const legendIcon = document.createElement("span");

legendIcon.setAttribute("class", name);

legends.appendChild(legendItem);
legendItem.appendChild(legendIcon);

legendItem.innerHTML += key;
return legendItem;
};
const legends = document.createElement("div");
const legendsHeader = document.createElement("h4");
legends.setAttribute("id", "legend");
legendsHeader.innerHTML = "Legend";
legends.appendChild(legendsHeader);
legends.appendChild(createLegend("Up", "link-up"));
legends.appendChild(createLegend("Down", "link-down"));

document.body.appendChild(legends);

map.render();
</script>
</body>
</html>
5 changes: 5 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ <h1>NetJSONGraph.js Example Demos</h1>
>Geographic map with GeoJSON data</a
>
</div>
<div class="cards">
<a href="./examples/netjson-clustering.html" target="_blank"
>Clustering</a
>
</div>
</main>
</body>
</html>
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@types/jest": "^28.1.6",
"acorn": "^8.7.1",
"coveralls": "^3.1.1",
"css-loader": "^6.7.1",
"eslint": "^8.18.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
Expand All @@ -54,6 +55,7 @@
"jest-environment-jsdom": "^28.1.1",
"lint-staged": "^13.0.2",
"prettier": "^2.7.1",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.3",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0",
Expand All @@ -62,7 +64,9 @@
"dependencies": {
"echarts": "^5.3.3",
"echarts-gl": "^2.0.8",
"kdbush": "^3.0.0",
"leaflet": "^1.8.0",
"leaflet.markercluster": "^1.5.3",
"zrender": "^5.3.2"
}
}
5 changes: 5 additions & 0 deletions src/css/netjsongraph-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
color: #000;
}

.marker-cluster div {
color: #fff;
background-color: rgba(21, 102, 169, 0.8) !important;
}

@media only screen and (max-width: 850px) {
.njg-sideBar {
background: rgba(255, 255, 255, 0.96);
Expand Down
19 changes: 19 additions & 0 deletions src/js/netjsongraph.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const NetJSONGraphDefaultConfig = {
switchMode: false,
maxPointsFetched: 10000,
loadMoreAtZoomLevel: 9,
clustering: false,
clusteringThreshold: 100,
disableClusteringAtLevel: 8,
clusterRadius: 80,
showMetaOnNarrowScreens: false,
showLabelsAtZoomLevel: 7,
echartsOption: {
Expand Down Expand Up @@ -183,6 +187,21 @@ const NetJSONGraphDefaultConfig = {
},
},
},
clusterConfig: {
symbolSize: 30,
itemStyle: {
color: "#1566a9",
},
tooltip: {
show: false,
},
label: {
show: true,
position: "inside",
color: "#fff",
offset: [0, 0],
},
},
baseOptions: {
toolbox: {
show: false,
Expand Down
Loading