From 12c1762c5d8da5b3d1eae52cb7cfb8db34324b32 Mon Sep 17 00:00:00 2001 From: Alex Muramoto Date: Thu, 13 Jul 2023 09:39:12 -0700 Subject: [PATCH] fix: reduce flickering (#699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(release): 2.2.0-beta.1 [skip ci] ## [2.2.0-beta.1](https://github.com/googlemaps/js-markerclusterer/compare/v2.1.4...v2.2.0-beta.1) (2023-06-01) ### Features * add a dev server ([#656](https://github.com/googlemaps/js-markerclusterer/issues/656)) ([b025dec](https://github.com/googlemaps/js-markerclusterer/commit/b025dec7fdfe2a1c9317a5e5b1ec62350adf1759)) ### Code Refactoring * **distanceBetweenPoints:** optimize ([#646](https://github.com/googlemaps/js-markerclusterer/issues/646)) ([e0f9a11](https://github.com/googlemaps/js-markerclusterer/commit/e0f9a114b7f3f93a2c0a62fd0afba12d82ed201a)) ### Miscellaneous Chores * **deps-dev:** bump @babel/preset-env from 7.21.5 to 7.22.4 ([#650](https://github.com/googlemaps/js-markerclusterer/issues/650)) ([982730d](https://github.com/googlemaps/js-markerclusterer/commit/982730d12def9ca6595a52f0c2c5781c849ebf3a)) * **deps-dev:** bump @babel/runtime-corejs3 from 7.21.5 to 7.22.3 ([#649](https://github.com/googlemaps/js-markerclusterer/issues/649)) ([1c9f4fb](https://github.com/googlemaps/js-markerclusterer/commit/1c9f4fb446cf92258b35ca04fb811a52ffd82ca2)) * **deps-dev:** bump @types/selenium-webdriver from 4.1.14 to 4.1.15 ([#655](https://github.com/googlemaps/js-markerclusterer/issues/655)) ([526e65c](https://github.com/googlemaps/js-markerclusterer/commit/526e65c1839ec747f4dc047bc7553b5214410eac)) * **deps-dev:** bump @typescript-eslint/eslint-plugin ([#654](https://github.com/googlemaps/js-markerclusterer/issues/654)) ([68a94db](https://github.com/googlemaps/js-markerclusterer/commit/68a94dbff007c8b8937be651372ae46a35a576c1)) * **deps-dev:** bump @typescript-eslint/parser from 5.59.7 to 5.59.8 ([#653](https://github.com/googlemaps/js-markerclusterer/issues/653)) ([a46d0a7](https://github.com/googlemaps/js-markerclusterer/commit/a46d0a7c68a2af564e34b37dd211b24d90e4ec47)) * **deps-dev:** bump geckodriver from 4.0.0 to 4.0.2 ([#652](https://github.com/googlemaps/js-markerclusterer/issues/652)) ([19518a4](https://github.com/googlemaps/js-markerclusterer/commit/19518a436826c5117eb79f6a6626e72c29eb1688)) * update actions to use Node.js 16 ([#659](https://github.com/googlemaps/js-markerclusterer/issues/659)) ([bcbdddf](https://github.com/googlemaps/js-markerclusterer/commit/bcbdddf8996b9447940fefc8c065df27958f4880)) * fix: reduce flickering (#660) * chore(release): 2.2.0 [skip ci] ## [2.2.0](https://github.com/googlemaps/js-markerclusterer/compare/v2.1.4...v2.2.0) (2023-06-01) ### Features * add a dev server ([#656](https://github.com/googlemaps/js-markerclusterer/issues/656)) ([b025dec](https://github.com/googlemaps/js-markerclusterer/commit/b025dec7fdfe2a1c9317a5e5b1ec62350adf1759)) ### Code Refactoring * **distanceBetweenPoints:** optimize ([#646](https://github.com/googlemaps/js-markerclusterer/issues/646)) ([e0f9a11](https://github.com/googlemaps/js-markerclusterer/commit/e0f9a114b7f3f93a2c0a62fd0afba12d82ed201a)) ### Miscellaneous Chores * **deps-dev:** bump @babel/preset-env from 7.21.5 to 7.22.4 ([#650](https://github.com/googlemaps/js-markerclusterer/issues/650)) ([982730d](https://github.com/googlemaps/js-markerclusterer/commit/982730d12def9ca6595a52f0c2c5781c849ebf3a)) * **deps-dev:** bump @babel/runtime-corejs3 from 7.21.5 to 7.22.3 ([#649](https://github.com/googlemaps/js-markerclusterer/issues/649)) ([1c9f4fb](https://github.com/googlemaps/js-markerclusterer/commit/1c9f4fb446cf92258b35ca04fb811a52ffd82ca2)) * **deps-dev:** bump @types/selenium-webdriver from 4.1.14 to 4.1.15 ([#655](https://github.com/googlemaps/js-markerclusterer/issues/655)) ([526e65c](https://github.com/googlemaps/js-markerclusterer/commit/526e65c1839ec747f4dc047bc7553b5214410eac)) * **deps-dev:** bump @typescript-eslint/eslint-plugin ([#654](https://github.com/googlemaps/js-markerclusterer/issues/654)) ([68a94db](https://github.com/googlemaps/js-markerclusterer/commit/68a94dbff007c8b8937be651372ae46a35a576c1)) * **deps-dev:** bump @typescript-eslint/parser from 5.59.7 to 5.59.8 ([#653](https://github.com/googlemaps/js-markerclusterer/issues/653)) ([a46d0a7](https://github.com/googlemaps/js-markerclusterer/commit/a46d0a7c68a2af564e34b37dd211b24d90e4ec47)) * **deps-dev:** bump geckodriver from 4.0.0 to 4.0.2 ([#652](https://github.com/googlemaps/js-markerclusterer/issues/652)) ([19518a4](https://github.com/googlemaps/js-markerclusterer/commit/19518a436826c5117eb79f6a6626e72c29eb1688)) * update actions to use Node.js 16 ([#659](https://github.com/googlemaps/js-markerclusterer/issues/659)) ([bcbdddf](https://github.com/googlemaps/js-markerclusterer/commit/bcbdddf8996b9447940fefc8c065df27958f4880)) * fix: reduce flickering * Individual markers Before this PR all the individual markers were removed from the map during the render cycle by calling the reset method and to maybe be added back later in renderClusters. After this CL the individual markers that will still be displayed on the map after the render cycle are not removed from the map. * Group markers This PR still renders the group markers each time but the former group markers are only removed from the map after the new one are added. It turns out that removing the group markers in the next raf really help with flickering. *  chore: resolves merge conflicts on to beta --------- Co-authored-by: semantic-release-bot Co-authored-by: Alex Muramoto * chore: trigger beta release * chore(release): 2.2.0-beta.2 [skip ci] ## [2.2.0-beta.2](https://github.com/googlemaps/js-markerclusterer/compare/v2.2.0-beta.1...v2.2.0-beta.2) (2023-06-01) ### Bug Fixes * reduce flickering ([#660](https://github.com/googlemaps/js-markerclusterer/issues/660)) ([8b756a7](https://github.com/googlemaps/js-markerclusterer/commit/8b756a7ebea7639ba7744fbe7b4537afbff32a2f)), closes [#656](https://github.com/googlemaps/js-markerclusterer/issues/656) [#646](https://github.com/googlemaps/js-markerclusterer/issues/646) [#650](https://github.com/googlemaps/js-markerclusterer/issues/650) [#649](https://github.com/googlemaps/js-markerclusterer/issues/649) [#655](https://github.com/googlemaps/js-markerclusterer/issues/655) [#654](https://github.com/googlemaps/js-markerclusterer/issues/654) [#653](https://github.com/googlemaps/js-markerclusterer/issues/653) [#652](https://github.com/googlemaps/js-markerclusterer/issues/652) [#659](https://github.com/googlemaps/js-markerclusterer/issues/659) ### Miscellaneous Chores * trigger beta release ([434cc68](https://github.com/googlemaps/js-markerclusterer/commit/434cc68b2b0d457041044f3580015239d3f5c104)) * chore(release): 2.3.2-beta.1 [skip ci] ### [2.3.2-beta.1](https://github.com/googlemaps/js-markerclusterer/compare/v2.3.1...v2.3.2-beta.1) (2023-07-13) ### Bug Fixes * reduce flickering ([#660](https://github.com/googlemaps/js-markerclusterer/issues/660)) ([8b756a7](https://github.com/googlemaps/js-markerclusterer/commit/8b756a7ebea7639ba7744fbe7b4537afbff32a2f)), closes [#656](https://github.com/googlemaps/js-markerclusterer/issues/656) [#646](https://github.com/googlemaps/js-markerclusterer/issues/646) [#650](https://github.com/googlemaps/js-markerclusterer/issues/650) [#649](https://github.com/googlemaps/js-markerclusterer/issues/649) [#655](https://github.com/googlemaps/js-markerclusterer/issues/655) [#654](https://github.com/googlemaps/js-markerclusterer/issues/654) [#653](https://github.com/googlemaps/js-markerclusterer/issues/653) [#652](https://github.com/googlemaps/js-markerclusterer/issues/652) [#659](https://github.com/googlemaps/js-markerclusterer/issues/659) ### Miscellaneous Chores * **deps-dev:** bump @babel/preset-env from 7.22.4 to 7.22.5 ([#683](https://github.com/googlemaps/js-markerclusterer/issues/683)) ([24f0a1c](https://github.com/googlemaps/js-markerclusterer/commit/24f0a1c5b61ff1978d74119971752ce35b81f3d6)) * **deps-dev:** bump @babel/preset-env from 7.22.5 to 7.22.7 ([#694](https://github.com/googlemaps/js-markerclusterer/issues/694)) ([2eee952](https://github.com/googlemaps/js-markerclusterer/commit/2eee952667f6b310c13da469abc72128397b3848)) * **deps-dev:** bump @babel/runtime-corejs3 from 7.22.3 to 7.22.6 ([#697](https://github.com/googlemaps/js-markerclusterer/issues/697)) ([c8850f3](https://github.com/googlemaps/js-markerclusterer/commit/c8850f3ed8f9162aaad4b471253f33b108159807)) * **deps-dev:** bump @googlemaps/jest-mocks from 2.19.1 to 2.19.2 ([#684](https://github.com/googlemaps/js-markerclusterer/issues/684)) ([d1aa925](https://github.com/googlemaps/js-markerclusterer/commit/d1aa92519fb1996bfe2c9a330cfe492d8d1d6c86)) * **deps-dev:** bump @rollup/plugin-typescript from 11.1.1 to 11.1.2 ([#690](https://github.com/googlemaps/js-markerclusterer/issues/690)) ([e5ba6c5](https://github.com/googlemaps/js-markerclusterer/commit/e5ba6c57ccc943fda106e5de1df647a5261b0599)) * **deps-dev:** bump @typescript-eslint/eslint-plugin ([#686](https://github.com/googlemaps/js-markerclusterer/issues/686)) ([0e1f24a](https://github.com/googlemaps/js-markerclusterer/commit/0e1f24a780b002eb9c25eaf003d71a061282b2fb)) * **deps-dev:** bump @typescript-eslint/eslint-plugin ([#689](https://github.com/googlemaps/js-markerclusterer/issues/689)) ([0becc85](https://github.com/googlemaps/js-markerclusterer/commit/0becc85ca276c27bbece8e157ae47aa79d7c5750)) * **deps-dev:** bump @typescript-eslint/eslint-plugin ([#696](https://github.com/googlemaps/js-markerclusterer/issues/696)) ([bebef45](https://github.com/googlemaps/js-markerclusterer/commit/bebef4553049b7ed350f3550de3e15acf9988051)) * **deps-dev:** bump core-js from 3.31.0 to 3.31.1 ([#695](https://github.com/googlemaps/js-markerclusterer/issues/695)) ([e865156](https://github.com/googlemaps/js-markerclusterer/commit/e865156f2c9f3e95c77cc6cb9fec42e621b4993d)) * **deps-dev:** bump eslint from 8.42.0 to 8.43.0 ([#685](https://github.com/googlemaps/js-markerclusterer/issues/685)) ([122eb7b](https://github.com/googlemaps/js-markerclusterer/commit/122eb7bcdb73d773fd8e61b6f0e576a5f1ece1e5)) * **deps-dev:** bump eslint from 8.43.0 to 8.44.0 ([#688](https://github.com/googlemaps/js-markerclusterer/issues/688)) ([7f21c12](https://github.com/googlemaps/js-markerclusterer/commit/7f21c12ae96a78b64ea112a427d727d863e64b2c)) * **deps:** bump tough-cookie from 4.1.2 to 4.1.3 ([#693](https://github.com/googlemaps/js-markerclusterer/issues/693)) ([adf3051](https://github.com/googlemaps/js-markerclusterer/commit/adf3051997de77bc04d40206386aa7ce3da931d8)) * **release:** 2.2.0-beta.1 [skip ci] ([90a62ee](https://github.com/googlemaps/js-markerclusterer/commit/90a62ee7fe1a753e9e341b415d4165c6ff796b66)), closes [#656](https://github.com/googlemaps/js-markerclusterer/issues/656) [#646](https://github.com/googlemaps/js-markerclusterer/issues/646) [#650](https://github.com/googlemaps/js-markerclusterer/issues/650) [#649](https://github.com/googlemaps/js-markerclusterer/issues/649) [#655](https://github.com/googlemaps/js-markerclusterer/issues/655) [#654](https://github.com/googlemaps/js-markerclusterer/issues/654) [#653](https://github.com/googlemaps/js-markerclusterer/issues/653) [#652](https://github.com/googlemaps/js-markerclusterer/issues/652) [#659](https://github.com/googlemaps/js-markerclusterer/issues/659) * **release:** 2.2.0-beta.2 [skip ci] ([3706d68](https://github.com/googlemaps/js-markerclusterer/commit/3706d6862ba4bbe5bd4f70604afa01eb615f8a8b)), closes [#656](https://github.com/googlemaps/js-markerclusterer/issues/656) [#646](https://github.com/googlemaps/js-markerclusterer/issues/646) [#650](https://github.com/googlemaps/js-markerclusterer/issues/650) [#649](https://github.com/googlemaps/js-markerclusterer/issues/649) [#655](https://github.com/googlemaps/js-markerclusterer/issues/655) [#654](https://github.com/googlemaps/js-markerclusterer/issues/654) [#653](https://github.com/googlemaps/js-markerclusterer/issues/653) [#652](https://github.com/googlemaps/js-markerclusterer/issues/652) [#659](https://github.com/googlemaps/js-markerclusterer/issues/659) * trigger beta release ([434cc68](https://github.com/googlemaps/js-markerclusterer/commit/434cc68b2b0d457041044f3580015239d3f5c104)) --------- Co-authored-by: semantic-release-bot Co-authored-by: Victor Berchet --- package-lock.json | 482 +++++------------------------------- package.json | 2 +- src/markerclusterer.test.ts | 113 ++++++++- src/markerclusterer.ts | 46 +++- 4 files changed, 213 insertions(+), 430 deletions(-) diff --git a/package-lock.json b/package-lock.json index bfdfd5df..efb70395 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@googlemaps/markerclusterer", - "version": "2.3.1", + "version": "2.3.2-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@googlemaps/markerclusterer", - "version": "2.3.1", + "version": "2.3.2-beta.1", "license": "Apache-2.0", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -3115,92 +3115,32 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.0.0.tgz", - "integrity": "sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.0", - "@typescript-eslint/scope-manager": "6.0.0", - "@typescript-eslint/type-utils": "6.0.0", - "@typescript-eslint/utils": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", + "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "semver": "^7.5.0", - "ts-api-utils": "^1.0.1" + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.0.0.tgz", - "integrity": "sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.0.0.tgz", - "integrity": "sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.0.0.tgz", - "integrity": "sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.0", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -3208,49 +3148,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.0.0.tgz", - "integrity": "sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.3.0", - "@types/json-schema": "^7.0.11", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "6.0.0", - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/typescript-estree": "6.0.0", - "eslint-scope": "^5.1.1", - "semver": "^7.5.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.0.0.tgz", - "integrity": "sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3264,9 +3161,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3285,83 +3182,25 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.0.0.tgz", - "integrity": "sha512-TNaufYSPrr1U8n+3xN+Yp9g31vQDJqhXzzPSHfQDLcaO4tU+mCfODPxCwf4H530zo7aUBE3QIdxCXamEnG04Tg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.0.0", - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/typescript-estree": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.0.0.tgz", - "integrity": "sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.0.0.tgz", - "integrity": "sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.0.0.tgz", - "integrity": "sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.0", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -3369,64 +3208,14 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.0.0.tgz", - "integrity": "sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.61.0.tgz", - "integrity": "sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/visitor-keys": "5.61.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3437,25 +3226,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.0.0.tgz", - "integrity": "sha512-ah6LJvLgkoZ/pyJ9GAdFkzeuMZ8goV6BH7eC9FPmojrnX9yNCIsfjB+zYcnex28YO3RFvBkV6rMV6WpIqkPvoQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.0.0", - "@typescript-eslint/utils": "6.0.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "tsutils": "^3.21.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "*" }, "peerDependenciesMeta": { "typescript": { @@ -3463,143 +3252,10 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.0.0.tgz", - "integrity": "sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.0.0.tgz", - "integrity": "sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.0.0.tgz", - "integrity": "sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/visitor-keys": "6.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.0", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.0.0.tgz", - "integrity": "sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.3.0", - "@types/json-schema": "^7.0.11", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "6.0.0", - "@typescript-eslint/types": "6.0.0", - "@typescript-eslint/typescript-estree": "6.0.0", - "eslint-scope": "^5.1.1", - "semver": "^7.5.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.0.0.tgz", - "integrity": "sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.0.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/types": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.61.0.tgz", - "integrity": "sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3610,13 +3266,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.61.0.tgz", - "integrity": "sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/visitor-keys": "5.61.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3649,9 +3305,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3670,17 +3326,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.61.0.tgz", - "integrity": "sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.61.0", - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/typescript-estree": "5.61.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -3729,12 +3385,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.61.0.tgz", - "integrity": "sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.61.0", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6242,12 +5898,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -11478,18 +11128,6 @@ "node": ">=8" } }, - "node_modules/ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/ts-jest": { "version": "26.5.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", diff --git a/package.json b/package.json index 8056c9a7..47b383fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@googlemaps/markerclusterer", - "version": "2.3.1", + "version": "2.3.2-beta.1", "description": "Creates and manages per-zoom-level clusters for large amounts of markers.", "keywords": [ "cluster", diff --git a/src/markerclusterer.test.ts b/src/markerclusterer.test.ts index 2f42491d..eac65d2f 100644 --- a/src/markerclusterer.test.ts +++ b/src/markerclusterer.test.ts @@ -40,14 +40,23 @@ describe.each(markerClasses)( const renderer = { render }; let map: google.maps.Map; + let rafSpy: jest.SpyInstance; beforeEach(() => { map = new google.maps.Map(document.createElement("div")); + // Runs the raf callback immediately. + rafSpy = jest + .spyOn(window, "requestAnimationFrame") + .mockImplementation((cb) => { + cb(performance.now()); + return 0; + }); }); afterEach(() => { calculate.mockClear(); render.mockClear(); + rafSpy.mockRestore(); }); test("markerClusterer does not render if no map", () => { @@ -81,7 +90,7 @@ describe.each(markerClasses)( markerClusterer.render(); expect(calculate).toBeCalledWith({ map, markers, mapCanvasProjection }); - expect(markerClusterer["reset"]).toHaveBeenCalledTimes(1); + expect(markerClusterer["reset"]).toHaveBeenCalledTimes(0); expect(markerClusterer["renderClusters"]).toHaveBeenCalledTimes(1); }); @@ -125,6 +134,86 @@ describe.each(markerClasses)( expect(deleteSpy).toHaveBeenCalledTimes(1); }); + test("markerClusterer render should not remove markers from the map if they were already rendered", () => { + const marker = new markerClass(); + const markers: Marker[] = [marker]; + + const algorithm = { + calculate: jest.fn().mockReturnValue({ + clusters: [new Cluster({ markers })], + changed: true, + }), + }; + const markerClusterer = new MarkerClusterer({ + markers, + algorithm, + }); + markerClusterer.getMap = jest.fn().mockImplementation(() => map); + markerClusterer.getProjection = jest + .fn() + .mockImplementation(() => jest.fn()); + markerClusterer["renderClusters"] = jest.fn(); + markerClusterer["clusters"] = [new Cluster({ markers })]; + + MarkerUtils.setMap = jest.fn().mockImplementation(() => null); + + markerClusterer["render"](); + + expect(MarkerUtils.setMap).toHaveBeenCalledTimes(0); + }); + + test("markerClusterer render should remove markers from the map if they are no more rendered", () => { + const marker = new markerClass(); + const markers: Marker[] = [marker]; + + const algorithm = { + calculate: jest.fn().mockReturnValue({ clusters: [], changed: true }), + }; + const markerClusterer = new MarkerClusterer({ + markers, + algorithm, + }); + markerClusterer.getMap = jest.fn().mockImplementation(() => map); + markerClusterer.getProjection = jest + .fn() + .mockImplementation(() => jest.fn()); + markerClusterer["renderClusters"] = jest.fn(); + const cluster = new Cluster({ markers }); + cluster.marker = marker; + markerClusterer["clusters"] = [cluster]; + + MarkerUtils.setMap = jest.fn().mockImplementation(() => null); + + markerClusterer["render"](); + + expect(MarkerUtils.setMap).toHaveBeenCalledWith(marker, null); + }); + + test("markerClusterer render should remove all group cluster markers from the map", () => { + const markers: Marker[] = [new markerClass(), new markerClass()]; + const algorithm = { + calculate: jest.fn().mockReturnValue({ clusters: [], changed: true }), + }; + const markerClusterer = new MarkerClusterer({ + markers, + algorithm, + }); + markerClusterer.getMap = jest.fn().mockImplementation(() => map); + markerClusterer.getProjection = jest + .fn() + .mockImplementation(() => jest.fn()); + markerClusterer["renderClusters"] = jest.fn(); + const cluster = new Cluster({ markers }); + cluster.marker = new markerClass(); + markerClusterer["clusters"] = [cluster]; + + MarkerUtils.setMap = jest.fn().mockImplementation(() => null); + + markerClusterer["render"](); + + expect(MarkerUtils.setMap).toHaveBeenCalledWith(cluster.marker, null); + }); + test("markerClusterer renderClusters bypasses renderer if just one", () => { const markers: Marker[] = [new markerClass()]; @@ -174,6 +263,28 @@ describe.each(markerClasses)( ); }); + test("markerClusterer renderClusters remove all individual markers from the map", () => { + const marker1 = new markerClass(); + const marker2 = new markerClass(); + const markers: Marker[] = [marker1, marker2]; + + const markerClusterer = new MarkerClusterer({ + markers, + renderer, + }); + + MarkerUtils.setMap = jest.fn(); + markerClusterer.getMap = jest.fn().mockImplementation(() => map); + + const clusters = [new Cluster({ markers })]; + + markerClusterer["clusters"] = clusters; + markerClusterer["renderClusters"](); + + expect(MarkerUtils.setMap).toBeCalledWith(marker1, null); + expect(MarkerUtils.setMap).toBeCalledWith(marker2, null); + }); + test("markerClusterer renderClusters does not set click handler", () => { const markers: Marker[] = [new markerClass()]; diff --git a/src/markerclusterer.ts b/src/markerclusterer.ts index c20a2f7b..6da5eb2e 100644 --- a/src/markerclusterer.ts +++ b/src/markerclusterer.ts @@ -178,14 +178,44 @@ export class MarkerClusterer extends OverlayViewSafe { mapCanvasProjection: this.getProjection(), }); - // allow algorithms to return flag on whether the clusters/markers have changed + // Allow algorithms to return flag on whether the clusters/markers have changed. if (changed || changed == undefined) { - // reset visibility of markers and clusters - this.reset(); - // store new clusters - this.clusters = clusters; + // Accumulate the markers of the clusters composed of a single marker. + // Those clusters directly use the marker. + // Clusters with more than one markers use a group marker generated by a renderer. + const singleMarker = new Set(); + for (const cluster of clusters) { + if (cluster.markers.length == 1) { + singleMarker.add(cluster.markers[0]); + } + } + + const groupMarkers: Marker[] = []; + // Iterate the clusters that are currently rendered. + for (const cluster of this.clusters) { + if (cluster.marker == null) { + continue; + } + if (cluster.markers.length == 1) { + if (!singleMarker.has(cluster.marker)) { + // The marker: + // - was previously rendered because it is from a cluster with 1 marker, + // - should no more be rendered as it is not in singleMarker. + MarkerUtils.setMap(cluster.marker, null); + } + } else { + // Delay the removal of old group markers to avoid flickering. + groupMarkers.push(cluster.marker); + } + } + this.clusters = clusters; this.renderClusters(); + + // Delayed removal of the markers of the former groups. + requestAnimationFrame(() => + groupMarkers.forEach((marker) => MarkerUtils.setMap(marker, null)) + ); } google.maps.event.trigger( this, @@ -215,14 +245,18 @@ export class MarkerClusterer extends OverlayViewSafe { } protected renderClusters(): void { - // generate stats to pass to renderers + // Generate stats to pass to renderers. const stats = new ClusterStats(this.markers, this.clusters); const map = this.getMap() as google.maps.Map; + this.clusters.forEach((cluster) => { if (cluster.markers.length === 1) { cluster.marker = cluster.markers[0]; } else { + // Generate the marker to represent the group. cluster.marker = this.renderer.render(cluster, stats, map); + // Make sure all individual markers are removed from the map. + cluster.markers.forEach((marker) => MarkerUtils.setMap(marker, null)); if (this.onClusterClick) { cluster.marker.addListener( "click",