From 196cb08dd9044d87255adcfe2da64f44cdada6bc Mon Sep 17 00:00:00 2001 From: "Braden M. Kelley" Date: Sun, 22 Jul 2018 20:09:27 -0700 Subject: [PATCH 1/2] add cluster mapreduce feature to style spec --- src/source/geojson_source.js | 1 + src/source/geojson_worker_source.js | 74 +++++++++++++++++- src/style-spec/reference/v8.json | 23 ++++++ .../geojson/clustered/expected.png | Bin 25176 -> 26512 bytes .../render-tests/geojson/clustered/style.json | 36 ++++++++- 5 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/source/geojson_source.js b/src/source/geojson_source.js index a63e5fcac4f..968ed0d4023 100644 --- a/src/source/geojson_source.js +++ b/src/source/geojson_source.js @@ -134,6 +134,7 @@ class GeoJSONSource extends Evented implements Source { (this.maxzoom - 1), extent: EXTENT, radius: (options.clusterRadius || 50) * scale, + mapreduce: options.clusterMapReduce, log: false } }, options.workerOptions); diff --git a/src/source/geojson_worker_source.js b/src/source/geojson_worker_source.js index 97117b40530..cfefc8e64d7 100644 --- a/src/source/geojson_worker_source.js +++ b/src/source/geojson_worker_source.js @@ -3,6 +3,8 @@ import { getJSON } from '../util/ajax'; import performance from '../util/performance'; +import styleSpec from '../style-spec/reference/latest'; +import extend from '../style-spec/util/extend'; import rewind from 'geojson-rewind'; import GeoJSONWrapper from './geojson_wrapper'; import vtpbf from 'vt-pbf'; @@ -10,6 +12,7 @@ import supercluster from 'supercluster'; import geojsonvt from 'geojson-vt'; import assert from 'assert'; import VectorTileWorkerSource from './vector_tile_worker_source'; +import { createExpression, createPropertyExpression } from '../style-spec/expression'; import type { WorkerTileParameters, @@ -23,6 +26,8 @@ import type {LoadVectorDataCallback} from './vector_tile_worker_source'; import type {RequestParameters} from '../util/ajax'; import type { Callback } from '../types/callback'; +type ExpressionFunction = typeof createExpression | typeof createPropertyExpression; + export type LoadGeoJSONParameters = { request?: RequestParameters, data?: string, @@ -170,7 +175,7 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource { try { this._geoJSONIndex = params.cluster ? - supercluster(params.superclusterOptions).load(data.features) : + supercluster(this._getSuperclusterOptions(params)).load(data.features) : geojsonvt(data, params.geojsonVtOptions); } catch (err) { return callback(err); @@ -193,6 +198,73 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource { }); } + + _getExpressions(values: any, expressionFunction: ExpressionFunction, spec: any) { + const expressions = {}; + + Object.keys(values).forEach(key => { + const expression = expressionFunction(values[key], spec[key] || spec['*']); + if (expression.result === 'success') { + expressions[key] = expression.value; + } else { + const messages = expression.value.map(({ message }) => message).join(', '); + const value = JSON.stringify(values[key]); + + console.log(`Error evaluating property "${key}" with value (${value}): ${messages}`); + } + }); + + return expressions; + } + + _getSuperclusterOptions(params: LoadGeoJSONParameters) { + const options = extend({}, params.superclusterOptions); + const { mapreduce } = options; + + if (mapreduce) { + delete options.mapreduce; + const { initial, map, reduce } = mapreduce; + const globals = {}; + const spec = styleSpec.source_geojson.clusterMapReduce; + + if (initial) { + const expressions = this._getExpressions(initial, createExpression, spec.initial); + + options.initial = () => Object.keys(expressions).reduce( + (_, key) => extend(_, ({ [key]: expressions[key].evaluate(globals) })), + {} + ); + } + + if (map) { + const expressions = this._getExpressions(map, createPropertyExpression, spec.map); + + options.map = (properties) => Object.keys(expressions).reduce( + (_, key) => extend(_, ({ [key]: expressions[key].evaluate(globals, { properties }) })), + {} + ); + } + + if (reduce) { + const expressions = this._getExpressions(reduce, createPropertyExpression, spec.reduce); + + options.reduce = (cluster, point) => { + const properties = { cluster, point }; + const newValues = Object.keys(expressions).reduce( + (_, key) => extend(_, ({ [key]: expressions[key].evaluate(globals, { properties }) })), + {} + ); + + Object.keys(newValues).forEach(key => { + cluster[key] = newValues[key]; + }); + }; + } + } + + return options; + } + /** * While processing `loadData`, we coalesce all further * `loadData` messages into a single call to _loadData diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index 31073ac0e26..2fc221a13f8 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -373,6 +373,29 @@ "type": "number", "doc": "Max zoom on which to cluster points if clustering is enabled. Defaults to one zoom less than maxzoom (so that last zoom features are not clustered)." }, + "clusterMapReduce": { + "initial": { + "*": { + "type": "*", + "property-type": "data-constant" + }, + "doc": "Initial properties of a cluster (before runnning the reducer)." + }, + "map": { + "*": { + "type": "*", + "property-type": "data-driven" + }, + "doc": "Properties to use for individual points when running the reducer. Point properties can be accessed directly." + }, + "reduce": { + "*": { + "type": "*", + "property-type": "data-driven" + }, + "doc": "Properties to add to the cluster. The cluster properties can be accessed from the `cluster` property (e.g. `cluster.total`, and the properties mapped in `map` can be accessed from `point` (e.g. `point.total`)." + } + }, "lineMetrics": { "type": "boolean", "default": false, diff --git a/test/integration/render-tests/geojson/clustered/expected.png b/test/integration/render-tests/geojson/clustered/expected.png index 56a2639ad58639c4bfdb33a4b1988b4d098bc100..8c89a7334314cff74d1f235e7cd3db9b433cc611 100644 GIT binary patch literal 26512 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 ZGejq!0$tQw;2$GyX@c}rYnAPz{~u{00AT Date: Sun, 22 Jul 2018 21:31:58 -0700 Subject: [PATCH 2/2] fix flow tests --- build/generate-flow-typed-style-spec.js | 2 + flow-typed/style-spec.js | 8 +++ src/source/geojson_worker_source.js | 2 +- src/style-spec/reference/v8.json | 65 +++++++++++++++++-------- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/build/generate-flow-typed-style-spec.js b/build/generate-flow-typed-style-spec.js index d7a4070a801..f9ff2c1ebe0 100644 --- a/build/generate-flow-typed-style-spec.js +++ b/build/generate-flow-typed-style-spec.js @@ -165,6 +165,8 @@ ${flowObjectDeclaration('StyleSpecification', spec.$root)} ${flowObjectDeclaration('LightSpecification', spec.light)} +${flowObjectDeclaration('ClusterMapReduceSpecification', spec.clusterMapReduce)} + ${spec.source.map(key => flowObjectDeclaration(flowSourceTypeName(key), spec[key])).join('\n\n')} declare type SourceSpecification = diff --git a/flow-typed/style-spec.js b/flow-typed/style-spec.js index f479c08501e..d76955a31eb 100644 --- a/flow-typed/style-spec.js +++ b/flow-typed/style-spec.js @@ -72,11 +72,18 @@ declare type LightSpecification = {| "intensity"?: PropertyValueSpecification |} +declare type ClusterMapReduceSpecification = {| + "initial"?: mixed, + "map"?: mixed, + "reduce"?: mixed +|} + declare type VectorSourceSpecification = { "type": "vector", "url"?: string, "tiles"?: Array, "bounds"?: [number, number, number, number], + "scheme"?: "xyz" | "tms", "minzoom"?: number, "maxzoom"?: number, "attribution"?: string @@ -116,6 +123,7 @@ declare type GeojsonSourceSpecification = {| "cluster"?: boolean, "clusterRadius"?: number, "clusterMaxZoom"?: number, + "clusterMapReduce"?: ClusterMapReduceSpecification, "lineMetrics"?: boolean |} diff --git a/src/source/geojson_worker_source.js b/src/source/geojson_worker_source.js index cfefc8e64d7..531bc6c4f71 100644 --- a/src/source/geojson_worker_source.js +++ b/src/source/geojson_worker_source.js @@ -225,7 +225,7 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource { delete options.mapreduce; const { initial, map, reduce } = mapreduce; const globals = {}; - const spec = styleSpec.source_geojson.clusterMapReduce; + const spec = styleSpec.clusterMapReduce; if (initial) { const expressions = this._getExpressions(initial, createExpression, spec.initial); diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index 2fc221a13f8..8eada511af2 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -374,26 +374,27 @@ "doc": "Max zoom on which to cluster points if clustering is enabled. Defaults to one zoom less than maxzoom (so that last zoom features are not clustered)." }, "clusterMapReduce": { - "initial": { - "*": { - "type": "*", - "property-type": "data-constant" - }, - "doc": "Initial properties of a cluster (before runnning the reducer)." - }, - "map": { - "*": { - "type": "*", - "property-type": "data-driven" - }, - "doc": "Properties to use for individual points when running the reducer. Point properties can be accessed directly." - }, - "reduce": { - "*": { - "type": "*", - "property-type": "data-driven" + "type": "clusterMapReduce", + "doc": "Execute mapreduce functions on cluster properties to get more meaningful data.", + "example": { + "initial": { + "max": 1, + "sum": 0 }, - "doc": "Properties to add to the cluster. The cluster properties can be accessed from the `cluster` property (e.g. `cluster.total`, and the properties mapped in `map` can be accessed from `point` (e.g. `point.total`)." + "map": { + "max": ["get", "scalerank"], + "sum": ["get", "scalerank"] + }, + "reduce": { + "max": ["max", + ["get", "max", ["get", "cluster"]], + ["get", "max", ["get", "point"]] + ], + "sum": ["+", + ["get", "sum", ["get", "cluster"]], + ["get", "sum", ["get", "point"]] + ] + } } }, "lineMetrics": { @@ -3252,6 +3253,32 @@ } } }, + "clusterMapReduce": { + "initial": { + "type": "*", + "*": { + "type": "*", + "property-type": "data-constant" + }, + "doc": "Initial properties of a cluster (before runnning the reducer)." + }, + "map": { + "type": "*", + "*": { + "type": "*", + "property-type": "data-driven" + }, + "doc": "Properties to use for individual points when running the reducer. Point properties can be accessed directly." + }, + "reduce": { + "type": "*", + "*": { + "type": "*", + "property-type": "data-driven" + }, + "doc": "Properties to add to the cluster. The cluster properties can be accessed from the `cluster` property (e.g. `[\"get\", \"total\", [\"get\", \"cluster\"]]`), and the properties mapped in `map` can be accessed from `point` (e.g. `[\"get\", \"total\", [\"get\", \"point\"]]`)." + } + }, "paint": [ "paint_fill", "paint_line",