11# MapLibre GL Teritorio Cluster
22
3- Render native MapLibre GL JS clusters as HTML marker .
3+ Enhance MapLibre GL JS with fully interactive HTML-based clusters and markers .
44
5- Renders:
6- - HTML cluster
7- - HTML Unfolded cluster defined by a minimum leaves and min / max zoom threshold
8- - Pin Marker on feature click
5+ ** Features:**
6+ - 🧱 Renders native MapLibre GL JS clusters as HTML elements
7+ - 🌀 Smart unfolded clusters (circle, hexagrid, grid) based on zoom level and item count
8+ - 📌 Pin marker display on feature click
9+ - 🔍 Interact with overlapping markers without needing to zoom in
10+ - 🚫 Avoids the need to uncluster or zoom for interaction
11+ ---
12+ ## Demo
913
10- Allow visualization and interaction with all markers, even when superposed.
11- Can display and interact with small cluster without the need to zoom or uncluster.
14+ 👉 [ ** Live Demo** ] ( https://teritorio.github.io/maplibre-gl-teritorio-cluster/index.html )
1215
13- See the [ Demo page] ( https://teritorio.github.io/maplibre-gl-teritorio-cluster/index.html ) .
16+ ![ Demo screenshot] ( public/image.png )
17+ ## Installation
1418
15- ![ alt text ] ( public/image.png )
19+ Install @ teritorio/maplibre-gl-teritorio-cluster with yarn
1620
17- ## Usage
18-
19- Install as a dependency
2021``` bash
21- yarn add @teritorio/maplibre-gl-teritorio-cluster
22+ yarn add @teritorio/maplibre-gl-teritorio-cluster
2223```
2324
2425Or use it from CDN
2526``` html
2627<script type =" module" src =" https://unpkg.com/@teritorio/maplibre-gl-teritorio-cluster/dist/maplibre-gl-teritorio-cluster.js" ></script >
2728```
2829
30+ ## Usage/Examples
31+
2932> [ !WARNING]
30- > Set your GeoJson source with ` clusterMaxZoom: 22 ` in order to let the plugin handle cluster/individual marker rendering across all zoom level
33+ > Set your GeoJSON source with ` clusterMaxZoom: 22 ` in order to let the plugin handle cluster/individual marker rendering across all zoom level
3134
32- ``` js
35+ ``` javascript
3336import { TeritorioCluster } from ' @teritorio/maplibre-gl-teritorio-cluster'
34- import { Map } from ' maplibre-gl'
37+ import maplibregl from ' maplibre-gl'
38+ import ' maplibre-gl/dist/maplibre-gl.css'
3539
36- const map = new Map ({
40+ const map = new maplibregl. Map ({
3741 container: ' map' ,
3842 style: {
3943 version: 8 ,
@@ -63,23 +67,24 @@ const map = new Map({
6367 }
6468 },
6569 glyphs: ' https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf' ,
66- layers: [
67- {
68- id: ' cluster' ,
69- type: ' circle' ,
70- source: ' points'
71- }
72- ],
70+ layers: [],
7371 id: ' muks8j3'
7472 }
7573})
7674
7775map .on (' load' , () => {
78- const teritorioCluster = new TeritorioCluster (map, ' points' , options)
79-
80- // Get feature click event
81- teritorioCluster .addEventListener (' click' , (e ) => {
82- console .log (e .detail .selectedFeature )
76+ const teritorioLayer = new TeritorioCluster (
77+ ' teritorio-cluster-layer' ,
78+ ' points' ,
79+ options
80+ )
81+
82+ // Add the layer to map
83+ map .addLayer (teritorioLayer)
84+
85+ // Subscribe to feature click event
86+ teritorioLayer .addEventListener (' feature-click' , (event ) => {
87+ console .log (event .detail .selectedFeature )
8388 })
8489})
8590
@@ -93,72 +98,77 @@ function markerRender(element, feature, markerSize) {}
9398function pinMarkerRender (coords , offset ) {}
9499```
95100
96- ## API
97-
98- - [ TeritorioCluster] ( #teritoriocluster )
99- - [ Parameters] ( #parameters )
100- - [ Options] ( #options )
101- - [ Methods] ( #methods )
102- - [ addEventListener] ( #addeventlistener )
101+ ## API Reference
103102
104- ### TeritorioCluster
103+ #### Constructor
105104
106- Create a new Maplibre GL JS plugin for feature (cluster / individual marker) rendering
105+ ``` js
106+ const teritorioLayer = new TeritorioCluster (id, sourceId, options)
107+ ```
107108
108- #### Parameters
109- | Name | Type | Description | Required | Default value |
110- | ----------| --------------------------------------------------------------------| --------------------------------------------------------------------------------------------------| ----------| ---------------|
111- | map | [ ` Map ` ] ( https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/ ) | The Map object represents the map on your page | ✅ | ❌ |
112- | sourceId | ` string ` | The ID of the source. Should be a vector source, preferably of type GeoJSON and not vector tiles | ✅ | ❌ |
113- | options | ` object ` | Options to configure the plugin | ❌ | ` undefined ` |
109+ | Parameter | Type | Description |
110+ | ---------- | ---------------------------------- | ---------------------------------------- |
111+ | ` id ` | ` string ` | Unique ID for the layer. |
112+ | ` sourceId ` | ` string ` | ID of the GeoJSON source. |
113+ | ` options ` | ` Partial<TeritorioClusterOptions> ` | Optional configuration overrides. |
114114
115115#### Options
116- | Name | Type | Description | Required | Default value |
117- | -------------------------------| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------------------------------------------------------------------------------------------------| ----------| -----------------------------------------------------|
118- | clusterMaxZoom | ` number ` | Maximal zoom level at which we force the rendering of the Unfolded Cluster | ❌ | ` 17 ` |
119- | clusterMinZoom | ` number ` | Minimal zoom level at which we force the rendering of the Unfolded Cluster | ❌ | ` 0 ` |
120- | clusterRenderFn | ` (element: HTMLDivElement, props: MapGeoJSONFeature['properties']): void ` | Cluster render function | ❌ | ` src/utils/helpers.ts/clusterRenderDefault() ` |
121- | fitBoundsOptions | [ ` FitBoundsOptions ` ] ( https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FitBoundsOptions ) | Options for [ Map#fitBounds] ( https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#fitbounds ) method | ❌ | ` { padding: 20 } ` |
122- | initialFeature | [ ` MapGeoJSONFeature ` ] ( https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapGeoJSONFeature/ ) | Feature to select on initial rendering | ❌ | ` undefined ` |
123- | markerRenderFn | ` (element: HTMLDivElement, feature: MapGeoJSONFeature, markerSize: number): void ` | Individual Marker render function | ❌ | ` src/utils/helpers.ts/markerRenderDefault() ` |
124- | markerSize | ` number ` (in px) | Size of Marker | ❌ | ` 24 ` |
125- | unfoldedClusterRenderFn | ` (parent: HTMLDivElement, items: MapGeoJSONFeature[], markerSize: number, renderMarker: (feature: MapGeoJSONFeature) => HTMLDivElement, clickHandler: (e: Event, feature: MapGeoJSONFeature) => void) => void ` | Unfolded Cluster render function | ❌ | ` src/utils/helpers.ts/unfoldedClusterRenderSmart() ` |
126- | unfoldedClusterRenderSmart | Mix between Circular and HexaShape shape Unfolded Cluster render function | - | - | - |
127- | unfoldedClusterRenderGrid | Grid shape Unfolded Cluster render function function | - | - | - |
128- | unfoldedClusterRenderCircle | Circular shape Unfolded Cluster render function function | - | - | - |
129- | unfoldedClusterRenderHexaGrid | HexaGrid shape Unfolded Cluster render function function | - | - | - |
130- | unfoldedClusterMaxLeaves | ` number ` | Unfolded Cluster max leaves number | ❌ | ` 7 ` |
131- | pinMarkerRenderFn | ` (coords: LngLatLike, offset: Point): Marker ` | Pin Marker render function | ❌ | ` src/utils/helpers.ts/pinMarkerRenderDefault() ` |
132-
133- #### Methods
134- | Name | Type | Description |
135- | ----------------------| ------------------------------------------------------------------------------------------------------------------------| -----------------------------------------------------------------------------------------------------------------|
136- | addEventListener | ('feature-click', (e: Event) => void) | Listen to feature click and return a [ ` MapGeoJSONFeature ` ] ( https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapGeoJSONFeature/ ) from ` e.detail.selectedFeature ` for external control. |
137- | resetSelectedFeature | () => void | Remove selected feature and associated Pin Marker |
138- | setBoundsOptions | (options: [ ` FitBoundsOptions ` ] ( https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FitBoundsOptions ) ) => void | Update Map's visible area |
139- | setSelectedFeature | (feature: [ ` MapGeoJSONFeature ` ] ( https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapGeoJSONFeature/ ) ) => void | Set selected feature and display Pin Marker on top of it |
140-
141- ## Dev
142- Install dependencies
116+
117+ | Option | Type | Default | Description |
118+ | -------------------------- | ----------------------------- | ---------------------------- | -------------------------------------------------------------- |
119+ | ` clusterMaxZoom ` | ` number ` | ` 17 ` | Maximum zoom level where clusters are visible. |
120+ | ` clusterMinZoom ` | ` number ` | ` 0 ` | Minimum zoom level where clustering starts. |
121+ | ` clusterRender ` | ` (feature) => HTMLElement ` | ` clusterRenderDefault ` | Custom function to render cluster. |
122+ | ` markerRender ` | ` (feature) => HTMLElement ` | ` markerRenderDefault ` | Custom function to render individual markers. |
123+ | ` markerSize ` | ` number ` | ` 24 ` | Pixel size of rendered markers. |
124+ | ` unfoldedClusterRender ` | ` (features) => HTMLElement[] ` | ` unfoldedClusterRenderSmart ` | Function to render unfolded cluster. |
125+ | ` unfoldedClusterMaxLeaves ` | ` number ` | ` 7 ` | Maximum number of features to show when a cluster is unfolded. |
126+ | ` fitBoundsOptions ` | ` mapboxgl.FitBoundsOptions ` | ` { padding: 20 } ` | Options for [ fitBounds] ( https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#fitbounds ) method |
127+ | ` initialFeature ` | ` GeoJSONFeature \| undefined ` | ` undefined ` | Feature to auto-select on load. |
128+ | ` pinMarkerRender ` | ` (feature) => HTMLElement ` | ` pinMarkerRenderDefault ` | Custom renderer for the pinned marker. |
129+
130+ ## Events
131+
132+ ``` js
133+ teritorioLayer .addEventListener (' feature-click' , (event ) => {
134+ console .log (' Selected feature:' , event .detail .selectedFeature )
135+ })
136+ ```
137+ ## Run Locally
138+
139+ Clone the project
140+
141+ ``` bash
142+ git clone https://github.com/teritorio/maplibre-gl-teritorio-cluster.git
143+ ```
144+
145+ Go to the project directory
146+
143147``` bash
144- yarn install
148+ cd maplibre-gl-teritorio-cluster
145149```
146150
147- Serve the demo page
151+ Install dependencies
152+
148153``` bash
149- yarn dev
154+ yarn install
150155```
151156
152- ## Peer Dependencies
157+ Start the server
158+
159+ ``` bash
160+ yarn dev
161+ ```
153162
154- This library requires the following peer dependencies to be installed in your project:
163+ ## Contributing
155164
156- - [ maplibre-gl-js ] ( https://github.com/maplibre/maplibre-gl-js ) >= v5.4.0
165+ Contributions are always welcome!
157166
158- ## Contribution
167+ See [ ` CONTRIBUTING.md ` ] ( CONTRIBUTING.md ) for ways to get started.
159168
160- Please see the [ contribution guide ] ( CONTRIBUTING.md ) .
169+ ## Authors
161170
162- ## Author
171+ - [ Teritorio] ( https://teritorio.fr )
172+ ## License
163173
164- [ Teritorio ] ( https://teritorio.fr )
174+ [ MIT ] ( https://choosealicense.com/licenses/mit/ )
0 commit comments