Skip to content

Commit

Permalink
[feature] Implement clustering feature #114
Browse files Browse the repository at this point in the history
Closes #114
  • Loading branch information
totallynotvaishnav committed Nov 15, 2022
1 parent 14411ec commit cf33b1f
Show file tree
Hide file tree
Showing 12 changed files with 661 additions and 17 deletions.
47 changes: 44 additions & 3 deletions README.md
Expand Up @@ -115,6 +115,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 @@ -172,6 +200,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 @@ -188,6 +219,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 @@ -567,6 +600,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 @@ -732,6 +769,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)

### Upgrading from 0.1.x versions to 0.2.x

We advise all users of netjsongraph.js who are using the 0.1.x version to
Expand Down Expand Up @@ -773,15 +813,16 @@ passing any additional arguments to these functions is not needed anymore.
The option `linkDistance` has been renamed to `edgeLength`.
Options like `edgeLength`, `friction`, `gravity` are now passed as an object
named `force` in `series` property of `graphConfig`.
Learn more about `graphConfig` by looking at the [Arguments section](#arguments). Refer to the [Echarts documentation](https://echarts.apache.org/en/option.html#series-graph.force) for more details.
Learn more about `graphConfig` by looking at the [Arguments section](#arguments).
Refer to the [Echarts documentation](https://echarts.apache.org/en/option.html#series-graph.force) for more details.

Use `label` instead of `labelDx` and `labelDy` in the `series` property of `graphConfig`.
Refer to the [Arguments section](#arguments) for more details.
Refer to the [Arguments section](#arguments) for more details.
You can learn more about `label` in the
[Echarts documentation](https://echarts.apache.org/en/option.html#series-graph.label).

Use `onClickElement` instead of `onClickNode` and `onClickLink`.
Refer to the [Arguments section](#arguments) section for more details.
Refer to the [Arguments section](#arguments) section for more details.

### Contributing

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
@@ -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
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
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
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
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

0 comments on commit cf33b1f

Please sign in to comment.