Skip to content

Commit

Permalink
[feature] Cluster based on common properties
Browse files Browse the repository at this point in the history
  • Loading branch information
totallynotvaishnav committed Oct 9, 2022
1 parent 0ecb947 commit 6b63446
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 26 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,6 @@ Demo is [here](https://openwisp.github.io/netjsongraph.js/examples/netjson-dateP

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

> > > > > > > 168b103 ([docs] Update docs)

- `isObject`

Check if the param is object.
Expand Down
2 changes: 1 addition & 1 deletion dist/netjsongraph.min.js

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions src/css/netjsongraph-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,6 @@
background-color: rgba(21, 102, 169, 0.8) !important;
}

.marker-cluster-small,
.marker-cluster-medium,
.marker-cluster-large {
background-color: unset !important;
}

@media only screen and (max-width: 850px) {
.njg-sideBar {
background: rgba(255, 255, 255, 0.96);
Expand Down
56 changes: 51 additions & 5 deletions src/js/netjsongraph.render.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,58 @@ class NetJSONGraphRender {
self.leaflet.geoJSON = L.geoJSON(self.data, self.config.geoOptions);

if (self.config.clustering) {
self.leaflet.markerClusterGroup = L.markerClusterGroup({
const clusterOptions = {
showCoverageOnHover: false,
spiderfyOnMaxZoom: false,
maxClusterRadius: self.config.clusterRadius,
disableClusteringAtZoom: self.config.disableClusteringAtLevel - 1,
}).addTo(self.leaflet);
self.leaflet.markerClusterGroup.addLayer(self.leaflet.geoJSON);
};

if (self.config.clusteringAttribute) {
const clusterTypeSet = new Set();
self.data.features.forEach((feature) => {
clusterTypeSet.add(
feature.properties[self.config.clusteringAttribute] || "default",
);
if (!feature.properties[self.config.clusteringAttribute]) {
feature.properties[self.config.clusteringAttribute] = "default";
}
});
const clusterTypes = Array.from(clusterTypeSet);
const clusterGroup = [];
clusterTypes.forEach((type) => {
const features = self.data.features.filter(
(feature) =>
feature.properties[self.config.clusteringAttribute] === type,
);
const layer = L.geoJSON(
{
...self.data,
features,
},
self.config.geoOptions,
);
const cluster = L.markerClusterGroup({
...clusterOptions,
iconCreateFunction: (c) => {
const childCount = c.getChildCount();
return L.divIcon({
html: `<div><span>${childCount}</span></div>`,
className: `marker-cluster ${type}`,
iconSize: L.point(40, 40),
});
},
}).addTo(self.leaflet);
clusterGroup.push(cluster);
cluster.addLayer(layer);
});
self.leaflet.clusterGroup = clusterGroup;
} else {
self.leaflet.markerClusterGroup = L.markerClusterGroup(
clusterOptions,
).addTo(self.leaflet);
self.leaflet.markerClusterGroup.addLayer(self.leaflet.geoJSON);
}
} else {
self.leaflet.geoJSON.addTo(self.leaflet);
}
Expand Down Expand Up @@ -426,7 +471,7 @@ class NetJSONGraphRender {
),
);

self.echarts.on("mouseover", (params) => {
self.echarts.on("click", (params) => {
if (
(params.componentSubType === "scatter" ||
params.componentSubType === "effectScatter") &&
Expand All @@ -446,10 +491,11 @@ class NetJSONGraphRender {
clusters,
),
);
self.leaflet.setView([params.data.value[1], params.data.value[0]]);
}
});

self.leaflet.on("zoomend", () => {
self.leaflet.on("zoomend", (e) => {
if (self.leaflet.getZoom() < self.config.disableClusteringAtLevel) {
const nodeData = self.utils.makeCluster(self);
clusters = nodeData.clusters;
Expand Down
56 changes: 44 additions & 12 deletions src/js/netjsongraph.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ class NetJSONGraphUtil {
node.location.lng,
]).x;
node.visited = false;
node.cluster = null;
});

const index = new KDBush(
Expand All @@ -298,18 +299,38 @@ class NetJSONGraphUtil {

nodes.forEach((node) => {
let cluster;
let centroid = [0, 0];
const addNode = (n) => {
n.visited = true;
n.cluster = clusterId;
nodeMap.set(n.id, n.cluster);
centroid[0] += n.location.lng;
centroid[1] += n.location.lat;
};
if (!node.visited) {
let centroid = [0, 0];
const results = index
const neighbors = index
.within(node.x, node.y, self.config.clusterRadius)
.map((id) => {
nodes[id].visited = true;
nodes[id].cluster = clusterId;
nodeMap.set(nodes[id].id, nodes[id].cluster);
centroid[0] += nodes[id].location.lng;
centroid[1] += nodes[id].location.lat;
return nodes[id];
});
.map((id) => nodes[id]);
const results = neighbors.filter((n) => {
if (self.config.clusteringAttribute) {
if (
n.properties[self.config.clusteringAttribute] ===
node.properties[self.config.clusteringAttribute] &&
n.cluster === null
) {
addNode(n);
return true;
}
return false;
}

if (n.cluster === null) {
addNode(n);
return true;
}
return false;
});

if (results.length > 1) {
centroid = [
centroid[0] / results.length,
Expand All @@ -324,9 +345,20 @@ class NetJSONGraphUtil {
...self.config.mapOptions.clusterConfig,
};

if (self.config.clusteringAttribute) {
const {color} = self.config.nodeCategories.find(
(cat) =>
cat.name === node.properties[self.config.clusteringAttribute],
).nodeStyle;

cluster.itemStyle = {
...cluster.itemStyle,
color,
};
}

clusters.push(cluster);
} else {
results[0].clusterId = null;
} else if (results.length === 1) {
nodeMap.set(results[0].id, null);
nonClusterNodes.push(results[0]);
}
Expand Down

0 comments on commit 6b63446

Please sign in to comment.