kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
585 lines (533 loc) • 13.4 kB
JavaScript
// 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 keyMirror from 'keymirror';
export const ACTION_PREFIX = '@@kepler.gl/';
export const CLOUDFRONT = 'https://d1a3f4spazzrp4.cloudfront.net/kepler.gl';
export const STYLE_PREFIX = `${CLOUDFRONT}/map-styles`;
export const ICON_PREFIX = `${CLOUDFRONT}/geodude`;
// Modal Ids
export const LAYER_CONFIG_ID = 'copyConfig';
export const DATA_TABLE_ID = 'dataTable';
export const DELETE_DATA_ID = 'deleteData';
export const ADD_DATA_ID = 'addData';
export const EXPORT_IMAGE_ID = 'exportImage';
export const EXPORT_DATA_ID = 'exportData';
export const EXPORT_CONFIG_ID = 'exportConfig';
export const ADD_MAP_STYLE_ID = 'addMapStyle';
import {
Layers,
FilterFunnel,
Settings,
CursorClick
} from 'components/common/icons';
export const KEPLER_GL_NAME = 'kepler.gl';
export const KEPLER_GL_VERSION = 'v1.0';
export const DIMENSIONS = {
sidePanel: {
width: 300,
margin: {top: 20, left: 20, bottom: 30, right: 20},
headerHeight: 96
},
mapControl: {
width: 204,
padding: 12
}
};
export const PANELS = [
{
id: 'layer',
label: 'Layers',
iconComponent: Layers
},
{
id: 'filter',
label: 'Filters',
iconComponent: FilterFunnel
},
{
id: 'interaction',
label: 'Interactions',
iconComponent: CursorClick
},
{
id: 'map',
label: 'Base map',
iconComponent: Settings
}
];
export const PANELS_FOOTER = [
{
id: LAYER_CONFIG_ID,
label: 'Copy Config',
icon: 'clipboard'
}
];
// MAP STYLES
export const DEFAULT_LAYER_GROUPS = [
{
slug: 'label',
filter: ({id}) => id.match(/(?=(label|place-|poi-))/),
defaultVisibility: true
},
{
slug: 'road',
filter: ({id}) => id.match(/(?=(road|railway|tunnel|street|bridge))(?!.*label)/),
defaultVisibility: true
},
{
slug: 'border',
filter: ({id}) => id.match(/border|boundaries/),
defaultVisibility: false
},
{
slug: 'building',
filter: ({id}) => id.match(/building/),
defaultVisibility: true
},
{
slug: 'water',
filter: ({id}) => id.match(/(?=(water|stream|ferry))/),
defaultVisibility: true
},
{
slug: 'land',
filter: ({id}) => id.match(/(?=(parks|landcover|industrial|sand|hillshade))/),
defaultVisibility: true
}
];
export const DEFAULT_MAP_STYLES = [
{
id: 'dark',
label: 'Dark',
url: `${STYLE_PREFIX}/dark`,
icon: `${ICON_PREFIX}/UBER_DARK_V2.png`,
layerGroups: DEFAULT_LAYER_GROUPS
},
{
id: 'light',
label: 'Light',
url: `${STYLE_PREFIX}/light`,
icon: `${ICON_PREFIX}/UBER_LIGHT_V2.png`,
layerGroups: DEFAULT_LAYER_GROUPS
},
{
id: 'muted',
label: 'Muted Light',
url: `${STYLE_PREFIX}/muted-light`,
icon: `${ICON_PREFIX}/UBER_MUTED_LIGHT.png`,
layerGroups: DEFAULT_LAYER_GROUPS
},
{
id: 'muted_night',
label: 'Muted Night',
url: `${STYLE_PREFIX}/muted-night`,
icon: `${ICON_PREFIX}/UBER_MUTED_NIGHT.png`,
layerGroups: DEFAULT_LAYER_GROUPS
}
];
export const GEOJSON_FIELDS = {
geojson: ['_geojson', 'all_points', 'geojson']
};
export const ICON_FIELDS = {
icon: ['icon']
};
export const TRIP_POINT_FIELDS = [
['lat', 'lng'],
['lat', 'lon'],
['latitude', 'longitude']
];
export const TRIP_ARC_FIELDS = {
lat0: 'begintrip',
lng0: 'begintrip',
lat1: 'dropoff',
lng1: 'dropoff'
};
export const SCALE_TYPES = keyMirror({
ordinal: null,
quantile: null,
quantize: null,
linear: null,
// for radius
sqrt: null,
// ordinal domain to linear range
point: null
});
export const SCALE_FUNC = {
linear: require('d3-scale').scaleLinear,
quantize: require('d3-scale').scaleQuantize,
quantile: require('d3-scale').scaleQuantile,
ordinal: require('d3-scale').scaleOrdinal,
sqrt: require('d3-scale').scaleSqrt,
point: require('d3-scale').scalePoint
};
export const ALL_FIELD_TYPES = keyMirror({
boolean: null,
date: null,
geojson: null,
integer: null,
real: null,
string: null,
timestamp: null,
point: null
});
const ORANGE = '248, 194, 28';
const PINK = '231, 189, 194';
const PURPLE = '160, 106, 206';
const BLUE = '140, 210, 205';
const BLUE2 = '106, 160, 206';
const BLUE3 = '0, 172, 237';
const GREEN = '106, 160, 56';
const RED = '237, 88, 106';
export const FIELD_COLORS = {
default: RED
};
export const FILED_TYPE_DISPLAY = {
[ALL_FIELD_TYPES.boolean]: {
label: 'bool',
color: PINK
},
[ALL_FIELD_TYPES.date]: {
label: 'date',
color: PURPLE
},
[ALL_FIELD_TYPES.geojson]: {
label: 'geo',
color: BLUE2
},
[ALL_FIELD_TYPES.integer]: {
label: 'int',
color: ORANGE
},
[ALL_FIELD_TYPES.real]: {
label: 'float',
color: ORANGE
},
[ALL_FIELD_TYPES.string]: {
label: 'string',
color: BLUE
},
[ALL_FIELD_TYPES.timestamp]: {
label: 'time',
color: GREEN
},
// field pairs
[ALL_FIELD_TYPES.point]: {
label: 'point',
color: BLUE3
}
};
export const defaultFormat = d => d;
export const FIELD_DISPLAY_FORMAT = {
[ALL_FIELD_TYPES.string]: defaultFormat,
[ALL_FIELD_TYPES.timestamp]: defaultFormat,
[ALL_FIELD_TYPES.integer]: defaultFormat,
[ALL_FIELD_TYPES.boolean]: d => String(d),
[ALL_FIELD_TYPES.date]: defaultFormat,
[ALL_FIELD_TYPES.geojson]: defaultFormat
};
export const CHANNEL_SCALES = keyMirror({
color: null,
radius: null,
size: null,
colorAggr: null,
sizeAggr: null
});
export const AGGREGATION_TYPES = {
// default
count: 'count',
// linear
average: 'average',
maximum: 'maximum',
minimum: 'minimum',
median: 'median',
sum: 'sum',
// ordinal
mode: 'mode',
countUnique: 'count unique'
};
export const linearFieldScaleFunctions = {
[CHANNEL_SCALES.color]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
[CHANNEL_SCALES.radius]: [SCALE_TYPES.sqrt],
[CHANNEL_SCALES.size]: [SCALE_TYPES.linear]
};
export const linearFieldAggrScaleFunctions = {
[CHANNEL_SCALES.colorAggr]: {
[AGGREGATION_TYPES.average]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
[AGGREGATION_TYPES.maximum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
[AGGREGATION_TYPES.minimum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
[AGGREGATION_TYPES.median]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
[AGGREGATION_TYPES.sum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile]
},
[CHANNEL_SCALES.sizeAggr]: {
[AGGREGATION_TYPES.average]: [SCALE_TYPES.linear],
[AGGREGATION_TYPES.maximum]: [SCALE_TYPES.linear],
[AGGREGATION_TYPES.minimum]: [SCALE_TYPES.linear],
[AGGREGATION_TYPES.median]: [SCALE_TYPES.linear],
[AGGREGATION_TYPES.sum]: [SCALE_TYPES.linear]
}
};
export const ordinalFieldScaleFunctions = {
[CHANNEL_SCALES.color]: [SCALE_TYPES.ordinal],
[CHANNEL_SCALES.radius]: [SCALE_TYPES.point],
[CHANNEL_SCALES.size]: [SCALE_TYPES.point]
};
export const ordinalFieldAggrScaleFunctions = {
// [CHANNEL_SCALES.colorAggr]: [SCALE_TYPES.ordinal, SCALE_TYPES.linear],
[CHANNEL_SCALES.colorAggr]: {
[AGGREGATION_TYPES.mode]: [SCALE_TYPES.ordinal],
[AGGREGATION_TYPES.countUnique]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile]
},
// Currently doesn't support yet
[CHANNEL_SCALES.sizeAggr]: {}
};
export const notSupportedScaleOpts = {
[CHANNEL_SCALES.color]: [],
[CHANNEL_SCALES.radius]: [],
[CHANNEL_SCALES.size]: []
};
export const notSupportAggrOpts = {
[CHANNEL_SCALES.colorAggr]: {},
[CHANNEL_SCALES.sizeAggr]: {}
};
/**
* Default aggregation are based on ocunt
*/
export const DEFAULT_AGGREGATION = {
[CHANNEL_SCALES.colorAggr]: {
[AGGREGATION_TYPES.count]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile]
},
[CHANNEL_SCALES.sizeAggr]: {
[AGGREGATION_TYPES.count]: [SCALE_TYPES.linear]
}
};
/**
* Define what type of scale operation is allowed on each type of fields
*/
export const FIELD_OPTS = {
string: {
type: 'categorical',
scale: {
...ordinalFieldScaleFunctions,
...ordinalFieldAggrScaleFunctions
},
format: {
legend: d => d
}
},
real: {
type: 'numerical',
scale: {
...linearFieldScaleFunctions,
...linearFieldAggrScaleFunctions
},
format: {
legend: d => d
}
},
timestamp: {
type: 'time',
scale: {
...linearFieldScaleFunctions,
...notSupportAggrOpts
},
format: {
legend: d => d
}
},
integer: {
type: 'numerical',
scale: {
...linearFieldScaleFunctions,
...linearFieldAggrScaleFunctions
},
format: {
legend: d => d
}
},
boolean: {
type: 'boolean',
scale: {
...ordinalFieldScaleFunctions,
...ordinalFieldAggrScaleFunctions
},
format: {
legend: d => d
}
},
date: {
scale: {
...ordinalFieldScaleFunctions,
...ordinalFieldAggrScaleFunctions
},
format: {
legend: d => d
}
},
geojson: {
type: 'geometry',
scale: {
...notSupportedScaleOpts,
...notSupportAggrOpts
},
format: {
legend: d => '...'
}
}
};
export const CHANNEL_SCALE_SUPPORTED_FIELDS = Object.keys(
CHANNEL_SCALES
).reduce(
(accu, key) => ({
...accu,
[key]: Object.keys(FIELD_OPTS).filter(
ft => Object.keys(FIELD_OPTS[ft].scale[key]).length
)
}),
{}
);
// TODO: shan delete use of LAYER_TYPES
export const LAYER_TYPES = keyMirror({
point: null,
arc: null,
cluster: null,
line: null,
grid: null,
geojson: null,
icon: null,
heatmap: null,
hexagon: null
});
export const DEFAULT_LAYER_COLOR = {
tripArc: '#9226C6',
begintrip_lat: '#1E96BE',
dropoff_lat: '#FF991F',
request_lat: '#52A353'
};
// let user pass in default tooltip fields
export const DEFAULT_TOOLTIP_FIELDS = [];
export const DEFAULT_LIGHT_SETTINGS = {
lightsPosition: [-122.45, 37.66, 8000, -122.0, 38.0, 8000],
ambientRatio: 0.4,
diffuseRatio: 0.6,
specularRatio: 0.3,
lightsStrength: [0.9, 0.0, 0.8, 0.0],
numberOfLights: 2
};
export const NO_VALUE_COLOR = [147, 147, 147];
export const LAYER_BLENDINGS = {
additive: {
blendFunc: ['SRC_ALPHA', 'DST_ALPHA'],
blendEquation: 'FUNC_ADD'
},
normal: {
// reference to
// https://limnu.com/webgl-blending-youre-probably-wrong/
blendFunc: [
'SRC_ALPHA',
'ONE_MINUS_SRC_ALPHA',
'ONE',
'ONE_MINUS_SRC_ALPHA'
],
blendEquation: ['FUNC_ADD', 'FUNC_ADD']
},
subtractive: {
blendFunc: ['ONE', 'ONE_MINUS_DST_COLOR', 'SRC_ALPHA', 'DST_ALPHA'],
blendEquation: ['FUNC_SUBTRACT', 'FUNC_ADD']
}
};
export const MAX_DEFAULT_TOOLTIPS = 5;
export const RESOLUTIONS = keyMirror({
ONE_X: null,
TWO_X: null
});
export const RATIOS = keyMirror({
SCREEN: null,
FOUR_BY_THREE: null,
SIXTEEN_BY_NINE: null
});
export const RATIO_OPTIONS = [{
id: RATIOS.SCREEN,
label: 'Original Screen',
getSize: (screenW, screenH) => ({width: screenW, height: screenH})
}, {
id: RATIOS.FOUR_BY_THREE,
label: '4:3',
getSize: (screenW, screenH) => ({width: screenW, height: Math.round(screenW * 0.75)})
}, {
id: RATIOS.SIXTEEN_BY_NINE,
label: '16:9',
getSize: (screenW, screenH) => ({width: screenW, height: Math.round(screenW * 0.5625)})
}];
export const RESOLUTION_OPTIONS = [{
id: RESOLUTIONS.ONE_X,
label: '1x',
available: true,
scale: 1,
zoomOffset: Math.log2(1),
getSize: (screenW, screenH) => ({
width: screenW,
height: screenH
})
}, {
id: RESOLUTIONS.TWO_X,
label: '2x',
available: true,
scale: 2,
zoomOffset: Math.log2(2),
getSize: (screenW, screenH) => ({
width: screenW * 2,
height: screenH * 2
})
}];
export const DEFAULT_EXPORT_IMAGE_NAME = 'kepler-gl.png';
export const EXPORT_DATA_TYPE = keyMirror({
CSV: null
// SHAPEFILE: null,
// JSON: null,
// GEOJSON: null,
// TOPOJSON: null
});
export const EXPORT_DATA_TYPE_OPTIONS = [
{
id: EXPORT_DATA_TYPE.CSV,
label: 'csv',
available: true
}
// {
// id: EXPORT_DATA_TYPE.SHAPEFILE,
// label: 'shapefile',
// available: false
// },
// {
// id: EXPORT_DATA_TYPE.JSON,
// label: 'json',
// available: false
// },
// {
// id: EXPORT_DATA_TYPE.GEOJSON,
// label: 'geojson',
// available: false
// },
// {
// id: EXPORT_DATA_TYPE.TOPOJSON,
// label: 'topojson',
// available: false
// }
];