@@ -10,55 +10,13 @@ import type {
1010 Marker ,
1111 Point ,
1212} from 'maplibre-gl'
13+ import type { FeatureInClusterMatch , FeatureMatch , TeritorioClusterOptions } from './types'
1314import bbox from '@turf/bbox'
1415import { featureCollection } from '@turf/helpers'
1516import maplibre from 'maplibre-gl'
1617import { deepMerge } from './utils/deep-merge'
1718import { clusterRenderDefault , markerRenderDefault , pinMarkerRenderDefault , unfoldedClusterRenderSmart } from './utils/helpers'
18-
19- type UnfoldedCluster = (
20- (
21- parent : HTMLDivElement ,
22- items : MapGeoJSONFeature [ ] ,
23- markerSize : number ,
24- renderMarker : ( feature : MapGeoJSONFeature ) => HTMLDivElement ,
25- clickHandler : ( event : Event , feature : MapGeoJSONFeature ) => void
26- ) => void
27- )
28- type ClusterRender = (
29- (
30- element : HTMLDivElement ,
31- props : MapGeoJSONFeature [ 'properties' ]
32- ) => void
33- )
34- type MarkerRender = (
35- (
36- element : HTMLDivElement ,
37- markerSize : number ,
38- feature ?: GeoJSONFeature
39- ) => void
40- )
41- type PinMarkerRender = (
42- (
43- coords : LngLatLike ,
44- offset : Point
45- ) => Marker
46- )
47- interface FeatureInClusterMatch { clusterId : string , feature : GeoJSONFeature }
48- type FeatureMatch = FeatureInClusterMatch | GeoJSONFeature
49-
50- interface TeritorioClusterOptions {
51- clusterMaxZoom : number
52- clusterMinZoom : number
53- clusterRender : ClusterRender
54- fitBoundsOptions : FitBoundsOptions
55- initialFeature : MapGeoJSONFeature | undefined
56- markerRender : MarkerRender
57- markerSize : number
58- unfoldedClusterRender : UnfoldedCluster
59- unfoldedClusterMaxLeaves : number
60- pinMarkerRender : PinMarkerRender
61- }
19+ import { calculatePinMarkerOffset , getFeatureId , isClusterFeature } from './utils/index'
6220
6321export class TeritorioCluster extends EventTarget implements CustomLayerInterface {
6422 public id : string
@@ -148,7 +106,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
148106 }
149107
150108 public setSelectedFeature = ( feature : GeoJSONFeature ) : void => {
151- const id = this . getFeatureId ( feature )
109+ const id = getFeatureId ( feature )
152110 const match = this . findFeature ( id )
153111
154112 if ( ! match ) {
@@ -200,8 +158,13 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
200158 }
201159
202160 private renderCustom = async ( currentExec : number ) : Promise < void > => {
203- if ( ! this . shouldRender ( currentExec ) )
161+ if (
162+ ! this . map
163+ || ! this . map . isSourceLoaded ( this . sourceId )
164+ || ! this . source
165+ || this . abortExec !== currentExec ) {
204166 return
167+ }
205168
206169 const features = this . map ! . querySourceFeatures ( this . sourceId )
207170 this . clearRenderState ( )
@@ -217,10 +180,10 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
217180 if ( this . abortExec !== currentExec )
218181 return
219182
220- const id = this . getFeatureId ( feature )
183+ const id = getFeatureId ( feature )
221184 this . featuresMap . set ( id , feature )
222185
223- if ( this . isClusterFeature ( feature ) ) {
186+ if ( isClusterFeature ( feature ) ) {
224187 const success = await this . loadClusterLeaves ( id , feature )
225188
226189 if ( this . abortExec !== currentExec )
@@ -233,7 +196,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
233196
234197 this . featuresMap . forEach ( ( feature ) => {
235198 const coords = feature . geometry . type === 'Point' ? new maplibre . LngLat ( feature . geometry . coordinates [ 0 ] , feature . geometry . coordinates [ 1 ] ) : undefined
236- const id = this . getFeatureId ( feature )
199+ const id = getFeatureId ( feature )
237200
238201 if ( ! coords ) {
239202 console . error ( `Feature ${ id } is not Geometry.Point, thus not supported yet.` )
@@ -281,8 +244,8 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
281244
282245 // If initialFeature is part of this new cluster
283246 // We position the Pin marker on it
284- if ( this . opts . initialFeature && this . isFeatureInCluster ( id , this . getFeatureId ( this . opts . initialFeature ) ) ) {
285- this . selectedFeatureId = this . getFeatureId ( this . opts . initialFeature )
247+ if ( this . opts . initialFeature && this . isFeatureInCluster ( id , getFeatureId ( this . opts . initialFeature ) ) ) {
248+ this . selectedFeatureId = getFeatureId ( this . opts . initialFeature )
286249 this . renderPinMarkerInCluster ( element , coords )
287250 this . opts . initialFeature = undefined
288251 }
@@ -303,7 +266,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
303266
304267 // If initialFeature is this new marker
305268 // We position the Pin marker on it
306- if ( this . opts . initialFeature && ( this . getFeatureId ( this . opts . initialFeature ) === id ) ) {
269+ if ( this . opts . initialFeature && ( getFeatureId ( this . opts . initialFeature ) === id ) ) {
307270 this . selectedFeatureId = id
308271 this . renderPinMarker ( coords )
309272 this . opts . initialFeature = undefined
@@ -321,7 +284,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
321284 }
322285
323286 if ( this . opts . initialFeature && ! this . selectedFeatureId && ! this . pinMarker ) {
324- const id = this . getFeatureId ( this . opts . initialFeature )
287+ const id = getFeatureId ( this . opts . initialFeature )
325288 const coords = this . opts . initialFeature . geometry . type === 'Point'
326289 ? new maplibre . LngLat ( this . opts . initialFeature . geometry . coordinates [ 0 ] , this . opts . initialFeature . geometry . coordinates [ 1 ] )
327290 : undefined
@@ -389,20 +352,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
389352 return false
390353 }
391354
392- return this . clusterLeaves . get ( clusterId ) ! . findIndex ( feature => this . getFeatureId ( feature ) === featureId ) > - 1
393- }
394-
395- private getClusterCenter = ( cluster : HTMLElement ) : { clusterXCenter : number , clusterYCenter : number } => {
396- const { left, right, top, bottom } = cluster . getBoundingClientRect ( )
397-
398- return { clusterXCenter : ( left + right ) / 2 , clusterYCenter : ( top + bottom ) / 2 }
399- }
400-
401- private calculatePinMarkerOffset = ( cluster : HTMLElement , marker : HTMLElement ) : Point => {
402- const { clusterXCenter, clusterYCenter } = this . getClusterCenter ( cluster )
403- const { x, y, height, width } = marker . getBoundingClientRect ( )
404-
405- return new maplibre . Point ( x - clusterXCenter + ( width / 2 ) , y - clusterYCenter + ( height / 2 ) )
355+ return this . clusterLeaves . get ( clusterId ) ! . findIndex ( feature => getFeatureId ( feature ) === featureId ) > - 1
406356 }
407357
408358 private renderPinMarkerInCluster = ( cluster : HTMLElement , coords : LngLatLike ) : void => {
@@ -418,13 +368,13 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
418368 if ( ! selectedFeatureHTML )
419369 throw new Error ( 'Selected feature HTML marker was not found !' )
420370
421- this . renderPinMarker ( coords , this . calculatePinMarkerOffset ( cluster , selectedFeatureHTML ) )
371+ this . renderPinMarker ( coords , calculatePinMarkerOffset ( cluster , selectedFeatureHTML ) )
422372 }
423373 }
424374
425375 private renderMarker = ( feature : GeoJSONFeature ) : HTMLDivElement => {
426376 const element = document . createElement ( 'div' )
427- element . id = this . getFeatureId ( feature )
377+ element . id = getFeatureId ( feature )
428378
429379 this . opts . markerRender ( element , this . opts . markerSize , feature )
430380
@@ -439,7 +389,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
439389 const iterator = this . clusterLeaves . entries ( )
440390
441391 for ( const [ key , value ] of iterator ) {
442- const match = value . find ( feature => this . getFeatureId ( feature ) === id )
392+ const match = value . find ( feature => getFeatureId ( feature ) === id )
443393
444394 if ( match ) {
445395 return { clusterId : key , feature : match }
@@ -450,7 +400,7 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
450400 private featureClickHandler = ( event : Event , feature : GeoJSONFeature ) : void => {
451401 event . stopPropagation ( )
452402
453- if ( ! ( event . currentTarget instanceof HTMLElement ) || this . selectedFeatureId === this . getFeatureId ( feature ) )
403+ if ( ! ( event . currentTarget instanceof HTMLElement ) || this . selectedFeatureId === getFeatureId ( feature ) )
454404 return
455405
456406 this . setSelectedFeature ( feature )
@@ -492,44 +442,11 @@ export class TeritorioCluster extends EventTarget implements CustomLayerInterfac
492442 }
493443 }
494444
495- private shouldRender = ( currentExec : number ) : boolean => {
496- return ! ! this . map
497- && this . map . isSourceLoaded ( this . sourceId )
498- && ! ! this . source
499- && this . abortExec === currentExec
500- }
501-
502445 private clearRenderState = ( ) : void => {
503446 this . clusterLeaves . clear ( )
504447 this . featuresMap . clear ( )
505448 }
506449
507- private isClusterFeature = ( feature : GeoJSONFeature ) : boolean => {
508- return Boolean ( feature . properties ?. cluster )
509- }
510-
511- private getFeatureId = ( feature : GeoJSONFeature ) : string => {
512- if ( feature . properties . cluster ) {
513- if ( ! feature . id )
514- throw new Error ( 'Cluster feature is missing "id".' )
515- return feature . id . toString ( )
516- }
517-
518- // Vido support: shouldn't be part of this plugin
519- let metadata = feature . properties . metadata
520-
521- if ( typeof metadata === 'string' ) {
522- try {
523- metadata = JSON . parse ( metadata )
524- }
525- catch {
526- metadata = undefined
527- }
528- }
529-
530- return ( metadata ?. id ?? feature . properties ?. id ) . toString ( )
531- }
532-
533450 private setSource = ( ) : void => {
534451 if ( ! this . map )
535452 return
0 commit comments