UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

177 lines (153 loc) 4.85 kB
// Copyright (c) 2020 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import wktParser from 'wellknown'; import normalize from '@mapbox/geojson-normalize'; import bbox from '@turf/bbox'; import {getSampleData} from 'utils/data-utils'; export function parseGeoJsonRawFeature(rawFeature) { if (typeof rawFeature === 'object') { // Support GeoJson feature as object // probably need to normalize it as well const normalized = normalize(rawFeature); if (!normalized || !Array.isArray(normalized.features)) { // fail to normalize GeoJson return null; } return normalized.features[0]; } else if (typeof rawFeature === 'string') { return parseGeometryFromString(rawFeature); } else if (Array.isArray(rawFeature)) { // Support GeoJson LineString as an array of points return { type: 'Feature', geometry: { // why do we need to flip it... coordinates: rawFeature.map(pts => [pts[1], pts[0]]), type: 'LineString' } }; } return null; } /** * Parse raw data to GeoJson feature * @param allData * @param getFeature * @returns {{}} */ export function getGeojsonDataMaps(allData, getFeature) { const acceptableTypes = [ 'Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon', 'GeometryCollection' ]; const dataToFeature = []; for (let index = 0; index < allData.length; index++) { const feature = parseGeoJsonRawFeature(getFeature(allData[index])); if (feature && feature.geometry && acceptableTypes.includes(feature.geometry.type)) { // store index of the data in feature properties feature.properties = { ...(feature.properties || {}), index }; dataToFeature[index] = feature; } else { dataToFeature[index] = null; } } return dataToFeature; } /** * Parse geojson from string * @param {String} geoString * @returns {null | Object} geojson object or null if failed */ export function parseGeometryFromString(geoString) { let parsedGeo; // try parse as geojson string // {"type":"Polygon","coordinates":[[[-74.158491,40.83594]]]} try { parsedGeo = JSON.parse(geoString); } catch (e) { // keep trying to parse } // try parse as wkt if (!parsedGeo) { try { parsedGeo = wktParser(geoString); } catch (e) { return null; } } if (!parsedGeo) { return null; } const normalized = normalize(parsedGeo); if (!normalized || !Array.isArray(normalized.features)) { // fail to normalize geojson return null; } return normalized.features[0]; } export function getGeojsonBounds(features = []) { // 70 ms for 10,000 polygons // here we only pick couple const maxCount = 10000; const samples = features.length > maxCount ? getSampleData(features, maxCount) : features; const nonEmpty = samples.filter( d => d && d.geometry && d.geometry.coordinates && d.geometry.coordinates.length ); try { return bbox({ type: 'FeatureCollection', features: nonEmpty }); } catch (e) { return null; } } export const featureToDeckGlGeoType = { Point: 'point', MultiPoint: 'point', LineString: 'line', MultiLineString: 'line', Polygon: 'polygon', MultiPolygon: 'polygon' }; /** * Parse geojson from string * @param {Array<Object>} allFeatures * @returns {Object} mapping of feature type existence */ export function getGeojsonFeatureTypes(allFeatures) { const featureTypes = {}; for (let f = 0; f < allFeatures.length; f++) { const feature = allFeatures[f]; const geoType = featureToDeckGlGeoType[feature && feature.geometry && feature.geometry.type]; if (geoType) { featureTypes[geoType] = true; } } return featureTypes; }