![PyPI Now Supports iOS and Android Wheels for Mobile Python Development](https://cdn.sanity.io/images/cgdhsj6q/production/96416c872705517a6a65ad9646ce3e7caef623a0-1024x1024.webp?w=400&fit=max&auto=format)
Security News
PyPI Now Supports iOS and Android Wheels for Mobile Python Development
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
supercluster-googlemaps-adapter
Advanced tools
The Supercluster adapter for Google Maps JavaScript API v3 brings functionality of the supercluster a very fast geospatial point clustering library to Google Maps.
The library accepts a standard GeoJSON FeatureCollection. The feature collection might contain any geometry features. All features with a Point geometry will be clusterized with a supercluster while all non-Point features will be added to the Google Maps Data Layer. The library provides several callbacks that allow customize point or cluster markers as well as data layer features appearence and behavior.
The Supercluster adapter library can be served from the firebase host. Add the following script tag in your html file.
<script src="https://maps-tools-242a6.firebaseapp.com/clusterer/supercluster/index.js">
</script>
It can also be installed from npm
npm install supercluster-googlemaps-adapter --save
Add library to your javascript or typescript file as
import SuperClusterAdapter from 'supercluster-googlemaps-adapter';
Please note that this library depends on the Google Maps JavaScript API, so it should be initialized once the Google Maps JavaScript API is fully loaded.
Typically Google Maps JavaScript API is loaded in asynchronous way as specified in the official documentation
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=[YOUR_API_KEY]]&callback=initMap">
</script>
That means we must include clusterer initialization code inside initMap() callback function after map object initialization.
E.g.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: {lat: 41.3850639, lng: 2.1734035}
});
google.maps.event.addListenerOnce(map, 'tilesloaded', () => {
SuperClusterAdapter.getClusterer().then(Clusterer => {
if (Clusterer) {
const clusterer = new Clusterer.Builder(map)
.withRadius(80)
.withMaxZoom(19)
.withMinZoom(0)
.build();
fetch(URL_TO_GET_GEOJSON_DATA).then(response => {
return response.json();
}).then(data => {
clusterer.load(data);
}).catch(err => {
console.log("Cannot fetch GeoJSON data for this example");
});
}
});
});
}
In this example the clusterer iniatialization was carried out as a response to tilesloaded
event of map instance. This event is triggered when all tiles of Google Maps are loaded and map is ready to be used.
Note that clusterer is loaded asynchronously, so the logic should be implemented once MarkerClusterer.getClusterer() promise is resolved.
In order to set up a clusterer you should call SuperClusterAdapter.getClusterer()
method that returns a promise. Once resolved the promise you will have a Clusterer class that should be used to create an instance of clusterer object.
Code snippet is the following
SuperClusterAdapter.getClusterer().then(Clusterer => {
if (Clusterer) {
// TODO: create instance of clusterer
}
});
In order to create instance of clusterer you must call Builder, the Builder accepts an instance of google.maps.Map as a constructor parameter and allows call several chained functions to establish parameters of clusterer.
const clusterer = new Clusterer.Builder(map)
.withRadius(80)
.withMaxZoom(19)
.withMinZoom(0)
.build();
The Builder class supports a set of public methods that allow customize the clusterer.
Defines cluster radius, in pixels. Default value is 80.
Maximum zoom level at which clusters are generated. Default: 19.
Minimum zoom level at which clusters are generated. Default: 0.
Defines styles for clusters such as images, fonts or text colors.
This interface is used to style the cluster's icons. There is default implementation of styles, but you can override it applying array of styles in Builder object
interface IStyle {
url: string; // Url of icon to use
height: number; // Height of icon
width: number; // Width of icon
textColor?: string; // Text color of cluster label
fontFamily?: string; // Font family of cluster label
textSize?: number; // Text size of cluster label
fontWeight?: string; // Font weight of cluster label
anchor?: number[] | null; // Anchor of cluster icon
}
Specifies the URL path where the cluster images are located.
Specifies extension of cluster images
Specifies if map should zoom in after clicking the cluster icon. Default: true.
You can specify a callback function that will be used to set a custom icon on individual markers that are not clusterized. This function receives a GeoJSON Feature with a Point geometry, it should return the URL that represents a marker icon.
E.g.
function customMarkerIcon(feature) {
if (feature.properties.iconUrl) {
return feature.properties.iconUrl;
} else {
return "http://maps.google.com/mapfiles/kml/paddle/pink-blank.png";
}
}
const clusterer = new Clusterer.Builder(map)
.withCustomMarkerIcon(customMarkerIcon)
.build();
You can define a callback function to respond the click events on individual markers that are not clustered. This function receives two parameters. The first is the Google Maps Marker and the second is Google Maps MouseEvent. It might be useful to show Info Window of individual markers
E.g.
function onMarkerClick(marker, event) {
infoWindow.close();
var title = marker.getTitle();
var content = `<h2>${title}</h2>`;
infoWindow.setContent(content);
infoWindow.open(map, marker);
}
const clusterer = new Clusterer.Builder(map)
.withMarkerClick(onMarkerClick)
.build();
You can define callback function to handle clicks on non-point features of your FeatureCollection. This function receives one parameter of type Data.MouseEvent.
E.g.
function onFeatureClick(event) {
infoWindow.close();
if (event.feature) {
var title = event.feature.getProperty("name");
var content = `<h2>${title}</h2>`;
infoWindow.setOptions({
content: content,
position: event.latLng,
map: map
});
infoWindow.open(map);
}
}
const clusterer = new Clusterer.Builder(map)
.withFeatureClick(onFeatureClick)
.build();
You can define a Styling Function for non-point features handled by Google Maps Data Layer.
E.g.
function featureStyle(feature) {
var options = {
fillColor: feature.getProperty("color"),
fillOpacity: 0.5,
strokeColor: feature.getProperty("color"),
strokeOpacity: 1,
strokeWeight: 2
};
return options;
}
const clusterer = new Clusterer.Builder(map)
.withFeatureStyle(featureStyle)
.build();
In some situations you may have a server-side clustering and retrieve clustered data from your endpoint. In order to show this data using the supercluster library you should apply a callbackfunction that transforms items from your server response to supercluster feature.
E.g.
function itemToSuperclusterFeature(item) {
var res = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [item.point.longitude, item.point.latitude]
},
properties: {
}
};
if (item.positionsInside > 1) { // Cluster
res.properties.cluster = true;
res.properties.cluster_id = getNewId();
res.properties.point_count = item.positionsInside;
res.properties.point_count_abbreviated = abbreviateNumber(item.positionsInside);
} else { // Point
res.properties.id = item.assetMapPosition.id;
res.properties.name = item.assetMapPosition.assetName;
}
return res;
}
const clusterer = new Clusterer.Builder(map)
.withServerSideFeatureToSuperCluster(itemToSuperclusterFeature)
.build();
Please note that for clusters you have to define mandatory properties cluster, cluster_id, point_count, point_count_abbreviated
. The feature that you return is a GeoJSON Feature with Point geometry.
The Supercluster adapter can be used in conjunction with the Overlapping Marker Spiderfier.
In order to use the Overlapping Marker Spiderfier include the following script in your html page
<script src="https://cdnjs.cloudflare.com/ajax/libs/OverlappingMarkerSpiderfier/1.0.3/oms.min.js"></script>
Initialize the instance of spiderfier once you have initialized a map instance. E.g.
var oms = new OverlappingMarkerSpiderfier(map, {
markersWontMove: true,
markersWontHide: true,
basicFormatEvents: true,
ignoreMapClick: true,
keepSpiderfied: true
});
Pass instance of spidefier to the supercluster adapter builder:
const clusterer = new Clusterer.Builder(map)
.withOverlapMarkerSpiderfier(oms)
.build();
Enjoy.
In order to load features to cluster you should use method
load(geoJson: GeoJSON.FeatureCollection)
E.g.
fetch(URL_TO_GET_GEOJSON_DATA).then(response => {
return response.json();
}).then(data => {
clusterer.load(data);
}).catch(err => {
console.log("Cannot fetch GeoJSON data for this example");
});
In order to display clusters calculated by your endpoint on server-side you should call method
drawServerSideCalculatedClusters(features: any[])
E.g.
fetch(URL_TO_GET_SERVERSIDE_DATA).then(response => {
return response.text();
}).then(data => {
var jsonData = JSON.parse(data);
clusterer.drawServerSideCalculatedClusters(jsonData.mapPositions);
}).catch(err => {
console.log("Cannot fetch data for this example");
});
Allows set visibility of clusterer
Destroys clusterer
Returns bounds for all features loaded to supercluster
The live demo is available at https://maps-tools-242a6.firebaseapp.com/clusterer/demos/supercluster.html
The demo that demonstrates usage of server side clustering and draw clusters can be found at https://maps-tools-242a6.firebaseapp.com/clusterer/demos/superclusterwithserverside.html
Stackblitz samples:
The source code of this library is licensed under the MIT License.
FAQs
Supercluster Adapter for Google Maps JavaScript API v3
The npm package supercluster-googlemaps-adapter receives a total of 8 weekly downloads. As such, supercluster-googlemaps-adapter popularity was classified as not popular.
We found that supercluster-googlemaps-adapter demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.