@@ -18,6 +18,7 @@ import { SuperClusterViewportAlgorithm } from "./superviewport";
1818import { initialize , MapCanvasProjection } from "@googlemaps/jest-mocks" ;
1919import { Marker } from "../marker-utils" ;
2020import { ClusterFeature } from "supercluster" ;
21+ import { Cluster } from "../cluster" ;
2122
2223initialize ( ) ;
2324const markerClasses = [
@@ -29,13 +30,28 @@ describe.each(markerClasses)(
2930 "SuperCluster works with legacy and Advanced Markers" ,
3031 ( markerClass ) => {
3132 let map : google . maps . Map ;
33+ let mapCanvasProjection : MapCanvasProjection ;
3234
3335 beforeEach ( ( ) => {
3436 map = new google . maps . Map ( document . createElement ( "div" ) ) ;
37+ mapCanvasProjection = new MapCanvasProjection ( ) ;
38+
39+ mapCanvasProjection . fromLatLngToDivPixel = jest
40+ . fn ( )
41+ . mockImplementation ( ( latLng : google . maps . LatLng ) => ( {
42+ x : latLng . lng ( ) * 100 ,
43+ y : latLng . lat ( ) * 100 ,
44+ } ) ) ;
45+
46+ mapCanvasProjection . fromDivPixelToLatLng = jest
47+ . fn ( )
48+ . mockImplementation ( ( point : google . maps . Point ) => ( {
49+ lat : ( ) => point . y / 100 ,
50+ lng : ( ) => point . x / 100 ,
51+ } ) ) ;
3552 } ) ;
3653
3754 test ( "should only call load if markers change" , ( ) => {
38- const mapCanvasProjection = new MapCanvasProjection ( ) ;
3955 const markers : Marker [ ] = [ new markerClass ( ) ] ;
4056
4157 const superCluster = new SuperClusterViewportAlgorithm ( { } ) ;
@@ -63,25 +79,31 @@ describe.each(markerClasses)(
6379 } ) ;
6480
6581 test ( "should cluster markers" , ( ) => {
66- const mapCanvasProjection = new MapCanvasProjection ( ) ;
6782 const markers : Marker [ ] = [ new markerClass ( ) , new markerClass ( ) ] ;
6883
6984 const superCluster = new SuperClusterViewportAlgorithm ( { } ) ;
7085 map . getZoom = jest . fn ( ) . mockReturnValue ( 0 ) ;
86+
87+ const northEast = {
88+ lat : jest . fn ( ) . mockReturnValue ( - 3 ) ,
89+ lng : jest . fn ( ) . mockReturnValue ( 34 ) ,
90+ } ;
91+ const southWest = {
92+ lat : jest . fn ( ) . mockReturnValue ( 29 ) ,
93+ lng : jest . fn ( ) . mockReturnValue ( 103 ) ,
94+ } ;
95+
7196 map . getBounds = jest . fn ( ) . mockReturnValue ( {
7297 toJSON : ( ) => ( {
7398 west : - 180 ,
7499 south : - 90 ,
75100 east : 180 ,
76101 north : 90 ,
77102 } ) ,
78- getNorthEast : jest
79- . fn ( )
80- . mockReturnValue ( { getLat : ( ) => - 3 , getLng : ( ) => 34 } ) ,
81- getSouthWest : jest
82- . fn ( )
83- . mockReturnValue ( { getLat : ( ) => 29 , getLng : ( ) => 103 } ) ,
103+ getNorthEast : jest . fn ( ) . mockReturnValue ( northEast ) ,
104+ getSouthWest : jest . fn ( ) . mockReturnValue ( southWest ) ,
84105 } ) ;
106+
85107 const { clusters } = superCluster . calculate ( {
86108 markers,
87109 map,
@@ -106,7 +128,6 @@ describe.each(markerClasses)(
106128 } ,
107129 } ;
108130
109- // mock out the supercluster implementation
110131 jest
111132 . spyOn ( superCluster [ "superCluster" ] , "getLeaves" )
112133 . mockImplementation ( ( ) => [ clusterFeature ] ) ;
@@ -117,7 +138,6 @@ describe.each(markerClasses)(
117138 } ) ;
118139
119140 test ( "should not cluster if zoom didn't change" , ( ) => {
120- const mapCanvasProjection = new MapCanvasProjection ( ) ;
121141 const markers : Marker [ ] = [ new markerClass ( ) , new markerClass ( ) ] ;
122142
123143 const superCluster = new SuperClusterViewportAlgorithm ( { } ) ;
@@ -134,12 +154,11 @@ describe.each(markerClasses)(
134154 mapCanvasProjection,
135155 } ) ;
136156
137- expect ( changed ) . toBeTruthy ( ) ;
157+ expect ( changed ) . toBeFalsy ( ) ;
138158 expect ( clusters ) . toBe ( superCluster [ "clusters" ] ) ;
139159 } ) ;
140160
141161 test ( "should not cluster if zoom beyond maxZoom" , ( ) => {
142- const mapCanvasProjection = new MapCanvasProjection ( ) ;
143162 const markers : Marker [ ] = [ new markerClass ( ) , new markerClass ( ) ] ;
144163
145164 const superCluster = new SuperClusterViewportAlgorithm ( { } ) ;
@@ -150,40 +169,46 @@ describe.each(markerClasses)(
150169
151170 map . getZoom = jest . fn ( ) . mockReturnValue ( superCluster [ "state" ] . zoom + 1 ) ;
152171
172+ const northEast = {
173+ lat : jest . fn ( ) . mockReturnValue ( 0 ) ,
174+ lng : jest . fn ( ) . mockReturnValue ( 0 ) ,
175+ } ;
176+ const southWest = {
177+ lat : jest . fn ( ) . mockReturnValue ( 0 ) ,
178+ lng : jest . fn ( ) . mockReturnValue ( 0 ) ,
179+ } ;
180+ map . getBounds = jest . fn ( ) . mockReturnValue ( {
181+ getNorthEast : jest . fn ( ) . mockReturnValue ( northEast ) ,
182+ getSouthWest : jest . fn ( ) . mockReturnValue ( southWest ) ,
183+ } ) ;
184+
153185 const { clusters, changed } = superCluster . calculate ( {
154186 markers,
155187 map,
156188 mapCanvasProjection,
157189 } ) ;
158190
159- expect ( changed ) . toBeTruthy ( ) ;
191+ expect ( changed ) . toBeFalsy ( ) ;
160192 expect ( clusters ) . toBe ( superCluster [ "clusters" ] ) ;
161- expect ( superCluster [ "state" ] ) . toEqual ( { zoom : 21 , view : [ 0 , 0 , 0 , 0 ] } ) ;
193+ expect ( superCluster [ "state" ] . zoom ) . toBe ( 21 ) ;
194+ expect ( Array . isArray ( superCluster [ "state" ] . view ) ) . toBeTruthy ( ) ;
162195 } ) ;
163196
164197 test ( "should round fractional zoom" , ( ) => {
165- const mapCanvasProjection = new MapCanvasProjection ( ) ;
166198 const markers : Marker [ ] = [ new markerClass ( ) , new markerClass ( ) ] ;
167- mapCanvasProjection . fromLatLngToDivPixel = jest
168- . fn ( )
169- . mockImplementation ( ( b : google . maps . LatLng ) => ( {
170- x : b . lat ( ) * 100 ,
171- y : b . lng ( ) * 100 ,
172- } ) ) ;
173- mapCanvasProjection . fromDivPixelToLatLng = jest
174- . fn ( )
175- . mockImplementation (
176- ( p : google . maps . Point ) =>
177- new google . maps . LatLng ( { lat : p . x / 100 , lng : p . y / 100 } )
178- ) ;
199+
200+ const northEast = {
201+ lat : jest . fn ( ) . mockReturnValue ( - 3 ) ,
202+ lng : jest . fn ( ) . mockReturnValue ( 34 ) ,
203+ } ;
204+ const southWest = {
205+ lat : jest . fn ( ) . mockReturnValue ( 29 ) ,
206+ lng : jest . fn ( ) . mockReturnValue ( 103 ) ,
207+ } ;
179208
180209 map . getBounds = jest . fn ( ) . mockReturnValue ( {
181- getNorthEast : jest
182- . fn ( )
183- . mockReturnValue ( { lat : ( ) => - 3 , lng : ( ) => 34 } ) ,
184- getSouthWest : jest
185- . fn ( )
186- . mockReturnValue ( { lat : ( ) => 29 , lng : ( ) => 103 } ) ,
210+ getNorthEast : jest . fn ( ) . mockReturnValue ( northEast ) ,
211+ getSouthWest : jest . fn ( ) . mockReturnValue ( southWest ) ,
187212 } ) ;
188213
189214 const superCluster = new SuperClusterViewportAlgorithm ( { } ) ;
@@ -195,19 +220,190 @@ describe.each(markerClasses)(
195220 map . getZoom = jest . fn ( ) . mockReturnValue ( 1.534 ) ;
196221 expect (
197222 superCluster . calculate ( { markers, map, mapCanvasProjection } )
198- ) . toEqual ( { changed : true , clusters : [ ] } ) ;
223+ ) . toEqual ( { changed : false , clusters : [ ] } ) ;
199224
200225 expect ( superCluster [ "superCluster" ] . getClusters ) . toHaveBeenCalledWith (
201- [ 0 , 0 , 0 , 0 ] ,
226+ expect . any ( Array ) ,
202227 2
203228 ) ;
204229
205230 map . getZoom = jest . fn ( ) . mockReturnValue ( 3.234 ) ;
206231 superCluster . calculate ( { markers, map, mapCanvasProjection } ) ;
207232 expect ( superCluster [ "superCluster" ] . getClusters ) . toHaveBeenCalledWith (
208- [ 0 , 0 , 0 , 0 ] ,
233+ expect . any ( Array ) ,
209234 3
210235 ) ;
211236 } ) ;
237+
238+ test ( "should return changed=false when viewport changes but clusters remain the same" , ( ) => {
239+ const markers : Marker [ ] = [ new markerClass ( ) , new markerClass ( ) ] ;
240+
241+ map . getZoom = jest . fn ( ) . mockReturnValue ( 10 ) ;
242+
243+ const initialNorthEast = {
244+ lat : jest . fn ( ) . mockReturnValue ( 10 ) ,
245+ lng : jest . fn ( ) . mockReturnValue ( 10 ) ,
246+ } ;
247+ const initialSouthWest = {
248+ lat : jest . fn ( ) . mockReturnValue ( 0 ) ,
249+ lng : jest . fn ( ) . mockReturnValue ( 0 ) ,
250+ } ;
251+ const initialBounds = {
252+ getNorthEast : jest . fn ( ) . mockReturnValue ( initialNorthEast ) ,
253+ getSouthWest : jest . fn ( ) . mockReturnValue ( initialSouthWest ) ,
254+ } ;
255+ map . getBounds = jest . fn ( ) . mockReturnValue ( initialBounds ) ;
256+
257+ const algorithm = new SuperClusterViewportAlgorithm ( {
258+ viewportPadding : 60 ,
259+ } ) ;
260+
261+ const sameCluster = [
262+ new Cluster ( {
263+ markers : markers ,
264+ position : { lat : 5 , lng : 5 } ,
265+ } ) ,
266+ ] ;
267+
268+ algorithm . cluster = jest . fn ( ) . mockReturnValue ( sameCluster ) ;
269+
270+ const firstResult = algorithm . calculate ( {
271+ markers,
272+ map,
273+ mapCanvasProjection,
274+ } ) ;
275+
276+ expect ( firstResult . changed ) . toBeTruthy ( ) ;
277+
278+ const newNorthEast = {
279+ lat : jest . fn ( ) . mockReturnValue ( 15 ) ,
280+ lng : jest . fn ( ) . mockReturnValue ( 15 ) ,
281+ } ;
282+ const newSouthWest = {
283+ lat : jest . fn ( ) . mockReturnValue ( 5 ) ,
284+ lng : jest . fn ( ) . mockReturnValue ( 5 ) ,
285+ } ;
286+ const newBounds = {
287+ getNorthEast : jest . fn ( ) . mockReturnValue ( newNorthEast ) ,
288+ getSouthWest : jest . fn ( ) . mockReturnValue ( newSouthWest ) ,
289+ } ;
290+ map . getBounds = jest . fn ( ) . mockReturnValue ( newBounds ) ;
291+
292+ const secondResult = algorithm . calculate ( {
293+ markers,
294+ map,
295+ mapCanvasProjection,
296+ } ) ;
297+
298+ expect ( secondResult . changed ) . toBeFalsy ( ) ;
299+ expect ( secondResult . clusters ) . toEqual ( sameCluster ) ;
300+ } ) ;
301+
302+ test ( "should detect cluster changes accurately with areClusterArraysEqual" , ( ) => {
303+ const markers : Marker [ ] = [ new markerClass ( ) , new markerClass ( ) ] ;
304+
305+ map . getZoom = jest . fn ( ) . mockReturnValue ( 10 ) ;
306+ map . getBounds = jest . fn ( ) . mockReturnValue ( {
307+ getNorthEast : jest
308+ . fn ( )
309+ . mockReturnValue ( { lat : ( ) => 10 , lng : ( ) => 10 } ) ,
310+ getSouthWest : jest . fn ( ) . mockReturnValue ( { lat : ( ) => 0 , lng : ( ) => 0 } ) ,
311+ } ) ;
312+
313+ const algorithm = new SuperClusterViewportAlgorithm ( { } ) ;
314+
315+ const cluster1 = [
316+ new Cluster ( {
317+ markers : [ markers [ 0 ] ] ,
318+ position : { lat : 2 , lng : 2 } ,
319+ } ) ,
320+ new Cluster ( {
321+ markers : [ markers [ 1 ] ] ,
322+ position : { lat : 8 , lng : 8 } ,
323+ } ) ,
324+ ] ;
325+
326+ algorithm . cluster = jest . fn ( ) . mockReturnValueOnce ( cluster1 ) ;
327+
328+ const result1 = algorithm . calculate ( {
329+ markers,
330+ map,
331+ mapCanvasProjection,
332+ } ) ;
333+ expect ( result1 . changed ) . toBeTruthy ( ) ;
334+
335+ const cluster2 = [
336+ new Cluster ( {
337+ markers : [ markers [ 0 ] ] ,
338+ position : { lat : 2 , lng : 2 } ,
339+ } ) ,
340+ new Cluster ( {
341+ markers : [ markers [ 1 ] ] ,
342+ position : { lat : 8 , lng : 8 } ,
343+ } ) ,
344+ ] ;
345+
346+ algorithm . cluster = jest . fn ( ) . mockReturnValueOnce ( cluster2 ) ;
347+
348+ const result2 = algorithm . calculate ( {
349+ markers,
350+ map,
351+ mapCanvasProjection,
352+ } ) ;
353+ expect ( result2 . changed ) . toBeFalsy ( ) ;
354+
355+ const cluster3 = [
356+ new Cluster ( {
357+ markers : markers ,
358+ position : { lat : 5 , lng : 5 } ,
359+ } ) ,
360+ ] ;
361+
362+ algorithm . cluster = jest . fn ( ) . mockReturnValueOnce ( cluster3 ) ;
363+
364+ const result3 = algorithm . calculate ( {
365+ markers,
366+ map,
367+ mapCanvasProjection,
368+ } ) ;
369+ expect ( result3 . changed ) . toBeTruthy ( ) ;
370+ } ) ;
371+
372+ test ( "should correctly calculate viewport state with getPaddedViewport" , ( ) => {
373+ const markers : Marker [ ] = [ new markerClass ( ) ] ;
374+
375+ map . getZoom = jest . fn ( ) . mockReturnValue ( 10 ) ;
376+
377+ const northEast = {
378+ lat : jest . fn ( ) . mockReturnValue ( 10 ) ,
379+ lng : jest . fn ( ) . mockReturnValue ( 20 ) ,
380+ } ;
381+ const southWest = {
382+ lat : jest . fn ( ) . mockReturnValue ( 0 ) ,
383+ lng : jest . fn ( ) . mockReturnValue ( 10 ) ,
384+ } ;
385+
386+ const bounds = {
387+ getNorthEast : jest . fn ( ) . mockReturnValue ( northEast ) ,
388+ getSouthWest : jest . fn ( ) . mockReturnValue ( southWest ) ,
389+ } ;
390+ map . getBounds = jest . fn ( ) . mockReturnValue ( bounds ) ;
391+
392+ const algorithm = new SuperClusterViewportAlgorithm ( {
393+ viewportPadding : 60 ,
394+ } ) ;
395+ algorithm . cluster = jest . fn ( ) . mockReturnValue ( [ ] ) ;
396+
397+ const result = algorithm . calculate ( {
398+ markers,
399+ map,
400+ mapCanvasProjection,
401+ } ) ;
402+
403+ const state = algorithm [ "state" ] ;
404+
405+ expect ( state . view ) . toEqual ( [ 0 , 0 , 0 , 0 ] ) ;
406+ expect ( state . zoom ) . toBe ( 10 ) ;
407+ } ) ;
212408 }
213409) ;
0 commit comments