Skip to content

teritorio/maplibre-gl-teritorio-cluster

Repository files navigation

MapLibre GL Teritorio Cluster

Enhance MapLibre GL JS with fully interactive HTML-based clusters and markers.

Features:

  • đź§± Renders MapLibre GL JS clusters as HTML elements.
  • 📌 Displays a pinned marker when a feature is clicked.
  • đźš« Unfolded small clusters to avoid requiring zoom or manual ungrouping.

3 Cluster States:

  • Cluster Marker: A single marker representing a cluster, eg. displaying the number of features.
  • Unfolded Cluster: Displays individual features grouped from a small cluster or when at the highest zoom level.
  • Unclustered Features

Customization Callbacks:

  • Custom function to render cluster.
  • Custom function to render individual markers.
  • Custom function to render unfolded cluster.

Demo

👉 Live Demo

Demo screenshot

Installation

Install @teritorio/maplibre-gl-teritorio-cluster with yarn

yarn add @teritorio/maplibre-gl-teritorio-cluster

Or use it from CDN

<script type="module" src="https://unpkg.com/@teritorio/maplibre-gl-teritorio-cluster/dist/maplibre-gl-teritorio-cluster.js"></script>

Usage/Examples

Warning

Set your GeoJSON source with clusterMaxZoom: 22 in order to let the plugin handle individual marker rendering at the highest zoom level.

import { buildCss, TeritorioCluster } from '@teritorio/maplibre-gl-teritorio-cluster'
import maplibregl from 'maplibre-gl'
import 'maplibre-gl/dist/maplibre-gl.css'

const map = new maplibregl.Map({
  container: 'map',
  style: {
    version: 8,
    name: 'MapLibre GL Teritorio Cluster',
    sources: {
      points: {
        type: 'geojson',
        cluster: true,
        clusterRadius: 80,
        clusterMaxZoom: 22, // Required
        data: {
          type: 'FeatureCollection',
          features: [
            {
              type: 'Feature',
              properties: { id: 1 },
              geometry: { type: 'Point', coordinates: [0, 0] }
            },
            {
              type: 'Feature',
              properties: { id: 2 },
              geometry: { type: 'Point', coordinates: [0, 1] }
            }
          ]
        }
      }
    },
    glyphs: 'https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf',
    layers: [],
    id: 'maplibre-gl-teritorio-cluster'
  }
})

// Create whatever HTML element you want as Cluster
function clusterRender(element, props) {
  element.innerHTML = props.point_count.toLocaleString()
  element.style.setProperty('background-color', 'white')
  element.style.setProperty('border-radius', '100%')
  element.style.setProperty('border', '2px solid green')
  element.style.setProperty('justify-content', 'center')
  element.style.setProperty('align-items', 'center')
  element.style.setProperty('display', 'flex')
  element.style.setProperty('color', 'black')
  element.style.setProperty('width', '60px')
  element.style.setProperty('height', '60px')
  element.style.setProperty('cursor', 'pointer')
}

// Create whatever HTML element you want as individual Marker
// You can use buildCss helper as well (exported by @teritorio/maplibre-gl-teritorio-cluster)
function markerRender(element, feature, markerSize) {
  element.innerHTML = props.point_count.toLocaleString()

  buildCss(element, {
    'background-color': 'white',
    'border-radius': '100%',
    'border': '2px solid green',
    'justify-content': 'center',
    'align-items': 'center',
    'display': 'flex',
    'color': 'black',
    'width': `60px`,
    'height': `60px`,
    'cursor': 'pointer'
  })
}

// Create whatever HTML element you want as Pin Marker
function pinMarkerRender(coords, offset) {
  return new maplibregl.Marker({
    scale: 1.3,
    color: '#f44336',
    anchor: 'bottom'
  })
    .setLngLat(coords)
    .setOffset(offset)
}

map.on('load', () => {
  const clusterLayer = new TeritorioCluster(
    'teritorio-cluster-layer',
    'points',
    {
      clusterRender,
      markerRender,
      pinMarkerRender
    }
  )

  // Add the layer to map
  map.addLayer(clusterLayer)

  // Subscribe to feature click event
  clusterLayer.addEventListener('feature-click', (event) => {
    console.log(event.detail.selectedFeature)
  })
})

API Reference

Constructor

const clusterLayer = new TeritorioCluster(id, sourceId, options)
Parameter Type Description
id string Unique ID for the layer.
sourceId string ID of the GeoJSON source.
options Partial<TeritorioClusterOptions> Optional configuration overrides.

Options

Option Type Default Description
clusterMaxZoom number 17 Maximum zoom level where clusters are visible.
clusterMinZoom number 0 Minimum zoom level where clustering starts.
clusterRender (feature) => HTMLElement clusterRenderDefault Custom function to render cluster.
markerRender (feature) => HTMLElement markerRenderDefault Custom function to render individual markers.
markerSize number 24 Pixel size of rendered markers.
unfoldedClusterRender (features) => HTMLElement[] unfoldedClusterRenderSmart Custom function to render unfolded cluster.
unfoldedClusterMaxLeaves number 7 Maximum number of features to show when a cluster is unfolded.
fitBoundsOptions mapboxgl.FitBoundsOptions { padding: 20 } Options for fitBounds method
initialFeature GeoJSONFeature \ undefined undefined Feature to auto-select on load.
pinMarkerRender (feature) => HTMLElement pinMarkerRenderDefault Custom renderer for the pinned marker.
unfoldedClusterRender

The following rendering function are at your disposal:

  • unfoldedClusterRenderSmart (default): Renders an unfolded cluster in a smart shape (between circle and hexagonal) based on the number of items.

    Smart layout
  • unfoldedClusterRenderCircle: Renders an unfolded cluster in a circular shape.

    Circle layout
  • unfoldedClusterRenderHexaGrid: Renders an unfolded cluster in a hexagonal grid spiral.

    Hexagonal layout
  • unfoldedClusterRenderGrid: Renders an unfolded cluster in a square grid.

    Grid layout

Events

clusterLayer.addEventListener('feature-click', (event) => {
  console.info('Selected feature:', event.detail.selectedFeature)
})

Run Locally

Clone the project

git clone https://github.com/teritorio/maplibre-gl-teritorio-cluster.git

Go to the project directory

cd maplibre-gl-teritorio-cluster

Install dependencies

yarn install

Start the server

yarn dev

Peer Dependencies

This library requires the following peer dependencies to be installed in your project:

Contributing

Contributions are always welcome!

See CONTRIBUTING.md for ways to get started.

Authors

License

MIT

Releases

No releases published

Packages

 
 
 

Contributors