@mapgis/supercluster 7.1.0 → 16.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,105 +1,105 @@
1
- # supercluster [![Simply Awesome](https://img.shields.io/badge/simply-awesome-brightgreen.svg)](https://github.com/mourner/projects) [![Build Status](https://travis-ci.org/mapbox/supercluster.svg?branch=main)](https://travis-ci.org/mapbox/supercluster)
2
-
3
- A very fast JavaScript library for geospatial point clustering for browsers and Node.
4
-
5
- ```html
6
- <script src="https://unpkg.com/supercluster@6.0.2/dist/supercluster.min.js"></script>
7
- ```
8
-
9
- ```js
10
- const index = new Supercluster({
11
- radius: 40,
12
- maxZoom: 16
13
- });
14
- index.load(points);
15
- index.getClusters([-180, -85, 180, 85], 2);
16
- ```
17
-
18
- Clustering 6 million points in Leaflet:
19
-
20
- ![clusters2](https://cloud.githubusercontent.com/assets/25395/11857351/43407b46-a40c-11e5-8662-e99ab1cd2cb7.gif)
21
-
22
- ## Install
23
-
24
- Install using NPM (`npm install supercluster`) or Yarn (`yarn add supercluster`), then:
25
-
26
- ```js
27
- // import as a ES module
28
- import Supercluster from 'supercluster';
29
-
30
- // or require in Node / Browserify
31
- const Supercluster = require('supercluster');
32
- ```
33
-
34
- Or use a browser build directly:
35
-
36
- ```html
37
- <script src="https://unpkg.com/supercluster@6.0.2/dist/supercluster.min.js"></script>
38
- ```
39
-
40
- ## Methods
41
-
42
- #### `load(points)`
43
-
44
- Loads an array of [GeoJSON Feature](https://tools.ietf.org/html/rfc7946#section-3.2) objects. Each feature's `geometry` must be a [GeoJSON Point](https://tools.ietf.org/html/rfc7946#section-3.1.2). Once loaded, index is immutable.
45
-
46
- #### `getClusters(bbox, zoom)`
47
-
48
- For the given `bbox` array (`[westLng, southLat, eastLng, northLat]`) and integer `zoom`, returns an array of clusters and points as [GeoJSON Feature](https://tools.ietf.org/html/rfc7946#section-3.2) objects.
49
-
50
- #### `getTile(z, x, y)`
51
-
52
- For a given zoom and x/y coordinates, returns a [geojson-vt](https://github.com/mapbox/geojson-vt)-compatible JSON tile object with cluster/point features.
53
-
54
- #### `getChildren(clusterId)`
55
-
56
- Returns the children of a cluster (on the next zoom level) given its id (`cluster_id` value from feature properties).
57
-
58
- #### `getLeaves(clusterId, limit = 10, offset = 0)`
59
-
60
- Returns all the points of a cluster (given its `cluster_id`), with pagination support:
61
- `limit` is the number of points to return (set to `Infinity` for all points),
62
- and `offset` is the amount of points to skip (for pagination).
63
-
64
- #### `getClusterExpansionZoom(clusterId)`
65
-
66
- Returns the zoom on which the cluster expands into several children (useful for "click to zoom" feature) given the cluster's `cluster_id`.
67
-
68
- ## Options
69
-
70
- | Option | Default | Description |
71
- |------------|---------|-------------------------------------------------------------------|
72
- | minZoom | 0 | Minimum zoom level at which clusters are generated. |
73
- | maxZoom | 16 | Maximum zoom level at which clusters are generated. |
74
- | minPoints | 2 | Minimum number of points to form a cluster. |
75
- | radius | 40 | Cluster radius, in pixels. |
76
- | extent | 512 | (Tiles) Tile extent. Radius is calculated relative to this value. |
77
- | nodeSize | 64 | Size of the KD-tree leaf node. Affects performance. |
78
- | log | false | Whether timing info should be logged. |
79
- | generateId | false | Whether to generate ids for input features in vector tiles. |
80
-
81
- ### Property map/reduce options
82
-
83
- In addition to the options above, supercluster supports property aggregation with the following two options:
84
-
85
- - `map`: a function that returns cluster properties corresponding to a single point.
86
- - `reduce`: a reduce function that merges properties of two clusters into one.
87
-
88
- Example of setting up a `sum` cluster property that accumulates the sum of `myValue` property values:
89
-
90
- ```js
91
- const index = new Supercluster({
92
- map: (props) => ({sum: props.myValue}),
93
- reduce: (accumulated, props) => { accumulated.sum += props.sum; }
94
- });
95
- ```
96
-
97
- Note that `reduce` must not mutate the second argument (`props`).
98
-
99
- ## Developing Supercluster
100
-
101
- ```
102
- npm install # install dependencies
103
- npm run build # generate dist/supercluster.js and dist/supercluster.min.js
104
- npm test # run tests
105
- ```
1
+ # supercluster [![Simply Awesome](https://img.shields.io/badge/simply-awesome-brightgreen.svg)](https://github.com/mourner/projects) [![Build Status](https://travis-ci.org/mapbox/supercluster.svg?branch=main)](https://travis-ci.org/mapbox/supercluster)
2
+
3
+ A very fast JavaScript library for geospatial point clustering for browsers and Node.
4
+
5
+ ```html
6
+ <script src="https://unpkg.com/supercluster@6.0.2/dist/supercluster.min.js"></script>
7
+ ```
8
+
9
+ ```js
10
+ const index = new Supercluster({
11
+ radius: 40,
12
+ maxZoom: 16
13
+ });
14
+ index.load(points);
15
+ index.getClusters([-180, -85, 180, 85], 2);
16
+ ```
17
+
18
+ Clustering 6 million points in Leaflet:
19
+
20
+ ![clusters2](https://cloud.githubusercontent.com/assets/25395/11857351/43407b46-a40c-11e5-8662-e99ab1cd2cb7.gif)
21
+
22
+ ## Install
23
+
24
+ Install using NPM (`npm install supercluster`) or Yarn (`yarn add supercluster`), then:
25
+
26
+ ```js
27
+ // import as a ES module
28
+ import Supercluster from 'supercluster';
29
+
30
+ // or require in Node / Browserify
31
+ const Supercluster = require('supercluster');
32
+ ```
33
+
34
+ Or use a browser build directly:
35
+
36
+ ```html
37
+ <script src="https://unpkg.com/supercluster@6.0.2/dist/supercluster.min.js"></script>
38
+ ```
39
+
40
+ ## Methods
41
+
42
+ #### `load(points)`
43
+
44
+ Loads an array of [GeoJSON Feature](https://tools.ietf.org/html/rfc7946#section-3.2) objects. Each feature's `geometry` must be a [GeoJSON Point](https://tools.ietf.org/html/rfc7946#section-3.1.2). Once loaded, index is immutable.
45
+
46
+ #### `getClusters(bbox, zoom)`
47
+
48
+ For the given `bbox` array (`[westLng, southLat, eastLng, northLat]`) and integer `zoom`, returns an array of clusters and points as [GeoJSON Feature](https://tools.ietf.org/html/rfc7946#section-3.2) objects.
49
+
50
+ #### `getTile(z, x, y)`
51
+
52
+ For a given zoom and x/y coordinates, returns a [geojson-vt](https://github.com/mapbox/geojson-vt)-compatible JSON tile object with cluster/point features.
53
+
54
+ #### `getChildren(clusterId)`
55
+
56
+ Returns the children of a cluster (on the next zoom level) given its id (`cluster_id` value from feature properties).
57
+
58
+ #### `getLeaves(clusterId, limit = 10, offset = 0)`
59
+
60
+ Returns all the points of a cluster (given its `cluster_id`), with pagination support:
61
+ `limit` is the number of points to return (set to `Infinity` for all points),
62
+ and `offset` is the amount of points to skip (for pagination).
63
+
64
+ #### `getClusterExpansionZoom(clusterId)`
65
+
66
+ Returns the zoom on which the cluster expands into several children (useful for "click to zoom" feature) given the cluster's `cluster_id`.
67
+
68
+ ## Options
69
+
70
+ | Option | Default | Description |
71
+ |------------|---------|-------------------------------------------------------------------|
72
+ | minZoom | 0 | Minimum zoom level at which clusters are generated. |
73
+ | maxZoom | 16 | Maximum zoom level at which clusters are generated. |
74
+ | minPoints | 2 | Minimum number of points to form a cluster. |
75
+ | radius | 40 | Cluster radius, in pixels. |
76
+ | extent | 512 | (Tiles) Tile extent. Radius is calculated relative to this value. |
77
+ | nodeSize | 64 | Size of the KD-tree leaf node. Affects performance. |
78
+ | log | false | Whether timing info should be logged. |
79
+ | generateId | false | Whether to generate ids for input features in vector tiles. |
80
+
81
+ ### Property map/reduce options
82
+
83
+ In addition to the options above, supercluster supports property aggregation with the following two options:
84
+
85
+ - `map`: a function that returns cluster properties corresponding to a single point.
86
+ - `reduce`: a reduce function that merges properties of two clusters into one.
87
+
88
+ Example of setting up a `sum` cluster property that accumulates the sum of `myValue` property values:
89
+
90
+ ```js
91
+ const index = new Supercluster({
92
+ map: (props) => ({sum: props.myValue}),
93
+ reduce: (accumulated, props) => { accumulated.sum += props.sum; }
94
+ });
95
+ ```
96
+
97
+ Note that `reduce` must not mutate the second argument (`props`).
98
+
99
+ ## Developing Supercluster
100
+
101
+ ```
102
+ npm install # install dependencies
103
+ npm run build # generate dist/supercluster.js and dist/supercluster.min.js
104
+ npm test # run tests
105
+ ```
package/package.json CHANGED
@@ -1,54 +1,53 @@
1
- {
2
- "name": "@mapgis/supercluster",
3
- "version": "7.1.0",
4
- "description": "A very fast geospatial point clustering library.",
5
- "main": "dist/supercluster.js",
6
- "module": "index.js",
7
- "jsdelivr": "dist/supercluster.min.js",
8
- "unpkg": "dist/supercluster.min.js",
9
- "scripts": {
10
- "pretest": "eslint index.js bench.js test/test.js demo/index.js demo/worker.js",
11
- "test": "tape -r esm test/test.js",
12
- "cov": "c8 npm run test",
13
- "bench": "node --expose-gc -r esm bench.js",
14
- "build": "mkdir dist && rollup -c",
15
- "prepublishOnly": "npm run build"
16
- },
17
- "files": [
18
- "index.js",
19
- "dist/supercluster.js",
20
- "dist/supercluster.min.js"
21
- ],
22
- "repository": {
23
- "type": "git",
24
- "url": "git://github.com/mapbox/supercluster.git"
25
- },
26
- "keywords": [
27
- "clustering",
28
- "geospatial",
29
- "markers"
30
- ],
31
- "author": "Vladimir Agafonkin",
32
- "license": "ISC",
33
- "dependencies": {
34
- "kdbush": "^3.0.0"
35
- },
36
- "devDependencies": {
37
- "c8": "^7.1.2",
38
- "eslint": "^7.1.0",
39
- "eslint-config-mourner": "^3.0.0",
40
- "esm": "^3.2.25",
41
- "mkdirp": "^1.0.4",
42
- "rollup": "^2.12.0",
43
- "@rollup/plugin-buble": "^0.21.3",
44
- "@rollup/plugin-node-resolve": "^8.0.0",
45
- "rollup-plugin-terser": "^6.1.0",
46
- "tape": "^5.0.1"
47
- },
48
- "eslintConfig": {
49
- "extends": "mourner",
50
- "rules": {
51
- "camelcase": 0
52
- }
53
- }
54
- }
1
+ {
2
+ "name": "@mapgis/supercluster",
3
+ "version":"16.6.0",
4
+ "description": "A very fast geospatial point clustering library.",
5
+ "main": "dist/supercluster.js",
6
+ "module": "index.js",
7
+ "jsdelivr": "dist/supercluster.min.js",
8
+ "unpkg": "dist/supercluster.min.js",
9
+ "scripts": {
10
+ "pretest": "eslint index.js bench.js test/test.js demo/index.js demo/worker.js",
11
+ "test": "tape -r esm test/test.js",
12
+ "cov": "c8 npm run test",
13
+ "bench": "node --expose-gc -r esm bench.js",
14
+ "build": "mkdir dist && rollup -c"
15
+ },
16
+ "files": [
17
+ "index.js",
18
+ "dist/supercluster.js",
19
+ "dist/supercluster.min.js"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git://github.com/mapbox/supercluster.git"
24
+ },
25
+ "keywords": [
26
+ "clustering",
27
+ "geospatial",
28
+ "markers"
29
+ ],
30
+ "author": "Vladimir Agafonkin",
31
+ "license": "ISC",
32
+ "dependencies": {
33
+ "kdbush": "^3.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "c8": "^7.1.2",
37
+ "eslint": "^7.1.0",
38
+ "eslint-config-mourner": "^3.0.0",
39
+ "esm": "^3.2.25",
40
+ "mkdirp": "^1.0.4",
41
+ "rollup": "^2.12.0",
42
+ "@rollup/plugin-buble": "^0.21.3",
43
+ "@rollup/plugin-node-resolve": "^8.0.0",
44
+ "rollup-plugin-terser": "^6.1.0",
45
+ "tape": "^5.0.1"
46
+ },
47
+ "eslintConfig": {
48
+ "extends": "mourner",
49
+ "rules": {
50
+ "camelcase": 0
51
+ }
52
+ }
53
+ }
@@ -1,661 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define(factory) :
4
- (global = global || self, global.Supercluster = factory());
5
- }(this, (function () { 'use strict';
6
-
7
- function sortKD(ids, coords, nodeSize, left, right, depth) {
8
- if (right - left <= nodeSize) { return; }
9
-
10
- var m = (left + right) >> 1;
11
-
12
- select(ids, coords, m, left, right, depth % 2);
13
-
14
- sortKD(ids, coords, nodeSize, left, m - 1, depth + 1);
15
- sortKD(ids, coords, nodeSize, m + 1, right, depth + 1);
16
- }
17
-
18
- function select(ids, coords, k, left, right, inc) {
19
-
20
- while (right > left) {
21
- if (right - left > 600) {
22
- var n = right - left + 1;
23
- var m = k - left + 1;
24
- var z = Math.log(n);
25
- var s = 0.5 * Math.exp(2 * z / 3);
26
- var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
27
- var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
28
- var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
29
- select(ids, coords, k, newLeft, newRight, inc);
30
- }
31
-
32
- var t = coords[2 * k + inc];
33
- var i = left;
34
- var j = right;
35
-
36
- swapItem(ids, coords, left, k);
37
- if (coords[2 * right + inc] > t) { swapItem(ids, coords, left, right); }
38
-
39
- while (i < j) {
40
- swapItem(ids, coords, i, j);
41
- i++;
42
- j--;
43
- while (coords[2 * i + inc] < t) { i++; }
44
- while (coords[2 * j + inc] > t) { j--; }
45
- }
46
-
47
- if (coords[2 * left + inc] === t) { swapItem(ids, coords, left, j); }
48
- else {
49
- j++;
50
- swapItem(ids, coords, j, right);
51
- }
52
-
53
- if (j <= k) { left = j + 1; }
54
- if (k <= j) { right = j - 1; }
55
- }
56
- }
57
-
58
- function swapItem(ids, coords, i, j) {
59
- swap(ids, i, j);
60
- swap(coords, 2 * i, 2 * j);
61
- swap(coords, 2 * i + 1, 2 * j + 1);
62
- }
63
-
64
- function swap(arr, i, j) {
65
- var tmp = arr[i];
66
- arr[i] = arr[j];
67
- arr[j] = tmp;
68
- }
69
-
70
- function range(ids, coords, minX, minY, maxX, maxY, nodeSize) {
71
- var stack = [0, ids.length - 1, 0];
72
- var result = [];
73
- var x, y;
74
-
75
- while (stack.length) {
76
- var axis = stack.pop();
77
- var right = stack.pop();
78
- var left = stack.pop();
79
-
80
- if (right - left <= nodeSize) {
81
- for (var i = left; i <= right; i++) {
82
- x = coords[2 * i];
83
- y = coords[2 * i + 1];
84
- if (x >= minX && x <= maxX && y >= minY && y <= maxY) { result.push(ids[i]); }
85
- }
86
- continue;
87
- }
88
-
89
- var m = Math.floor((left + right) / 2);
90
-
91
- x = coords[2 * m];
92
- y = coords[2 * m + 1];
93
-
94
- if (x >= minX && x <= maxX && y >= minY && y <= maxY) { result.push(ids[m]); }
95
-
96
- var nextAxis = (axis + 1) % 2;
97
-
98
- if (axis === 0 ? minX <= x : minY <= y) {
99
- stack.push(left);
100
- stack.push(m - 1);
101
- stack.push(nextAxis);
102
- }
103
- if (axis === 0 ? maxX >= x : maxY >= y) {
104
- stack.push(m + 1);
105
- stack.push(right);
106
- stack.push(nextAxis);
107
- }
108
- }
109
-
110
- return result;
111
- }
112
-
113
- function within(ids, coords, qx, qy, r, nodeSize) {
114
- var stack = [0, ids.length - 1, 0];
115
- var result = [];
116
- var r2 = r * r;
117
-
118
- while (stack.length) {
119
- var axis = stack.pop();
120
- var right = stack.pop();
121
- var left = stack.pop();
122
-
123
- if (right - left <= nodeSize) {
124
- for (var i = left; i <= right; i++) {
125
- if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2) { result.push(ids[i]); }
126
- }
127
- continue;
128
- }
129
-
130
- var m = Math.floor((left + right) / 2);
131
-
132
- var x = coords[2 * m];
133
- var y = coords[2 * m + 1];
134
-
135
- if (sqDist(x, y, qx, qy) <= r2) { result.push(ids[m]); }
136
-
137
- var nextAxis = (axis + 1) % 2;
138
-
139
- if (axis === 0 ? qx - r <= x : qy - r <= y) {
140
- stack.push(left);
141
- stack.push(m - 1);
142
- stack.push(nextAxis);
143
- }
144
- if (axis === 0 ? qx + r >= x : qy + r >= y) {
145
- stack.push(m + 1);
146
- stack.push(right);
147
- stack.push(nextAxis);
148
- }
149
- }
150
-
151
- return result;
152
- }
153
-
154
- function sqDist(ax, ay, bx, by) {
155
- var dx = ax - bx;
156
- var dy = ay - by;
157
- return dx * dx + dy * dy;
158
- }
159
-
160
- var defaultGetX = function (p) { return p[0]; };
161
- var defaultGetY = function (p) { return p[1]; };
162
-
163
- var KDBush = function KDBush(points, getX, getY, nodeSize, ArrayType) {
164
- if ( getX === void 0 ) getX = defaultGetX;
165
- if ( getY === void 0 ) getY = defaultGetY;
166
- if ( nodeSize === void 0 ) nodeSize = 64;
167
- if ( ArrayType === void 0 ) ArrayType = Float64Array;
168
-
169
- this.nodeSize = nodeSize;
170
- this.points = points;
171
-
172
- var IndexArrayType = points.length < 65536 ? Uint16Array : Uint32Array;
173
-
174
- var ids = this.ids = new IndexArrayType(points.length);
175
- var coords = this.coords = new ArrayType(points.length * 2);
176
-
177
- for (var i = 0; i < points.length; i++) {
178
- ids[i] = i;
179
- coords[2 * i] = getX(points[i]);
180
- coords[2 * i + 1] = getY(points[i]);
181
- }
182
-
183
- sortKD(ids, coords, nodeSize, 0, ids.length - 1, 0);
184
- };
185
-
186
- KDBush.prototype.range = function range$1 (minX, minY, maxX, maxY) {
187
- return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize);
188
- };
189
-
190
- KDBush.prototype.within = function within$1 (x, y, r) {
191
- return within(this.ids, this.coords, x, y, r, this.nodeSize);
192
- };
193
-
194
- var defaultOptions = {
195
- crs: 'EPSG:3857', // 默认3857
196
- minZoom: 0, // min zoom to generate clusters on
197
- maxZoom: 16, // max zoom level to cluster the points on
198
- minPoints: 2, // minimum points to form a cluster
199
- radius: 40, // cluster radius in pixels
200
- extent: 512, // tile extent (radius is calculated relative to it)
201
- nodeSize: 64, // size of the KD-tree leaf node, affects performance
202
- log: false, // whether to log timing info
203
-
204
- // whether to generate numeric ids for input features (in vector tiles)
205
- generateId: false,
206
-
207
- // a reduce function for calculating custom cluster properties
208
- reduce: null, // (accumulated, props) => { accumulated.sum += props.sum; }
209
-
210
- // properties to use for individual points when running the reducer
211
- map: function (props) { return props; } // props => ({sum: props.my_value})
212
- };
213
-
214
- var Supercluster = function Supercluster(options) {
215
- this.options = extend(Object.create(defaultOptions), options);
216
- this.trees = new Array(this.options.maxZoom + 1);
217
- };
218
-
219
- Supercluster.prototype.load = function load (points) {
220
- var ref = this.options;
221
- var log = ref.log;
222
- var minZoom = ref.minZoom;
223
- var maxZoom = ref.maxZoom;
224
- var nodeSize = ref.nodeSize;
225
- var crs = ref.crs;
226
-
227
- if (log) { console.time('total time'); }
228
-
229
- var timerId = "prepare " + (points.length) + " points";
230
- if (log) { console.time(timerId); }
231
-
232
- this.points = points;
233
-
234
- // generate a cluster object for each point and index input points into a KD-tree
235
- var clusters = [];
236
- for (var i = 0; i < points.length; i++) {
237
- if (!points[i].geometry) { continue; }
238
- clusters.push(createPointCluster(points[i], i, crs));
239
- }
240
- this.trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
241
-
242
- if (log) { console.timeEnd(timerId); }
243
-
244
- // cluster points on max zoom, then cluster the results on previous zoom, etc.;
245
- // results in a cluster hierarchy across zoom levels
246
- for (var z = maxZoom; z >= minZoom; z--) {
247
- var now = +Date.now();
248
-
249
- // create a new set of clusters for the zoom and index them with a KD-tree
250
- clusters = this._cluster(clusters, z);
251
- this.trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
252
-
253
- if (log) { console.log('z%d: %d clusters in %dms', z, clusters.length, +Date.now() - now); }
254
- }
255
-
256
- if (log) { console.timeEnd('total time'); }
257
-
258
- return this;
259
- };
260
-
261
- Supercluster.prototype.getClusters = function getClusters (bbox, zoom) {
262
- var crs = this.crs;
263
- var minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
264
- var minLat = Math.max(-90, Math.min(90, bbox[1]));
265
- var maxLng = bbox[2] === 180 ? 180 : ((bbox[2] + 180) % 360 + 360) % 360 - 180;
266
- var maxLat = Math.max(-90, Math.min(90, bbox[3]));
267
-
268
- if (bbox[2] - bbox[0] >= 360) {
269
- minLng = -180;
270
- maxLng = 180;
271
- } else if (minLng > maxLng) {
272
- var easternHem = this.getClusters([minLng, minLat, 180, maxLat], zoom);
273
- var westernHem = this.getClusters([-180, minLat, maxLng, maxLat], zoom);
274
- return easternHem.concat(westernHem);
275
- }
276
-
277
- var tree = this.trees[this._limitZoom(zoom)];
278
- var ids = tree.range(lngX(minLng, crs), latY(maxLat, crs), lngX(maxLng, crs), latY(minLat, crs));
279
- var clusters = [];
280
- for (var i = 0, list = ids; i < list.length; i += 1) {
281
- var id = list[i];
282
-
283
- var c = tree.points[id];
284
- clusters.push(c.numPoints ? getClusterJSON(c, crs) : this.points[c.index]);
285
- }
286
- return clusters;
287
- };
288
-
289
- Supercluster.prototype.getChildren = function getChildren (clusterId) {
290
- var crs = this.crs;
291
- var originId = this._getOriginId(clusterId);
292
- var originZoom = this._getOriginZoom(clusterId);
293
- var errorMsg = 'No cluster with the specified id.';
294
-
295
- var index = this.trees[originZoom];
296
- if (!index) { throw new Error(errorMsg); }
297
-
298
- var origin = index.points[originId];
299
- if (!origin) { throw new Error(errorMsg); }
300
-
301
- var r = this.options.radius / (this.options.extent * Math.pow(2, originZoom - 1));
302
- var ids = index.within(origin.x, origin.y, r);
303
- var children = [];
304
- for (var i = 0, list = ids; i < list.length; i += 1) {
305
- var id = list[i];
306
-
307
- var c = index.points[id];
308
- if (c.parentId === clusterId) {
309
- children.push(c.numPoints ? getClusterJSON(c, crs) : this.points[c.index]);
310
- }
311
- }
312
-
313
- if (children.length === 0) { throw new Error(errorMsg); }
314
-
315
- return children;
316
- };
317
-
318
- Supercluster.prototype.getLeaves = function getLeaves (clusterId, limit, offset) {
319
- limit = limit || 10;
320
- offset = offset || 0;
321
-
322
- var leaves = [];
323
- this._appendLeaves(leaves, clusterId, limit, offset, 0);
324
-
325
- return leaves;
326
- };
327
-
328
- Supercluster.prototype.getTile = function getTile (z, x, y) {
329
- var tree = this.trees[this._limitZoom(z)];
330
- var z2 = Math.pow(2, z);
331
- var ref = this.options;
332
- var extent = ref.extent;
333
- var radius = ref.radius;
334
- var p = radius / extent;
335
- var top = (y - p) / z2;
336
- var bottom = (y + 1 + p) / z2;
337
-
338
- var tile = {
339
- features: []
340
- };
341
-
342
- this._addTileFeatures(
343
- tree.range((x - p) / z2, top, (x + 1 + p) / z2, bottom),
344
- tree.points, x, y, z2, tile);
345
-
346
- if (x === 0) {
347
- this._addTileFeatures(
348
- tree.range(1 - p / z2, top, 1, bottom),
349
- tree.points, z2, y, z2, tile);
350
- }
351
- if (x === z2 - 1) {
352
- this._addTileFeatures(
353
- tree.range(0, top, p / z2, bottom),
354
- tree.points, -1, y, z2, tile);
355
- }
356
-
357
- return tile.features.length ? tile : null;
358
- };
359
-
360
- Supercluster.prototype.getClusterExpansionZoom = function getClusterExpansionZoom (clusterId) {
361
- var expansionZoom = this._getOriginZoom(clusterId) - 1;
362
- while (expansionZoom <= this.options.maxZoom) {
363
- var children = this.getChildren(clusterId);
364
- expansionZoom++;
365
- if (children.length !== 1) { break; }
366
- clusterId = children[0].properties.cluster_id;
367
- }
368
- return expansionZoom;
369
- };
370
-
371
- Supercluster.prototype._appendLeaves = function _appendLeaves (result, clusterId, limit, offset, skipped) {
372
- var children = this.getChildren(clusterId);
373
-
374
- for (var i = 0, list = children; i < list.length; i += 1) {
375
- var child = list[i];
376
-
377
- var props = child.properties;
378
-
379
- if (props && props.cluster) {
380
- if (skipped + props.point_count <= offset) {
381
- // skip the whole cluster
382
- skipped += props.point_count;
383
- } else {
384
- // enter the cluster
385
- skipped = this._appendLeaves(result, props.cluster_id, limit, offset, skipped);
386
- // exit the cluster
387
- }
388
- } else if (skipped < offset) {
389
- // skip a single point
390
- skipped++;
391
- } else {
392
- // add a single point
393
- result.push(child);
394
- }
395
- if (result.length === limit) { break; }
396
- }
397
-
398
- return skipped;
399
- };
400
-
401
- Supercluster.prototype._addTileFeatures = function _addTileFeatures (ids, points, x, y, z2, tile) {
402
- for (var i$1 = 0, list = ids; i$1 < list.length; i$1 += 1) {
403
- var i = list[i$1];
404
-
405
- var c = points[i];
406
- var isCluster = c.numPoints;
407
- var f = {
408
- type: 1,
409
- geometry: [[
410
- Math.round(this.options.extent * (c.x * z2 - x)),
411
- Math.round(this.options.extent * (c.y * z2 - y))
412
- ]],
413
- tags: isCluster ? getClusterProperties(c) : this.points[c.index].properties
414
- };
415
-
416
- // assign id
417
- var id = (void 0);
418
- if (isCluster) {
419
- id = c.id;
420
- } else if (this.options.generateId) {
421
- // optionally generate id
422
- id = c.index;
423
- } else if (this.points[c.index].id) {
424
- // keep id if already assigned
425
- id = this.points[c.index].id;
426
- }
427
-
428
- if (id !== undefined) { f.id = id; }
429
-
430
- tile.features.push(f);
431
- }
432
- };
433
-
434
- Supercluster.prototype._limitZoom = function _limitZoom (z) {
435
- return Math.max(this.options.minZoom, Math.min(+z, this.options.maxZoom + 1));
436
- };
437
-
438
- Supercluster.prototype._cluster = function _cluster (points, zoom) {
439
- var clusters = [];
440
- var ref = this.options;
441
- var radius = ref.radius;
442
- var extent = ref.extent;
443
- var reduce = ref.reduce;
444
- var minPoints = ref.minPoints;
445
- var r = radius / (extent * Math.pow(2, zoom));
446
-
447
- // loop through each point
448
- for (var i = 0; i < points.length; i++) {
449
- var p = points[i];
450
- // if we've already visited the point at this zoom level, skip it
451
- if (p.zoom <= zoom) { continue; }
452
- p.zoom = zoom;
453
-
454
- // find all nearby points
455
- var tree = this.trees[zoom + 1];
456
- var neighborIds = tree.within(p.x, p.y, r);
457
-
458
- var numPointsOrigin = p.numPoints || 1;
459
- var numPoints = numPointsOrigin;
460
-
461
- // count the number of points in a potential cluster
462
- for (var i$1 = 0, list = neighborIds; i$1 < list.length; i$1 += 1) {
463
- var neighborId = list[i$1];
464
-
465
- var b = tree.points[neighborId];
466
- // filter out neighbors that are already processed
467
- if (b.zoom > zoom) { numPoints += b.numPoints || 1; }
468
- }
469
-
470
- if (numPoints >= minPoints) { // enough points to form a cluster
471
- var wx = p.x * numPointsOrigin;
472
- var wy = p.y * numPointsOrigin;
473
-
474
- var clusterProperties = reduce && numPointsOrigin > 1 ? this._map(p, true) : null;
475
-
476
- // encode both zoom and point index on which the cluster originated -- offset by total length of features
477
- var id = (i << 5) + (zoom + 1) + this.points.length;
478
-
479
- for (var i$2 = 0, list$1 = neighborIds; i$2 < list$1.length; i$2 += 1) {
480
- var neighborId$1 = list$1[i$2];
481
-
482
- var b$1 = tree.points[neighborId$1];
483
-
484
- if (b$1.zoom <= zoom) { continue; }
485
- b$1.zoom = zoom; // save the zoom (so it doesn't get processed twice)
486
-
487
- var numPoints2 = b$1.numPoints || 1;
488
- wx += b$1.x * numPoints2; // accumulate coordinates for calculating weighted center
489
- wy += b$1.y * numPoints2;
490
-
491
- b$1.parentId = id;
492
-
493
- if (reduce) {
494
- if (!clusterProperties) { clusterProperties = this._map(p, true); }
495
- reduce(clusterProperties, this._map(b$1));
496
- }
497
- }
498
-
499
- p.parentId = id;
500
- clusters.push(createCluster(wx / numPoints, wy / numPoints, id, numPoints, clusterProperties));
501
-
502
- } else { // left points as unclustered
503
- clusters.push(p);
504
-
505
- if (numPoints > 1) {
506
- for (var i$3 = 0, list$2 = neighborIds; i$3 < list$2.length; i$3 += 1) {
507
- var neighborId$2 = list$2[i$3];
508
-
509
- var b$2 = tree.points[neighborId$2];
510
- if (b$2.zoom <= zoom) { continue; }
511
- b$2.zoom = zoom;
512
- clusters.push(b$2);
513
- }
514
- }
515
- }
516
- }
517
-
518
- return clusters;
519
- };
520
-
521
- // get index of the point from which the cluster originated
522
- Supercluster.prototype._getOriginId = function _getOriginId (clusterId) {
523
- return (clusterId - this.points.length) >> 5;
524
- };
525
-
526
- // get zoom of the point from which the cluster originated
527
- Supercluster.prototype._getOriginZoom = function _getOriginZoom (clusterId) {
528
- return (clusterId - this.points.length) % 32;
529
- };
530
-
531
- Supercluster.prototype._map = function _map (point, clone) {
532
- if (point.numPoints) {
533
- return clone ? extend({}, point.properties) : point.properties;
534
- }
535
- var original = this.points[point.index].properties;
536
- var result = this.options.map(original);
537
- return clone && result === original ? extend({}, result) : result;
538
- };
539
-
540
- function createCluster(x, y, id, numPoints, properties) {
541
- return {
542
- x: x, // weighted cluster center
543
- y: y,
544
- zoom: Infinity, // the last zoom the cluster was processed at
545
- id: id, // encodes index of the first child of the cluster and its zoom level
546
- parentId: -1, // parent cluster id
547
- numPoints: numPoints,
548
- properties: properties
549
- };
550
- }
551
-
552
- function createPointCluster(p, id, crs) {
553
- var ref = p.geometry.coordinates;
554
- var x = ref[0];
555
- var y = ref[1];
556
- return {
557
- x: lngX(x, crs), // projected point coordinates
558
- y: latY(y, crs),
559
- zoom: Infinity, // the last zoom the point was processed at
560
- index: id, // index of the source feature in the original input array,
561
- parentId: -1 // parent cluster id
562
- };
563
- }
564
-
565
- function getClusterJSON(cluster, crs) {
566
- return {
567
- type: 'Feature',
568
- id: cluster.id,
569
- properties: getClusterProperties(cluster),
570
- geometry: {
571
- type: 'Point',
572
- coordinates: [xLng(cluster.x, crs), yLat(cluster.y, crs)]
573
- }
574
- };
575
- }
576
-
577
- function getClusterProperties(cluster) {
578
- var count = cluster.numPoints;
579
- var abbrev =
580
- count >= 10000 ? ((Math.round(count / 1000)) + "k") :
581
- count >= 1000 ? ((Math.round(count / 100) / 10) + "k") : count;
582
- return extend(extend({}, cluster.properties), {
583
- cluster: true,
584
- cluster_id: cluster.id,
585
- point_count: count,
586
- point_count_abbreviated: abbrev
587
- });
588
- }
589
-
590
- /**
591
- * 针对X方向投影
592
- * @param {*} lng
593
- * @param {*} crs
594
- * @returns 返回投影后的坐标,注意这里的坐标不是平面坐标值,而是矩阵值,即 [0 ~ 1]之间
595
- */
596
- function lngX(lng, crs) {
597
- var transformX;
598
- if (!crs || crs === 'EPSG:3857') {
599
- transformX = lng / 360 + 0.5;
600
- } else {
601
- transformX = lng / 360 + 0.5;
602
- }
603
- return transformX;
604
- }
605
-
606
- /**
607
- * 针对y方向投影
608
- * @param {*} lat
609
- * @param {*} crs
610
- * @returns 返回投影后的坐标,注意这里的坐标不是平面坐标值,而是矩阵值,即 [0 ~ 1]之间
611
- */
612
- function latY(lat, crs) {
613
- var transformY;
614
- if (!crs || crs === 'EPSG:3857') {
615
- var sin = Math.sin(lat * Math.PI / 180);
616
- transformY = 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
617
- } else {
618
- transformY = (90 - lat) / 360;
619
- }
620
- return transformY < 0 ? 0 : transformY > 1 ? 1 : transformY;
621
- /* const sin = Math.sin(lat * Math.PI / 180);
622
- const y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
623
- return y < 0 ? 0 : y > 1 ? 1 : y; */
624
- }
625
-
626
- // spherical mercator to longitude/latitude
627
- function xLng(x, crs) {
628
- if (!crs || crs === 'EPSG:3857') {
629
- return (x - 0.5) * 360;
630
- } else {
631
- return (x - 0.5) * 360;
632
- }
633
- // return (x - 0.5) * 360;
634
- }
635
- function yLat(y, crs) {
636
- if (!crs || crs === 'EPSG:3857') {
637
- var y2 = (180 - y * 360) * Math.PI / 180;
638
- return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
639
- } else {
640
- return 90 - (y * 360);
641
- }
642
-
643
- // const y2 = (180 - y * 360) * Math.PI / 180;
644
- // return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
645
- }
646
-
647
- function extend(dest, src) {
648
- for (var id in src) { dest[id] = src[id]; }
649
- return dest;
650
- }
651
-
652
- function getX(p) {
653
- return p.x;
654
- }
655
- function getY(p) {
656
- return p.y;
657
- }
658
-
659
- return Supercluster;
660
-
661
- })));
@@ -1 +0,0 @@
1
- !function(t,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define(o):(t=t||self).Supercluster=o()}(this,(function(){"use strict";function t(e,n,r,i,s,a){if(!(s-i<=r)){var p=i+s>>1;!function t(e,n,r,i,s,a){for(;s>i;){if(s-i>600){var p=s-i+1,h=r-i+1,u=Math.log(p),f=.5*Math.exp(2*u/3),d=.5*Math.sqrt(u*f*(p-f)/p)*(h-p/2<0?-1:1),l=Math.max(i,Math.floor(r-h*f/p+d)),c=Math.min(s,Math.floor(r+(p-h)*f/p+d));t(e,n,r,l,c,a)}var m=n[2*r+a],v=i,g=s;for(o(e,n,i,r),n[2*s+a]>m&&o(e,n,i,s);v<g;){for(o(e,n,v,g),v++,g--;n[2*v+a]<m;)v++;for(;n[2*g+a]>m;)g--}n[2*i+a]===m?o(e,n,i,g):(g++,o(e,n,g,s)),g<=r&&(i=g+1),r<=g&&(s=g-1)}}(e,n,p,i,s,a%2),t(e,n,r,i,p-1,a+1),t(e,n,r,p+1,s,a+1)}}function o(t,o,n,r){e(t,n,r),e(o,2*n,2*r),e(o,2*n+1,2*r+1)}function e(t,o,e){var n=t[o];t[o]=t[e],t[e]=n}function n(t,o,e,n){var r=t-e,i=o-n;return r*r+i*i}var r=function(t){return t[0]},i=function(t){return t[1]},s=function(o,e,n,s,a){void 0===e&&(e=r),void 0===n&&(n=i),void 0===s&&(s=64),void 0===a&&(a=Float64Array),this.nodeSize=s,this.points=o;for(var p=o.length<65536?Uint16Array:Uint32Array,h=this.ids=new p(o.length),u=this.coords=new a(2*o.length),f=0;f<o.length;f++)h[f]=f,u[2*f]=e(o[f]),u[2*f+1]=n(o[f]);t(h,u,s,0,h.length-1,0)};s.prototype.range=function(t,o,e,n){return function(t,o,e,n,r,i,s){for(var a,p,h=[0,t.length-1,0],u=[];h.length;){var f=h.pop(),d=h.pop(),l=h.pop();if(d-l<=s)for(var c=l;c<=d;c++)a=o[2*c],p=o[2*c+1],a>=e&&a<=r&&p>=n&&p<=i&&u.push(t[c]);else{var m=Math.floor((l+d)/2);a=o[2*m],p=o[2*m+1],a>=e&&a<=r&&p>=n&&p<=i&&u.push(t[m]);var v=(f+1)%2;(0===f?e<=a:n<=p)&&(h.push(l),h.push(m-1),h.push(v)),(0===f?r>=a:i>=p)&&(h.push(m+1),h.push(d),h.push(v))}}return u}(this.ids,this.coords,t,o,e,n,this.nodeSize)},s.prototype.within=function(t,o,e){return function(t,o,e,r,i,s){for(var a=[0,t.length-1,0],p=[],h=i*i;a.length;){var u=a.pop(),f=a.pop(),d=a.pop();if(f-d<=s)for(var l=d;l<=f;l++)n(o[2*l],o[2*l+1],e,r)<=h&&p.push(t[l]);else{var c=Math.floor((d+f)/2),m=o[2*c],v=o[2*c+1];n(m,v,e,r)<=h&&p.push(t[c]);var g=(u+1)%2;(0===u?e-i<=m:r-i<=v)&&(a.push(d),a.push(c-1),a.push(g)),(0===u?e+i>=m:r+i>=v)&&(a.push(c+1),a.push(f),a.push(g))}}return p}(this.ids,this.coords,t,o,e,this.nodeSize)};var a={crs:"EPSG:3857",minZoom:0,maxZoom:16,minPoints:2,radius:40,extent:512,nodeSize:64,log:!1,generateId:!1,reduce:null,map:function(t){return t}},p=function(t){this.options=g(Object.create(a),t),this.trees=new Array(this.options.maxZoom+1)};function h(t,o,e,n,r){return{x:t,y:o,zoom:1/0,id:e,parentId:-1,numPoints:n,properties:r}}function u(t,o,e){var n=t.geometry.coordinates,r=n[0],i=n[1];return{x:l(r,e),y:c(i,e),zoom:1/0,index:o,parentId:-1}}function f(t,o){return{type:"Feature",id:t.id,properties:d(t),geometry:{type:"Point",coordinates:[m(t.x,o),v(t.y,o)]}}}function d(t){var o=t.numPoints,e=o>=1e4?Math.round(o/1e3)+"k":o>=1e3?Math.round(o/100)/10+"k":o;return g(g({},t.properties),{cluster:!0,cluster_id:t.id,point_count:o,point_count_abbreviated:e})}function l(t,o){return t/360+.5}function c(t,o){var e;if(o&&"EPSG:3857"!==o)e=(90-t)/360;else{var n=Math.sin(t*Math.PI/180);e=.5-.25*Math.log((1+n)/(1-n))/Math.PI}return e<0?0:e>1?1:e}function m(t,o){return 360*(t-.5)}function v(t,o){if(o&&"EPSG:3857"!==o)return 90-360*t;var e=(180-360*t)*Math.PI/180;return 360*Math.atan(Math.exp(e))/Math.PI-90}function g(t,o){for(var e in o)t[e]=o[e];return t}function y(t){return t.x}function x(t){return t.y}return p.prototype.load=function(t){var o=this.options,e=o.log,n=o.minZoom,r=o.maxZoom,i=o.nodeSize,a=o.crs;e&&console.time("total time");var p="prepare "+t.length+" points";e&&console.time(p),this.points=t;for(var h=[],f=0;f<t.length;f++)t[f].geometry&&h.push(u(t[f],f,a));this.trees[r+1]=new s(h,y,x,i,Float32Array),e&&console.timeEnd(p);for(var d=r;d>=n;d--){var l=+Date.now();h=this._cluster(h,d),this.trees[d]=new s(h,y,x,i,Float32Array),e&&console.log("z%d: %d clusters in %dms",d,h.length,+Date.now()-l)}return e&&console.timeEnd("total time"),this},p.prototype.getClusters=function(t,o){var e=this.crs,n=((t[0]+180)%360+360)%360-180,r=Math.max(-90,Math.min(90,t[1])),i=180===t[2]?180:((t[2]+180)%360+360)%360-180,s=Math.max(-90,Math.min(90,t[3]));if(t[2]-t[0]>=360)n=-180,i=180;else if(n>i){var a=this.getClusters([n,r,180,s],o),p=this.getClusters([-180,r,i,s],o);return a.concat(p)}for(var h=this.trees[this._limitZoom(o)],u=[],d=0,m=h.range(l(n,e),c(s,e),l(i,e),c(r,e));d<m.length;d+=1){var v=m[d],g=h.points[v];u.push(g.numPoints?f(g,e):this.points[g.index])}return u},p.prototype.getChildren=function(t){var o=this.crs,e=this._getOriginId(t),n=this._getOriginZoom(t),r="No cluster with the specified id.",i=this.trees[n];if(!i)throw new Error(r);var s=i.points[e];if(!s)throw new Error(r);for(var a=this.options.radius/(this.options.extent*Math.pow(2,n-1)),p=[],h=0,u=i.within(s.x,s.y,a);h<u.length;h+=1){var d=u[h],l=i.points[d];l.parentId===t&&p.push(l.numPoints?f(l,o):this.points[l.index])}if(0===p.length)throw new Error(r);return p},p.prototype.getLeaves=function(t,o,e){o=o||10,e=e||0;var n=[];return this._appendLeaves(n,t,o,e,0),n},p.prototype.getTile=function(t,o,e){var n=this.trees[this._limitZoom(t)],r=Math.pow(2,t),i=this.options,s=i.extent,a=i.radius/s,p=(e-a)/r,h=(e+1+a)/r,u={features:[]};return this._addTileFeatures(n.range((o-a)/r,p,(o+1+a)/r,h),n.points,o,e,r,u),0===o&&this._addTileFeatures(n.range(1-a/r,p,1,h),n.points,r,e,r,u),o===r-1&&this._addTileFeatures(n.range(0,p,a/r,h),n.points,-1,e,r,u),u.features.length?u:null},p.prototype.getClusterExpansionZoom=function(t){for(var o=this._getOriginZoom(t)-1;o<=this.options.maxZoom;){var e=this.getChildren(t);if(o++,1!==e.length)break;t=e[0].properties.cluster_id}return o},p.prototype._appendLeaves=function(t,o,e,n,r){for(var i=0,s=this.getChildren(o);i<s.length;i+=1){var a=s[i],p=a.properties;if(p&&p.cluster?r+p.point_count<=n?r+=p.point_count:r=this._appendLeaves(t,p.cluster_id,e,n,r):r<n?r++:t.push(a),t.length===e)break}return r},p.prototype._addTileFeatures=function(t,o,e,n,r,i){for(var s=0,a=t;s<a.length;s+=1){var p=o[a[s]],h=p.numPoints,u={type:1,geometry:[[Math.round(this.options.extent*(p.x*r-e)),Math.round(this.options.extent*(p.y*r-n))]],tags:h?d(p):this.points[p.index].properties},f=void 0;h?f=p.id:this.options.generateId?f=p.index:this.points[p.index].id&&(f=this.points[p.index].id),void 0!==f&&(u.id=f),i.features.push(u)}},p.prototype._limitZoom=function(t){return Math.max(this.options.minZoom,Math.min(+t,this.options.maxZoom+1))},p.prototype._cluster=function(t,o){for(var e=[],n=this.options,r=n.radius,i=n.extent,s=n.reduce,a=n.minPoints,p=r/(i*Math.pow(2,o)),u=0;u<t.length;u++){var f=t[u];if(!(f.zoom<=o)){f.zoom=o;for(var d=this.trees[o+1],l=d.within(f.x,f.y,p),c=f.numPoints||1,m=c,v=0,g=l;v<g.length;v+=1){var y=g[v],x=d.points[y];x.zoom>o&&(m+=x.numPoints||1)}if(m>=a){for(var M=f.x*c,_=f.y*c,w=s&&c>1?this._map(f,!0):null,P=(u<<5)+(o+1)+this.points.length,z=0,Z=l;z<Z.length;z+=1){var I=Z[z],E=d.points[I];if(!(E.zoom<=o)){E.zoom=o;var S=E.numPoints||1;M+=E.x*S,_+=E.y*S,E.parentId=P,s&&(w||(w=this._map(f,!0)),s(w,this._map(E)))}}f.parentId=P,e.push(h(M/m,_/m,P,m,w))}else if(e.push(f),m>1)for(var F=0,C=l;F<C.length;F+=1){var b=C[F],A=d.points[b];A.zoom<=o||(A.zoom=o,e.push(A))}}}return e},p.prototype._getOriginId=function(t){return t-this.points.length>>5},p.prototype._getOriginZoom=function(t){return(t-this.points.length)%32},p.prototype._map=function(t,o){if(t.numPoints)return o?g({},t.properties):t.properties;var e=this.points[t.index].properties,n=this.options.map(e);return o&&n===e?g({},n):n},p}));