UNPKG

kepler.gl

Version:

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

182 lines (158 loc) 5.72 kB
// Copyright (c) 2018 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 Immutable from 'immutable'; import memoize from 'lodash.memoize'; import { DEFAULT_LAYER_GROUPS, RESOLUTIONS, RESOLUTION_OPTIONS } from 'constants/default-settings'; export function getDefaultLayerGroupVisibility({layerGroups = []}) { return layerGroups.reduce( (accu, layer) => ({ ...accu, [layer.slug]: layer.defaultVisibility }), {} ); } const resolver = ({id, mapStyle, visibleLayerGroups = {}}) => `${id}:${Object.keys(visibleLayerGroups) .filter(d => visibleLayerGroups[d]) .sort() .join('-')}`; /** * Edit preset map style to keep only visible layers * * @param {object} mapStyle - preset map style * @param {object} visibleLayerGroups - visible layers of top map * @returns {Immutable.Map} top map style */ export const editTopMapStyle = memoize(({id, mapStyle, visibleLayerGroups}) => { const visibleFilters = (mapStyle.layerGroups || []) .filter(lg => visibleLayerGroups[lg.slug]) .map(lg => lg.filter); // if top map // keep only visible layers const filteredLayers = mapStyle.style.layers.filter(layer => visibleFilters.some(match => match(layer)) ); return Immutable.fromJS({ ...mapStyle.style, layers: filteredLayers }); }, resolver); /** * Edit preset map style to filter out invisible layers * * @param {object} mapStyle - preset map style * @param {object} visibleLayerGroups - visible layers of bottom map * @returns {Immutable.Map} bottom map style */ export const editBottomMapStyle = memoize( ({id, mapStyle, visibleLayerGroups}) => { const invisibleFilters = (mapStyle.layerGroups || []) .filter(lg => !visibleLayerGroups[lg.slug]) .map(lg => lg.filter); // if bottom map // filter out invisible layers const filteredLayers = mapStyle.style.layers.filter(layer => invisibleFilters.every(match => !match(layer)) ); // console.log(filteredLayers) return Immutable.fromJS({ ...mapStyle.style, layers: filteredLayers }); }, resolver ); const mapUrlRg = /^mapbox:\/\/styles\/[-a-z0-9]{2,256}\/[-a-z0-9]{2,256}/; const httpRg = /^(?=(http:|https:))/; const mapboxStyleApiUrl = 'https://api.mapbox.com/styles/v1/'; // valid style url // mapbox://styles/uberdata/cjfyl03kp1tul2smf5v2tbdd4 // lowercase letters, numbers and dashes only. export function isValidStyleUrl(url) { return typeof url === 'string' && Boolean(url.match(mapUrlRg) || url.match(httpRg)); } export function getStyleDownloadUrl(styleUrl, accessToken) { if (styleUrl.startsWith('http')) { return styleUrl; } // mapbox://styles/jckr/cjhcl0lxv13di2rpfoytdbdyj if (styleUrl.startsWith('mapbox://styles')) { const styleId = styleUrl.replace('mapbox://styles/', ''); // https://api.mapbox.com/styles/v1/heshan0131/cjg1bfumo1cwm2rlrjxkinfgw?pluginName=Keplergl&access_token=<token> return `${mapboxStyleApiUrl}${styleId}?pluginName=Keplergl&access_token=${accessToken}` } // style url not recognized return null; } export function scaleMapStyleByResolution(mapboxStyle, resolution) { const labelLayerGroup = DEFAULT_LAYER_GROUPS.find(lg => lg.slug === 'label'); const {filter: labelLayerFilter} = labelLayerGroup; if (resolution !== RESOLUTIONS.ONE_X && mapboxStyle) { const {scale, zoomOffset} = RESOLUTION_OPTIONS.find( r => r.id === resolution ); const copyStyle = mapboxStyle.toJS(); (copyStyle.layers || []).forEach(d => { // edit minzoom and maxzoom if (d.maxzoom) { d.maxzoom += zoomOffset; } if (d.minzoom) { d.minzoom += zoomOffset; } // edit text size if (labelLayerFilter(d)) { if ( d.layout && d.layout['text-size'] && Array.isArray(d.layout['text-size'].stops) ) { d.layout['text-size'].stops.forEach(stop => { // zoom stop[0] += Math.log2(scale); // size stop[1] *= scale; }); } } }); return Immutable.fromJS(copyStyle); } return mapboxStyle; } /** * When switch to a new style, try to keep current layer group visibility * by merging default and current * @param {object} defaultLayerGroup * @param {object} currentLayerGroup * @return {object} mergedLayerGroups */ export function mergeLayerGroupVisibility(defaultLayerGroup, currentLayerGroup) { return Object.keys(currentLayerGroup) .reduce((accu, key) => ({ ...accu, ...(defaultLayerGroup.hasOwnProperty(key) ? {[key]: currentLayerGroup[key]} : {}) }), defaultLayerGroup); }