diff --git a/src/sources/mvt.js b/src/sources/mvt.js index a5bd5f830..e75a0a50c 100644 --- a/src/sources/mvt.js +++ b/src/sources/mvt.js @@ -1,9 +1,18 @@ import DataSource, {NetworkTileSource} from './data_source'; import Geo from '../utils/geo'; +import log from '../utils/log'; import Pbf from 'pbf'; import {VectorTile, VectorTileFeature} from '@mapbox/vector-tile'; +const PARSE_JSON_TYPE = { + NONE: 0, + ALL: 1, + SOME: 2 +}; + +const PARSE_JSON_TEST = ['{', '[']; // one-time allocated array/strings + /** Mapbox Vector Tile format @class MVTSource @@ -13,6 +22,27 @@ export class MVTSource extends NetworkTileSource { constructor (source, sources) { super(source, sources); this.response_type = 'arraybuffer'; // binary data + + // Optionally parse some or all properties from JSON strings + if (source.parse_json === true) { + // try to parse all properties (least efficient) + this.parse_json_type = PARSE_JSON_TYPE.ALL; + } + else if (Array.isArray(source.parse_json)) { + // try to parse a specific list of property names (more efficient) + this.parse_json_type = PARSE_JSON_TYPE.SOME; + this.parse_json_prop_list = source.parse_json; + } + else { + if (source.parse_json != null) { + let msg = `Data source '${this.name}': 'parse_json' parameter should be 'true', or an array of ` + + `property names (was '${source.parse_json}')`; + log({ level: 'warn', once: true }, msg); + } + + // skip parsing entirely (default behavior) + this.parse_json_type = PARSE_JSON_TYPE.NONE; + } } parseSourceData (tile, source, response) { @@ -55,6 +85,8 @@ export class MVTSource extends NetworkTileSource { properties: feature.properties }; + this.parseJSONProperties(feature_geojson); + var geometry = feature_geojson.geometry; var coordinates = feature.loadGeometry(); for (var r=0; r < coordinates.length; r++) { @@ -92,6 +124,29 @@ export class MVTSource extends NetworkTileSource { return layers; } + // Optionally parse some or all feature properties from JSON strings + parseJSONProperties (feature) { + if (this.parse_json_type !== PARSE_JSON_TYPE.NONE) { + const props = feature.properties; + for (const p in props) { + // if specified, check list of explicit properties to parse + // (otherwise try to parse all properties) + if (this.parse_json_type === PARSE_JSON_TYPE.SOME && + this.parse_json_prop_list.indexOf(p) === -1) { + continue; // skip this property + } + + // check if this property looks like JSON, and parse if so + if (PARSE_JSON_TEST.indexOf(props[p][0]) > -1) { + try { + props[p] = JSON.parse(props[p]); + } catch (e) { + // continue with original value if couldn't parse as JSON + } + } + } + } + } } // Decode multipolygons, which are encoded as a single set of rings