geogrid 0.0.1

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/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "geogrid",
3
+ "version": "0.0.1",
4
+ "description": "xxx",
5
+ "main": "src/index.js",
6
+ "module": "src/index.js",
7
+ "jsdelivr": "dist/index.min.js",
8
+ "unpkg": "dist/index.min.js",
9
+ "exports": {
10
+ "umd": "./dist/index.min.js",
11
+ "default": "./src/index.js"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "rollup --config",
19
+ "prepare": "npm run build",
20
+ "docs": "jsdoc --configure jsdoc.json --verbose"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/neocarto/geogrid.git"
25
+ },
26
+ "keywords": [
27
+ "xxx",
28
+ "xxx",
29
+ "d3xxx"
30
+ ],
31
+ "author": "Nicolas Lambert",
32
+ "license": "MIT",
33
+ "bugs": {
34
+ "url": "https://github.com/neocarto/geogrid/issues"
35
+ },
36
+ "homepage": "https://github.com/neocarto/geogrid#readme",
37
+ "dependencies": {
38
+ "@turf/boolean-point-in-polygon": "^7.1.0",
39
+ "@turf/helpers": "^7.1.0",
40
+ "@turf/intersect": "^7.1.0",
41
+ "d3-array": "^3.2.4",
42
+ "d3-delaunay": "^6.0.4",
43
+ "d3-geo": "^3.1.1",
44
+ "docs": "^0.3.2-canary.0",
45
+ "documentation": "^14.0.3",
46
+ "geojson2h3": "^1.2.0",
47
+ "h3-js": "^4.1.0",
48
+ "rollup": "^4.10.0"
49
+ },
50
+ "devDependencies": {
51
+ "@jood/jsdoc-theme": "^0.1.14",
52
+ "@rollup/plugin-babel": "^6.0.4",
53
+ "@rollup/plugin-commonjs": "^25.0.7",
54
+ "@rollup/plugin-node-resolve": "^15.2.3",
55
+ "@rollup/plugin-terser": "^0.4.3",
56
+ "clean-jsdoc-theme": "^4.2.17",
57
+ "docdash": "^2.0.1",
58
+ "jsdoc": "^4.0.2",
59
+ "jsdoc-to-markdown": "^8.0.0",
60
+ "modern-jsdoc-template": "^1.0.0",
61
+ "postman-jsdoc-theme": "^0.0.3"
62
+ }
63
+ }
@@ -0,0 +1,50 @@
1
+ import { range } from "d3-array";
2
+ const d3 = Object.assign({}, { range });
3
+
4
+ /**
5
+ * @function make.diamond
6
+ * @description The `make.diamond()` function allows to create a diamond geoJSON grid in SVG coordinates.
7
+ * @property {number} [step = 50] - step of the grid
8
+ * @property {number} [width = 1000] - width of the grid
9
+ * @property {number} [height = 500] - height of the grid
10
+ */
11
+ export function diamond({ step = 50, width = 1000, height = 500 } = {}) {
12
+ let size = step * Math.sqrt(2);
13
+
14
+ // build grid
15
+ let x = d3.range(0, width + size, size);
16
+ let y = d3.range(0, height + size, size / 2).reverse();
17
+ let grid = x.map((x) => y.map((y, j) => [x, y, j % 2])).flat();
18
+ grid = grid.map((d) => {
19
+ return d[2] == 1 ? [d[0] + size / 2, d[1]] : [d[0], d[1]];
20
+ });
21
+
22
+ let s = size / 2;
23
+ // build object
24
+ let result = grid.map((d, i) => {
25
+ return {
26
+ type: "Feature",
27
+ geometry: {
28
+ type: "Polygon",
29
+ coordinates: [
30
+ [
31
+ [d[0] - s, d[1]],
32
+ [d[0], d[1] + s],
33
+ [d[0] + s, d[1]],
34
+ [d[0], d[1] - s],
35
+ [d[0] - s, d[1]],
36
+ ],
37
+ ],
38
+ },
39
+ properties: {
40
+ index: i,
41
+ },
42
+ };
43
+ });
44
+ return {
45
+ type: "FeatureCollection",
46
+ grid: "diamond",
47
+ geo: false,
48
+ features: result,
49
+ };
50
+ }
@@ -0,0 +1,36 @@
1
+ import { range } from "d3-array";
2
+ const d3 = Object.assign({}, { range });
3
+
4
+ /**
5
+ * @function make.dot
6
+ * @description The `make.dot()` function allows to create a geoJSON vith regular dots in SVG coordinates.
7
+ * @property {number} [step = 50] - step of the grid
8
+ * @property {number} [width = 1000] - width of the grid
9
+ * @property {number} [height = 500] - height of the grid
10
+ */
11
+ export function dot({ step = 30, width = 1000, height = 500 } = {}) {
12
+ // build grid
13
+ let y = d3.range(0 + step / 2, height, step).reverse();
14
+ let x = d3.range(0 + step / 2, width, step);
15
+ let grid = x.map((x) => y.map((y) => [x, y])).flat();
16
+ let s = step / 2;
17
+ // build object
18
+ let result = grid.map((d, i) => {
19
+ return {
20
+ type: "Feature",
21
+ geometry: {
22
+ type: "Point",
23
+ coordinates: d,
24
+ },
25
+ properties: {
26
+ index: i,
27
+ },
28
+ };
29
+ });
30
+ return {
31
+ type: "FeatureCollection",
32
+ grid: "dot",
33
+ geo: false,
34
+ features: result,
35
+ };
36
+ }
package/src/grid/h3.js ADDED
@@ -0,0 +1,48 @@
1
+ import {
2
+ getRes0Cells,
3
+ cellToChildren,
4
+ isPentagon,
5
+ cellToBoundary,
6
+ } from "h3-js";
7
+
8
+ import { featureToH3Set, h3SetToFeatureCollection } from "geojson2h3";
9
+ import { rewind as rrewind } from "../helpers/rewind";
10
+
11
+ /**
12
+ * @function make.h3
13
+ * @description The `make.h3()` function allows to create a hexbin geoJSON grid in geographical coordinates.
14
+ * @property {number} [level = 0] - level of the grid. Form 0 (large hexagons) to 4 (small hexagons). See: https://h3geo.org
15
+ * @property {object} [domain] - a geoJSON to define an extent
16
+ * @property {boolen} [rewind] - to rewind the output
17
+ */
18
+ export function h3({ level = 0, domain = undefined, rewind = undefined } = {}) {
19
+ let output;
20
+ if (domain) {
21
+ rewind = rewind !== undefined ? rewind : true;
22
+ const hexagons = featureToH3Set(domain, level);
23
+ output = h3SetToFeatureCollection(hexagons, (hex) => ({
24
+ value: hex,
25
+ }));
26
+ } else {
27
+ rewind = rewind !== undefined ? rewind : false;
28
+ output = {
29
+ type: "FeatureCollection",
30
+ grid: "h3",
31
+ level: level,
32
+ geo: true,
33
+ features: getRes0Cells()
34
+ .map((i) => cellToChildren(i, level))
35
+ .flat()
36
+ .map((d) => ({
37
+ type: "Feature",
38
+ properties: { id: d, pentagon: isPentagon(d) },
39
+ geometry: {
40
+ type: "Polygon",
41
+ coordinates: [cellToBoundary(d, true).reverse()],
42
+ },
43
+ })),
44
+ };
45
+ }
46
+
47
+ return rewind ? rrewind(output) : output;
48
+ }
@@ -0,0 +1,52 @@
1
+ import { range, max } from "d3-array";
2
+ const d3 = Object.assign({}, { range, max });
3
+
4
+ /**
5
+ * @function make.hexbin
6
+ * @description The `make.hexbin()` function allows to create a hexbin geoJSON grid in SVG coordinates.
7
+ * @property {number} [step = 50] - step of the grid
8
+ * @property {number} [width = 1000] - width of the grid
9
+ * @property {number} [height = 500] - height of the grid
10
+ */
11
+ export function hexbin({ step = 50, width = 1000, height = 500 } = {}) {
12
+ let w = step;
13
+ let size = w / Math.sqrt(3);
14
+ let h = 2 * size * (3 / 4);
15
+
16
+ // build grid
17
+ let y = d3.range(0, height + size, h).reverse();
18
+ if (y.length % 2) {
19
+ y.unshift(d3.max(y) + h);
20
+ }
21
+ let x = d3.range(0, width + size, w);
22
+ let grid = x.map((x) => y.map((y) => [x, y])).flat();
23
+ grid = grid.map((d, i) => {
24
+ return i % 2 == 1 ? [d[0] + w / 2, d[1]] : d;
25
+ });
26
+ let s = step / 2;
27
+ // build object
28
+ let result = grid.map((d, i) => {
29
+ let hex = [];
30
+ for (let i = 0; i < 6; i++) {
31
+ let ang = (Math.PI / 180) * (60 * i - 30);
32
+ hex.push([d[0] + size * Math.cos(ang), d[1] + size * Math.sin(ang)]);
33
+ }
34
+
35
+ return {
36
+ type: "Feature",
37
+ geometry: {
38
+ type: "Polygon",
39
+ coordinates: [[hex[0], hex[1], hex[2], hex[3], hex[4], hex[5], hex[0]]],
40
+ },
41
+ properties: {
42
+ index: i,
43
+ },
44
+ };
45
+ });
46
+ return {
47
+ type: "FeatureCollection",
48
+ grid: "hexbin",
49
+ geo: false,
50
+ features: result,
51
+ };
52
+ }
@@ -0,0 +1,44 @@
1
+ import { Delaunay } from "d3-delaunay";
2
+ const d3 = Object.assign({}, { Delaunay });
3
+
4
+ /**
5
+ * @function make.random
6
+ * @description The `make.random()` function allows to create an arbitrary geoJSON grid in SVG coordinates.
7
+ * @property {number} [step = 50] - step of the grid
8
+ * @property {number} [width = 1000] - width of the grid
9
+ * @property {number} [height = 500] - height of the grid
10
+ */
11
+
12
+ export function random({ step = 50, width = 1000, height = 500 } = {}) {
13
+ let grid = [];
14
+ let nb = Math.round((width / step) * (height / step));
15
+ for (let i = 0; i < nb; i++) {
16
+ grid.push([Math.random() * width, Math.random() * height]);
17
+ }
18
+
19
+ let voronoi = d3.Delaunay.from(
20
+ grid,
21
+ (d) => d[0],
22
+ (d) => d[1]
23
+ ).voronoi([0, 0, width, height]);
24
+
25
+ // build object
26
+ let result = grid.map((d, i) => {
27
+ return {
28
+ type: "Feature",
29
+ geometry: {
30
+ type: "Polygon",
31
+ coordinates: [voronoi.cellPolygon(i)],
32
+ },
33
+ properties: {
34
+ index: i,
35
+ },
36
+ };
37
+ });
38
+ return {
39
+ type: "FeatureCollection",
40
+ grid: "random",
41
+ geo: false,
42
+ features: result,
43
+ };
44
+ }
@@ -0,0 +1,45 @@
1
+ import { range } from "d3-array";
2
+ const d3 = Object.assign({}, { range });
3
+
4
+ /**
5
+ * @function make.square
6
+ * @description The `make.square()` function allows to create a square geoJSON grid in SVG coordinates.
7
+ * @property {number} [step = 50] - step of the grid
8
+ * @property {number} [width = 1000] - width of the grid
9
+ * @property {number} [height = 500] - height of the grid
10
+ */
11
+ export function square({ step = 50, width = 1000, height = 500 } = {}) {
12
+ // build grid
13
+ let y = d3.range(0 + step / 2, height, step).reverse();
14
+ let x = d3.range(0 + step / 2, width, step);
15
+ let grid = x.map((x) => y.map((y) => [x, y])).flat();
16
+
17
+ let s = step / 2;
18
+ // build object
19
+ let result = grid.map((d, i) => {
20
+ return {
21
+ type: "Feature",
22
+ geometry: {
23
+ type: "Polygon",
24
+ coordinates: [
25
+ [
26
+ [d[0] - s, d[1] + s],
27
+ [d[0] + s, d[1] + s],
28
+ [d[0] + s, d[1] - s],
29
+ [d[0] - s, d[1] - s],
30
+ [d[0] - s, d[1] + s],
31
+ ],
32
+ ],
33
+ },
34
+ properties: {
35
+ index: i,
36
+ },
37
+ };
38
+ });
39
+ return {
40
+ type: "FeatureCollection",
41
+ grid: "square",
42
+ geo: false,
43
+ features: result,
44
+ };
45
+ }
@@ -0,0 +1,66 @@
1
+ import { range, max } from "d3-array";
2
+ const d3 = Object.assign({}, { range, max });
3
+
4
+ /**
5
+ * @function make.triangle
6
+ * @description The `make.triangle()` function allows to create a triangle geoJSON grid in SVG coordinates.
7
+ * @property {number} [step = 50] - step of the grid
8
+ * @property {number} [width = 1000] - width of the grid
9
+ * @property {number} [height = 500] - height of the grid
10
+ */
11
+ export function triangle({ step = 50, width = 1000, height = 500 } = {}) {
12
+ let triangletop = (p, size) => {
13
+ let h = (Math.sqrt(3) / 2) * size;
14
+ let p1 = [p[0] + size / 2, p[1]];
15
+ let p2 = [p[0], p[1] - h];
16
+ let p3 = [p[0] - size / 2, p[1]];
17
+ return [p1, p2, p3, p1];
18
+ };
19
+
20
+ let trianglebottom = (p, size) => {
21
+ let h = (Math.sqrt(3) / 2) * size;
22
+ let p1 = [p[0] + size / 2, p[1]];
23
+ let p2 = [p[0], p[1] + h];
24
+ let p3 = [p[0] - size / 2, p[1]];
25
+ return [p1, p2, p3, p1];
26
+ };
27
+
28
+ let size = step / Math.sqrt(3);
29
+ let h = (Math.sqrt(3) / 2) * step;
30
+
31
+ // build grid
32
+
33
+ let y = d3.range(0, height + size, h).reverse();
34
+ if (y.length % 2) {
35
+ y.unshift(d3.max(y) + h);
36
+ }
37
+ let x = d3.range(0, width + size, step);
38
+ let grid = x.map((x, i) => y.map((y) => [x, y])).flat();
39
+ grid = grid.map((d, i) => {
40
+ return i % 2 == 1 ? [d[0] + step / 2, d[1]] : d;
41
+ });
42
+
43
+ let nb = grid.length;
44
+ grid = grid.concat(grid);
45
+
46
+ // build object
47
+ let result = grid.map((d, i) => {
48
+ return {
49
+ type: "Feature",
50
+ geometry: {
51
+ type: "Polygon",
52
+ coordinates:
53
+ i < nb ? [triangletop(d, step)] : [trianglebottom(d, step)],
54
+ },
55
+ properties: {
56
+ index: i,
57
+ },
58
+ };
59
+ });
60
+ return {
61
+ type: "FeatureCollection",
62
+ grid: "triangle",
63
+ geo: false,
64
+ features: result,
65
+ };
66
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @function tool/rewind
3
+ * @description The `tool.rewind` function allows to generate compliant Polygon and MultiPolygon geometries. Adapted from MapBox geojson-rewind code (https://github.com/mapbox/grojson-rewind) under ISC license
4
+ * @see {@link https://observablehq.com/@neocartocnrs/handle-geometries}
5
+ * @property {object} data - a GeoJSON FeatureCollection
6
+ * @property {boolean} [options.outer = false] - rewind Rings Outer
7
+ * @property {boolean} [options.mutate = false] - mutate the Input geoJSON
8
+ */
9
+
10
+ export function rewind(data, options = {}) {
11
+ data = JSON.parse(JSON.stringify(data));
12
+ let outer = options.outer === false ? false : true;
13
+ let mutate = options.mutate === false ? false : true;
14
+ let geo = mutate === true ? data : JSON.parse(JSON.stringify(x));
15
+ for (let i = 0; i < geo.features.length; i++) {
16
+ if (geo.features[i].geometry.type === "Polygon") {
17
+ rewindRings(geo.features[i].geometry.coordinates, outer);
18
+ } else if (geo.features[i].geometry.type === "MultiPolygon") {
19
+ for (let j = 0; j < geo.features[i].geometry.coordinates.length; j++) {
20
+ rewindRings(geo.features[i].geometry.coordinates[j], outer);
21
+ }
22
+ }
23
+ }
24
+ return geo;
25
+ }
26
+
27
+ function rewindRings(rings, outer) {
28
+ if (rings.length === 0) return;
29
+ rewindRing(rings[0], outer);
30
+ for (let i = 1; i < rings.length; i++) {
31
+ rewindRing(rings[i], !outer);
32
+ }
33
+ }
34
+
35
+ function rewindRing(ring, dir) {
36
+ let tArea = 0;
37
+ let err = 0;
38
+ for (let i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
39
+ const k = (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
40
+ const m = tArea + k;
41
+ err += Math.abs(tArea) >= Math.abs(k) ? tArea - m + k : k - m + tArea;
42
+ tArea = m;
43
+ }
44
+ if (tArea + err >= 0 !== !!dir) ring.reverse();
45
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * The code in this file rewinds GeoJSON polygons and multipolygons to fit d3's expectations.
3
+ * This is adapted by Matthieu Viry from a notebook of Philippe Rivière: https://observablehq.com/@fil/rewind
4
+ * which is licensed under the ISC license.
5
+ */
6
+
7
+ import d3 from './d3-custom';
8
+ import { GeoJSONFeature, GeoJSONFeatureCollection } from '../global';
9
+
10
+ const {
11
+ geoTransform,
12
+ geoStream,
13
+ geoContains,
14
+ geoArea,
15
+ } = d3;
16
+
17
+ function projectPolygons(o, stream) {
18
+ let coordinates = [];
19
+ let polygon; let
20
+ line;
21
+ geoStream(
22
+ o,
23
+ stream({
24
+ polygonStart() {
25
+ coordinates.push((polygon = []));
26
+ },
27
+ polygonEnd() {},
28
+ lineStart() {
29
+ polygon.push((line = []));
30
+ },
31
+ lineEnd() {
32
+ line.push(line[0].slice());
33
+ },
34
+ point(x, y) {
35
+ line.push([x, y]);
36
+ },
37
+ }),
38
+ );
39
+ if (o.type === 'Polygon') {
40
+ // eslint-disable-next-line prefer-destructuring
41
+ coordinates = coordinates[0];
42
+ }
43
+ return { ...o, coordinates, rewind: true };
44
+ }
45
+
46
+ function projectGeometry(o, stream) {
47
+ // eslint-disable-next-line no-nested-ternary
48
+ return !o
49
+ ? null
50
+ : o.type === 'GeometryCollection' // eslint-disable-line no-nested-ternary
51
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
52
+ ? projectGeometryCollection(o, stream)
53
+ : o.type === 'Polygon' || o.type === 'MultiPolygon'
54
+ ? projectPolygons(o, stream)
55
+ : o;
56
+ }
57
+
58
+ function projectFeature(o, stream) {
59
+ return { ...o, geometry: projectGeometry(o.geometry, stream) };
60
+ }
61
+
62
+ function projectFeatureCollection(o, stream) {
63
+ return { ...o, features: o.features.map((f) => projectFeature(f, stream)) };
64
+ }
65
+
66
+ function projectGeometryCollection(obj, stream) {
67
+ return {
68
+ ...obj,
69
+ geometries: obj.geometries.map((o) => projectGeometry(o, stream)),
70
+ };
71
+ }
72
+
73
+ const geoProjectSimple = function (object, projection) {
74
+ const { stream } = projection;
75
+ let project;
76
+ if (!stream) throw new Error('invalid projection');
77
+ switch (object && object.type) {
78
+ case 'Feature':
79
+ project = projectFeature;
80
+ break;
81
+ case 'FeatureCollection':
82
+ project = projectFeatureCollection;
83
+ break;
84
+ default:
85
+ project = projectGeometry;
86
+ break;
87
+ }
88
+ return project(object, stream);
89
+ };
90
+
91
+ function geoRewindStream(simple = true) {
92
+ let ring;
93
+ let polygon;
94
+ return geoTransform({
95
+ polygonStart() {
96
+ this.stream.polygonStart();
97
+ polygon = [];
98
+ },
99
+ lineStart() {
100
+ if (polygon) polygon.push((ring = []));
101
+ else this.stream.lineStart();
102
+ },
103
+ lineEnd() {
104
+ if (!polygon) this.stream.lineEnd();
105
+ },
106
+ point(x, y) {
107
+ if (polygon) ring.push([x, y]);
108
+ else this.stream.point(x, y);
109
+ },
110
+ polygonEnd() {
111
+ // eslint-disable-next-line no-restricted-syntax
112
+ for (const [i, rring] of polygon.entries()) {
113
+ rring.push(rring[0].slice());
114
+ if (
115
+ i // eslint-disable-line no-nested-ternary
116
+ // a hole must contain the first point of the polygon
117
+ ? !geoContains(
118
+ { type: 'Polygon', coordinates: [rring] },
119
+ polygon[0][0],
120
+ )
121
+ : polygon[1]
122
+ // the outer ring must contain the first point of its first hole (if any)
123
+ ? !geoContains(
124
+ { type: 'Polygon', coordinates: [rring] },
125
+ polygon[1][0],
126
+ // eslint-disable-next-line @typescript-eslint/no-loop-func
127
+ ) && !rring.some((p) => p[0] === polygon[1][0][0] && p[1] === polygon[1][0][1])
128
+ // a single ring polygon must be smaller than a hemisphere (optional)
129
+ : simple && geoArea({ type: 'Polygon', coordinates: [rring] }) > 2 * Math.PI
130
+ ) {
131
+ rring.reverse();
132
+ }
133
+
134
+ this.stream.lineStart();
135
+ rring.pop();
136
+ // eslint-disable-next-line no-restricted-syntax
137
+ for (const [x, y] of rring) this.stream.point(x, y);
138
+ this.stream.lineEnd();
139
+ }
140
+ this.stream.polygonEnd();
141
+ polygon = null;
142
+ },
143
+ });
144
+ }
145
+
146
+ const rewindFeature = (
147
+ feature: GeoJSONFeature,
148
+ simple: boolean,
149
+ ) => geoProjectSimple(feature, geoRewindStream(simple));
150
+
151
+ const rewindLayer = (
152
+ layer: GeoJSONFeatureCollection,
153
+ simple: boolean = true,
154
+ ): GeoJSONFeatureCollection => {
155
+ const features = layer.features.map((feature) => rewindFeature(feature, simple));
156
+ return { ...layer, features };
157
+ };
158
+
159
+ export default rewindLayer;
package/src/index.js ADDED
@@ -0,0 +1,21 @@
1
+ import { square } from "./grid/square.js";
2
+ import { triangle } from "./grid/triangle.js";
3
+ import { dot } from "./grid/dot.js";
4
+ import { random } from "./grid/random.js";
5
+ import { diamond } from "./grid/diamond.js";
6
+ import { hexbin } from "./grid/hexbin.js";
7
+ import { h3 } from "./grid/h3.js";
8
+
9
+ export let make = {
10
+ square,
11
+ triangle,
12
+ dot,
13
+ diamond,
14
+ random,
15
+ hexbin,
16
+ h3,
17
+ };
18
+
19
+ import { pointstogrid } from "./operator/pointstogrid.js";
20
+ import { polygonstogrid } from "./operator/polygonstogrid.js";
21
+ export let op = { pointstogrid, polygonstogrid };
@@ -0,0 +1,49 @@
1
+ import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
2
+
3
+ /**
4
+ * @function op.pointstogrid
5
+ * @description The `op.pointstogrid()` function allows to count dots in polygons (e.g. grid cells)
6
+ * @property {object} [points] - dots geoJSON
7
+ * @property {object} [grid] - grid
8
+ * @property {string} [var = undefined] - field (absolute quantitative data only)
9
+ */
10
+ export function pointstogrid(
11
+ opts = {
12
+ points: undefined,
13
+ grid: undefined,
14
+ var: undefined,
15
+ }
16
+ ) {
17
+ let polys = opts.grid.features;
18
+ let points = opts.dots.features;
19
+ let count = new Array(polys.length).fill(0);
20
+ let nb = points.length;
21
+ let test = new Array(nb).fill(true);
22
+ polys.forEach((p, i) => {
23
+ points.forEach((d, j) => {
24
+ if (test[j]) {
25
+ if (booleanPointInPolygon(d, p)) {
26
+ if (opts.var == undefined) {
27
+ count[i] = count[i] + 1;
28
+ } else {
29
+ count[i] = count[i] + parseFloat(d.properties[opts.var]);
30
+ }
31
+ test[j] = false;
32
+ }
33
+ }
34
+ });
35
+ });
36
+
37
+ // Rebuild grid
38
+ let output = polys
39
+ .map((d, i) => ({
40
+ type: d.type,
41
+ geometry: d.geometry,
42
+ properties: { ...d.properties, count: count[i] },
43
+ }))
44
+ .filter((d) => d.properties.count !== 0);
45
+
46
+ //const endTime = performance.now();
47
+ //const elapsedTime = endTime - startTime;
48
+ return { type: "FeatureCollection", features: output };
49
+ }