Skip to content

Commit 7a162eb

Browse files
committed
docs: add JSDocs + update README #38
1 parent b0c009d commit 7a162eb

File tree

7 files changed

+601
-128
lines changed

7 files changed

+601
-128
lines changed

README.md

Lines changed: 91 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,43 @@
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

2425
Or 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
3336
import { 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

7775
map.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) {}
9398
function 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/)

index.html

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,33 @@
9090
document.getElementById('select-feature').addEventListener('click', selectFeature)
9191
})
9292

93+
// Custom rendering functions
94+
const markerRender = (element, markerSize, feature) => {
95+
element.textContent = feature.properties.mag
96+
97+
buildCss(element, {
98+
'background-color': 'green',
99+
'border-radius': '100%',
100+
'justify-content': 'center',
101+
'align-items': 'center',
102+
'display': 'flex',
103+
'color': 'white',
104+
'width': `${markerSize}px`,
105+
'height': `${markerSize}px`,
106+
'cursor': 'pointer'
107+
});
108+
}
109+
110+
const pinMarkerRender = (coords, offset) => {
111+
return new maplibregl.Marker({
112+
scale: 1.3,
113+
color: '#f44336',
114+
anchor: 'bottom'
115+
})
116+
.setLngLat(coords)
117+
.setOffset(offset)
118+
}
119+
93120
const clusterRender = (element, props) => {
94121
element.innerHTML = props.point_count.toLocaleString();
95122

@@ -107,6 +134,7 @@
107134
});
108135
}
109136

137+
// Specific features showcase functions
110138
const loadData = async () => {
111139
const url = document.getElementById('custom-url').value
112140

@@ -131,32 +159,6 @@
131159
})
132160
}
133161

134-
const markerRender = (element, markerSize, feature) => {
135-
element.textContent = feature.properties.mag
136-
137-
buildCss(element, {
138-
'background-color': 'green',
139-
'border-radius': '100%',
140-
'justify-content': 'center',
141-
'align-items': 'center',
142-
'display': 'flex',
143-
'color': 'white',
144-
'width': `${markerSize}px`,
145-
'height': `${markerSize}px`,
146-
'cursor': 'pointer'
147-
});
148-
}
149-
150-
const pinMarkerRender = (coords, offset) => {
151-
return new maplibregl.Marker({
152-
scale: 1.3,
153-
color: '#f44336',
154-
anchor: 'bottom'
155-
})
156-
.setLngLat(coords)
157-
.setOffset(offset)
158-
}
159-
160162
const selectFeature = async () => {
161163
const id = document.getElementById('feature-id').value
162164

0 commit comments

Comments
 (0)