kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
948 lines (801 loc) • 86.6 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.OVERLAY_TYPE = undefined;
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _extends6 = require('babel-runtime/helpers/extends');
var _extends7 = _interopRequireDefault(_extends6);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _colorUtils = require('../utils/color-utils');
var _window = require('global/window');
var _keymirror = require('keymirror');
var _keymirror2 = _interopRequireDefault(_keymirror);
var _defaultLayerIcon = require('./default-layer-icon');
var _defaultLayerIcon2 = _interopRequireDefault(_defaultLayerIcon);
var _defaultSettings = require('../constants/default-settings');
var _customColorRanges = require('../constants/custom-color-ranges');
var _layerFactory = require('./layer-factory');
var _utils = require('../utils/utils');
var _dataUtils = require('../utils/data-utils');
var _dataScaleUtils = require('../utils/data-scale-utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _marked = /*#__PURE__*/_regenerator2.default.mark(generateColor); // 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.
/**
* Approx. number of points to sample in a large data set
* @type {number}
*/
var MAX_SAMPLE_SIZE = 5000;
var OVERLAY_TYPE = exports.OVERLAY_TYPE = (0, _keymirror2.default)({
deckgl: null,
mapboxgl: null
});
var layerColors = Object.values(_customColorRanges.DataVizColors).map(_colorUtils.hexToRgb);
function generateColor() {
var index;
return _regenerator2.default.wrap(function generateColor$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
index = 0;
case 1:
if (!(index < layerColors.length + 1)) {
_context.next = 7;
break;
}
if (index === layerColors.length) {
index = 0;
}
_context.next = 5;
return layerColors[index++];
case 5:
_context.next = 1;
break;
case 7:
case 'end':
return _context.stop();
}
}
}, _marked, this);
}
var colorMaker = generateColor();
var defaultGetFieldValue = function defaultGetFieldValue(field, d) {
return d[field.tableFieldIndex - 1];
};
var Layer = function () {
function Layer() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
(0, _classCallCheck3.default)(this, Layer);
this.id = props.id || (0, _utils.generateHashId)(6);
// meta
this.meta = {};
// visConfigSettings
this.visConfigSettings = {};
this.config = this.getDefaultLayerConfig((0, _extends7.default)({
columns: this.getLayerColumns()
}, props));
}
(0, _createClass3.default)(Layer, [{
key: 'getDefaultLayerConfig',
value: function getDefaultLayerConfig() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return {
dataId: props.dataId || null,
label: props.label || 'new layer',
color: props.color || colorMaker.next().value,
columns: props.columns || null,
isVisible: props.isVisible || false,
isConfigActive: props.isConfigActive || false,
highlightColor: props.highlightColor || [252, 242, 26, 255],
// TODO: refactor this into separate visual Channel config
// color by field, domain is set by filters, field, scale type
colorField: null,
colorDomain: [0, 1],
colorScale: 'quantile',
// color by size, domain is set by filters, field, scale type
sizeDomain: [0, 1],
sizeScale: 'linear',
sizeField: null,
visConfig: {},
textLabel: {
field: null,
color: [255, 255, 255],
size: 50,
offset: [0, 0],
anchor: 'middle'
}
};
}
/**
* Get the description of a visualChannel config
* @param key
* @returns {{label: string, measure: (string|string)}}
*/
}, {
key: 'getVisualChannelDescription',
value: function getVisualChannelDescription(key) {
// e.g. label: Color, measure: Vehicle Type
return {
label: this.visConfigSettings[this.visualChannels[key].range].label,
measure: this.config[this.visualChannels[key].field] ? this.config[this.visualChannels[key].field].name : this.visualChannels[key].defaultMeasure
};
}
/**
* Assign a field to layer column, return column config
* @param key - Column Key
* @param field - Selected field
* @returns {{}} - Column config
*/
}, {
key: 'assignColumn',
value: function assignColumn(key, field) {
// field value could be null for optional columns
var update = field ? {
value: field.name,
fieldIdx: field.tableFieldIndex - 1
} : { value: null, fieldIdx: -1 };
return (0, _extends7.default)({}, this.config.columns, (0, _defineProperty3.default)({}, key, (0, _extends7.default)({}, this.config.columns[key], update)));
}
/**
* Assign a field pair to column config, return column config
* @param key - Column Key
* @param pair - field Pair
* @returns {{}} - Column config
*/
}, {
key: 'assignColumnPairs',
value: function assignColumnPairs(key, pair) {
var _extends3;
if (!this.columnPairs || !this.columnPairs[key]) {
// should not end in this state
return this.config.columns;
}
var _columnPairs$key = this.columnPairs[key],
partnerKey = _columnPairs$key.pair,
fieldPairKey = _columnPairs$key.fieldPairKey;
var partnerFieldPairKey = this.columnPairs[partnerKey].fieldPairKey;
return (0, _extends7.default)({}, this.config.columns, (_extends3 = {}, (0, _defineProperty3.default)(_extends3, key, pair[fieldPairKey]), (0, _defineProperty3.default)(_extends3, partnerKey, pair[partnerFieldPairKey]), _extends3));
}
/**
* Calculate a radius zoom multiplier to render points, so they are visible in all zoom level
* @param mapState
* @param mapState.zoom - actual zoom
* @param mapState.zoomOffset - zoomOffset when render in the plot container for export image
* @returns {number}
*/
}, {
key: 'getZoomFactor',
value: function getZoomFactor(_ref) {
var zoom = _ref.zoom,
_ref$zoomOffset = _ref.zoomOffset,
zoomOffset = _ref$zoomOffset === undefined ? 0 : _ref$zoomOffset;
return Math.pow(2, Math.max(14 - zoom + zoomOffset, 0));
}
/**
* Calculate a elevation zoom multiplier to render points, so they are visible in all zoom level
* @param mapState
* @param mapState.zoom - actual zoom
* @param mapState.zoomOffset - zoomOffset when render in the plot container for export image
* @returns {number}
*/
}, {
key: 'getElevationZoomFactor',
value: function getElevationZoomFactor(_ref2) {
var zoom = _ref2.zoom,
_ref2$zoomOffset = _ref2.zoomOffset,
zoomOffset = _ref2$zoomOffset === undefined ? 0 : _ref2$zoomOffset;
return Math.pow(2, Math.max(8 - zoom + zoomOffset, 0));
}
}, {
key: 'formatLayerData',
value: function formatLayerData(data, allData, filteredIndex) {
return {};
}
}, {
key: 'renderLayer',
value: function renderLayer() {
return [];
}
}, {
key: 'getHoverData',
value: function getHoverData(object) {
if (!object) {
return null;
}
// by default, each entry of layerData should have a data property points
// to the original item in the allData array
// each layer can implement its own getHoverData method
return object.data;
}
/**
* When change layer type, try to copy over layer configs as much as possible
* @param configToCopy - config to copy over
* @param visConfigSettings - visConfig settings of config to copy
*/
}, {
key: 'assignConfigToLayer',
value: function assignConfigToLayer(configToCopy, visConfigSettings) {
var _this = this;
// don't deep merge visualChannel field
var notToDeepMerge = Object.values(this.visualChannels).map(function (v) {
return v.field;
});
// don't deep merge color range, reversed: is not a key by default
notToDeepMerge.push('colorRange');
// don't copy over domain
var notToCopy = Object.values(this.visualChannels).map(function (v) {
return v.domain;
});
// if range is for the same property group copy it, otherwise, not to copy
Object.values(this.visualChannels).forEach(function (v) {
if (configToCopy.visConfig[v.range] && visConfigSettings[v.range].group !== _this.visConfigSettings[v.range].group) {
notToCopy.push(v.range);
}
});
// don't copy over visualChannel range
var currentConfig = this.config;
var copied = this.copyLayerConfig(currentConfig, configToCopy, { notToDeepMerge: notToDeepMerge, notToCopy: notToCopy });
this.updateLayerConfig(copied);
// validate visualChannel field type and scale types
Object.keys(this.visualChannels).forEach(function (channel) {
_this.validateVisualChannel(channel);
});
}
/*
* Recursively copy config over to an empty layer
* when received saved config, or copy config over from a different layer type
* make sure to only copy over value to existing keys
* @param {object} currentConfig - existing config to be override
* @param {object} configToCopy - new Config to copy over
* @param {string[]} notToDeepMerge - array of properties to not to be deep copied
* @param {string[]} notToCopy - array of properties not to copy
* @returns {object} - copied config
*/
}, {
key: 'copyLayerConfig',
value: function copyLayerConfig(currentConfig, configToCopy) {
var _this2 = this;
var _ref3 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
_ref3$notToDeepMerge = _ref3.notToDeepMerge,
notToDeepMerge = _ref3$notToDeepMerge === undefined ? [] : _ref3$notToDeepMerge,
_ref3$notToCopy = _ref3.notToCopy,
notToCopy = _ref3$notToCopy === undefined ? [] : _ref3$notToCopy;
var copied = {};
Object.keys(currentConfig).forEach(function (key) {
if ((0, _utils.isPlainObject)(currentConfig[key]) && (0, _utils.isPlainObject)(configToCopy[key]) && !notToDeepMerge.includes(key) && !notToCopy.includes(key)) {
// recursively assign object value
copied[key] = _this2.copyLayerConfig(currentConfig[key], configToCopy[key], { notToDeepMerge: notToDeepMerge, notToCopy: notToCopy });
} else if ((0, _utils.notNullorUndefined)(configToCopy[key]) && !notToCopy.includes(key)) {
// copy
copied[key] = configToCopy[key];
} else {
// keep existing
copied[key] = currentConfig[key];
}
});
return copied;
}
}, {
key: 'registerVisConfig',
value: function registerVisConfig(layerVisConfigs) {
var _this3 = this;
Object.keys(layerVisConfigs).forEach(function (item) {
if (typeof item === 'string' && _layerFactory.LAYER_VIS_CONFIGS[layerVisConfigs[item]]) {
// if assigned one of default LAYER_CONFIGS
_this3.config.visConfig[item] = _layerFactory.LAYER_VIS_CONFIGS[layerVisConfigs[item]].defaultValue;
_this3.visConfigSettings[item] = _layerFactory.LAYER_VIS_CONFIGS[layerVisConfigs[item]];
} else if (['type', 'defaultValue'].every(function (p) {
return layerVisConfigs[item][p];
})) {
// if provided customized visConfig, and has type && defaultValue
// TODO: further check if customized visConfig is valid
_this3.config.visConfig[item] = layerVisConfigs[item].defaultValue;
_this3.visConfigSettings[item] = layerVisConfigs[item];
}
});
}
}, {
key: 'getLayerColumns',
value: function getLayerColumns() {
var required = this.requiredLayerColumns.reduce(function (accu, key) {
return (0, _extends7.default)({}, accu, (0, _defineProperty3.default)({}, key, { value: null, fieldIdx: -1 }));
}, {});
var optional = this.optionalColumns.reduce(function (accu, key) {
return (0, _extends7.default)({}, accu, (0, _defineProperty3.default)({}, key, { value: null, fieldIdx: -1, optional: true }));
}, {});
return (0, _extends7.default)({}, required, optional);
}
}, {
key: 'updateLayerConfig',
value: function updateLayerConfig(newConfig) {
this.config = (0, _extends7.default)({}, this.config, newConfig);
return this;
}
}, {
key: 'updateLayerVisConfig',
value: function updateLayerVisConfig(newVisConfig) {
this.config.visConfig = (0, _extends7.default)({}, this.config.visConfig, newVisConfig);
return this;
}
/**
* Check whether layer has all columns
*
* @param {object} layer
* @returns {boolean} yes or no
*/
}, {
key: 'hasAllColumns',
value: function hasAllColumns() {
var columns = this.config.columns;
return columns && Object.values(columns).every(function (v) {
return Boolean(v.optional || v.value && v.fieldIdx > -1);
});
}
/**
* Check whether layer has data
*
* @param {object} layer
* @param {Array | Object} layerData
* @returns {boolean} yes or no
*/
}, {
key: 'hasLayerData',
value: function hasLayerData(layerData) {
if (!layerData) {
return false;
}
return Boolean(layerData.data && layerData.data.length);
}
}, {
key: 'isValidToSave',
value: function isValidToSave() {
return this.type && this.hasAllColumns();
}
}, {
key: 'shouldRenderLayer',
value: function shouldRenderLayer(data) {
return this.type && this.hasAllColumns() && this.config.isVisible && this.hasLayerData(data);
}
}, {
key: 'getVisChannelScale',
value: function getVisChannelScale(scale, domain, range, fixed) {
return _defaultSettings.SCALE_FUNC[fixed ? 'linear' : scale]().domain(domain).range(fixed ? domain : range);
}
}, {
key: 'getPointsBounds',
value: function getPointsBounds(allData, getPosition) {
// no need to loop through the entire dataset
// get a sample of data to calculate bounds
var sampleData = allData.length > MAX_SAMPLE_SIZE ? (0, _dataUtils.getSampleData)(allData, MAX_SAMPLE_SIZE) : allData;
var points = sampleData.map(getPosition);
var latBounds = (0, _dataUtils.getLatLngBounds)(points, 1, [-90, 90]);
var lngBounds = (0, _dataUtils.getLatLngBounds)(points, 0, [-180, 180]);
if (!latBounds || !lngBounds) {
return null;
}
return [lngBounds[0], latBounds[0], lngBounds[1], latBounds[1]];
}
}, {
key: 'getLightSettingsFromBounds',
value: function getLightSettingsFromBounds(bounds) {
return Array.isArray(bounds) && bounds.length >= 4 ? (0, _extends7.default)({}, _defaultSettings.DEFAULT_LIGHT_SETTINGS, {
lightsPosition: [].concat((0, _toConsumableArray3.default)(bounds.slice(0, 2)), [_defaultSettings.DEFAULT_LIGHT_SETTINGS.lightsPosition[2]], (0, _toConsumableArray3.default)(bounds.slice(2, 4)), [_defaultSettings.DEFAULT_LIGHT_SETTINGS.lightsPosition[5]])
}) : _defaultSettings.DEFAULT_LIGHT_SETTINGS;
}
}, {
key: 'getEncodedChannelValue',
value: function getEncodedChannelValue(scale, data, field) {
var defaultValue = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _defaultSettings.NO_VALUE_COLOR;
var getValue = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : defaultGetFieldValue;
var type = field.type;
var value = getValue(field, data);
var attributeValue = void 0;
if (type === _defaultSettings.ALL_FIELD_TYPES.timestamp) {
// shouldn't need to convert here
// scale Function should take care of it
attributeValue = scale(new Date(value));
} else {
attributeValue = scale(value);
}
if (!attributeValue) {
attributeValue = defaultValue;
}
return attributeValue;
}
}, {
key: 'updateMeta',
value: function updateMeta(meta) {
this.meta = (0, _extends7.default)({}, this.meta, meta);
}
/**
* helper function to update one layer domain when state.data changed
* if state.data change is due ot update filter, newFiler will be passed
* called by updateAllLayerDomainData
* @param {Object} dataset
* @param {Object} newFilter
* @returns {object} layer
*/
}, {
key: 'updateLayerDomain',
value: function updateLayerDomain(dataset, newFilter) {
var _this4 = this;
Object.values(this.visualChannels).forEach(function (channel) {
var scale = channel.scale;
var scaleType = _this4.config[scale];
// ordinal domain is based on allData, if only filter changed
// no need to update ordinal domain
if (!newFilter || scaleType !== _defaultSettings.SCALE_TYPES.ordinal) {
var domain = channel.domain;
var updatedDomain = _this4.calculateLayerDomain(dataset, channel);
_this4.updateLayerConfig((0, _defineProperty3.default)({}, domain, updatedDomain));
}
});
return this;
}
/**
* Validate visual channel field and scales based on supported field & scale type
* @param channel
*/
}, {
key: 'validateVisualChannel',
value: function validateVisualChannel(channel) {
this.validateFieldType(channel);
this.validateScale(channel);
}
/**
* Validate field type based on channelScaleType
*/
}, {
key: 'validateFieldType',
value: function validateFieldType(channel) {
var visualChannel = this.visualChannels[channel];
var field = visualChannel.field,
channelScaleType = visualChannel.channelScaleType,
supportedFieldTypes = visualChannel.supportedFieldTypes;
if (this.config[field]) {
// if field is selected, check if field type is supported
var channelSupportedFieldTypes = supportedFieldTypes || _defaultSettings.CHANNEL_SCALE_SUPPORTED_FIELDS[channelScaleType];
if (!channelSupportedFieldTypes.includes(this.config[field].type)) {
// field type is not supported, set it back to null
// set scale back to default
this.updateLayerConfig((0, _defineProperty3.default)({}, field, null));
}
}
}
/**
* Validate scale type based on aggregation
*/
}, {
key: 'validateScale',
value: function validateScale(channel) {
var visualChannel = this.visualChannels[channel];
var scale = visualChannel.scale;
if (!scale) {
// visualChannel doesn't have scale
return;
}
var scaleOptions = this.getScaleOptions(channel);
// check if current selected scale is
// supported, if not, change to default
if (!scaleOptions.includes(this.config[scale])) {
this.updateLayerConfig((0, _defineProperty3.default)({}, scale, scaleOptions[0]));
}
}
/**
* Get scale options based on current field
* @param {string} channel
* @returns {string[]}
*/
}, {
key: 'getScaleOptions',
value: function getScaleOptions(channel) {
var visualChannel = this.visualChannels[channel];
var field = visualChannel.field,
scale = visualChannel.scale,
channelScaleType = visualChannel.channelScaleType;
return this.config[field] ? _defaultSettings.FIELD_OPTS[this.config[field].type].scale[channelScaleType] : [this.getDefaultLayerConfig()[scale]];
}
}, {
key: 'updateLayerVisualChannel',
value: function updateLayerVisualChannel(dataset, channel) {
var visualChannel = this.visualChannels[channel];
this.validateVisualChannel(channel);
// calculate layer channel domain
var updatedDomain = this.calculateLayerDomain(dataset, visualChannel);
this.updateLayerConfig((0, _defineProperty3.default)({}, visualChannel.domain, updatedDomain));
}
}, {
key: 'calculateLayerDomain',
value: function calculateLayerDomain(dataset, visualChannel) {
var allData = dataset.allData,
filteredIndexForDomain = dataset.filteredIndexForDomain;
var defaultDomain = [0, 1];
var scale = visualChannel.scale;
var scaleType = this.config[scale];
var field = this.config[visualChannel.field];
if (!field) {
// if colorField or sizeField were set back to null
return defaultDomain;
}
if (!_defaultSettings.SCALE_TYPES[scaleType]) {
_window.console.error('scale type ' + scaleType + ' not supported');
return defaultDomain;
}
// TODO: refactor to add valueAccessor to field
var fieldIdx = field.tableFieldIndex - 1;
var isTime = field.type === _defaultSettings.ALL_FIELD_TYPES.timestamp;
var valueAccessor = _dataUtils.maybeToDate.bind(null, isTime, fieldIdx, field.format);
var indexValueAccessor = function indexValueAccessor(i) {
return valueAccessor(allData[i]);
};
var sortFunction = (0, _dataUtils.getSortingFunction)(field.type);
switch (scaleType) {
case _defaultSettings.SCALE_TYPES.ordinal:
case _defaultSettings.SCALE_TYPES.point:
// do not recalculate ordinal domain based on filtered data
// don't need to update ordinal domain every time
return (0, _dataScaleUtils.getOrdinalDomain)(allData, valueAccessor);
case _defaultSettings.SCALE_TYPES.quantile:
return (0, _dataScaleUtils.getQuantileDomain)(filteredIndexForDomain, indexValueAccessor, sortFunction);
case _defaultSettings.SCALE_TYPES.quantize:
case _defaultSettings.SCALE_TYPES.linear:
case _defaultSettings.SCALE_TYPES.sqrt:
default:
return (0, _dataScaleUtils.getLinearDomain)(filteredIndexForDomain, indexValueAccessor);
}
}
}, {
key: 'isLayerHovered',
value: function isLayerHovered(objectInfo) {
return objectInfo && objectInfo.layer && objectInfo.picked && objectInfo.layer.props.id === this.id;
}
}, {
key: 'getRadiusScaleByZoom',
value: function getRadiusScaleByZoom(mapState, fixedRadius) {
var radiusChannel = Object.values(this.visualChannels).find(function (vc) {
return vc.property === 'radius';
});
if (!radiusChannel) {
return 1;
}
var field = radiusChannel.field;
var fixed = fixedRadius === undefined ? this.config.visConfig.fixedRadius : fixedRadius;
var radius = this.config.visConfig.radius;
return fixed ? 1 : (this.config[field] ? 1 : radius) * this.getZoomFactor(mapState);
}
}, {
key: 'shouldCalculateLayerData',
value: function shouldCalculateLayerData(props) {
var _this5 = this;
return props.some(function (p) {
return !_this5.noneLayerDataAffectingProps.includes(p);
});
}
}, {
key: 'layerIcon',
get: function get() {
return _defaultLayerIcon2.default;
}
}, {
key: 'overlayType',
get: function get() {
return OVERLAY_TYPE.deckgl;
}
}, {
key: 'type',
get: function get() {
return null;
}
}, {
key: 'name',
get: function get() {
return this.type;
}
}, {
key: 'isAggregated',
get: function get() {
return false;
}
}, {
key: 'requiredLayerColumns',
get: function get() {
return [];
}
}, {
key: 'optionalColumns',
get: function get() {
return [];
}
}, {
key: 'noneLayerDataAffectingProps',
get: function get() {
return ['label', 'opacity', 'thickness', 'isVisible'];
}
}, {
key: 'visualChannels',
get: function get() {
return {
color: {
property: 'color',
field: 'colorField',
scale: 'colorScale',
domain: 'colorDomain',
range: 'colorRange',
key: 'color',
channelScaleType: _defaultSettings.CHANNEL_SCALES.color
},
size: {
property: 'size',
field: 'sizeField',
scale: 'sizeScale',
domain: 'sizeDomain',
range: 'sizeRange',
key: 'size',
channelScaleType: _defaultSettings.CHANNEL_SCALES.size
}
};
}
/*
* Column pairs maps layer column to a specific field pairs,
* By default, it is set to null
*/
}, {
key: 'columnPairs',
get: function get() {
return null;
}
/*
* Default point column pairs, can be used for point based layers: point, icon etc.
*/
}, {
key: 'defaultPointColumnPairs',
get: function get() {
return {
lat: { pair: 'lng', fieldPairKey: 'lat' },
lng: { pair: 'lat', fieldPairKey: 'lng' }
};
}
/*
* Default link column pairs, can be used for link based layers: arc, line etc
*/
}, {
key: 'defaultLinkColumnPairs',
get: function get() {
return {
lat0: { pair: 'lng0', fieldPairKey: 'lat' },
lng0: { pair: 'lat0', fieldPairKey: 'lng' },
lat1: { pair: 'lng1', fieldPairKey: 'lat' },
lng1: { pair: 'lat1', fieldPairKey: 'lng' }
};
}
/**
* Return a React component for to render layer instructions in a modal
* @returns {object} - an object
* @example
* return {
* id: 'iconInfo',
* template: IconInfoModal,
* modalProps: {
* title: 'How to draw icons'
* };
* }
*/
}, {
key: 'layerInfoModal',
get: function get() {
return null;
}
/*
* Given a dataset, automatically create layers based on it
* and return the props
* By default, no layers will be found
*/
}], [{
key: 'findDefaultLayerProps',
value: function findDefaultLayerProps(fieldPairs, dataId) {
return null;
}
/**
* Given a array of preset required column names
* found field that has the same name to set as layer column
*
* @param {object[]} defaultFields
* @param {object[]} allFields
* @returns {object[] | null} all possible required layer column pairs
*/
}, {
key: 'findDefaultColumnField',
value: function findDefaultColumnField(defaultFields, allFields) {
// find all matched fields for each required col
var requiredColumns = Object.keys(defaultFields).reduce(function (prev, key) {
var requiredFields = allFields.filter(function (f) {
return f.name === defaultFields[key] || defaultFields[key].includes(f.name);
});
prev[key] = requiredFields.length ? requiredFields.map(function (f) {
return {
value: f.name,
fieldIdx: f.tableFieldIndex - 1
};
}) : null;
return prev;
}, {});
if (!Object.values(requiredColumns).every(Boolean)) {
// if any field missing, return null
return null;
}
return this.getAllPossibleColumnParis(requiredColumns);
}
}, {
key: 'getAllPossibleColumnParis',
value: function getAllPossibleColumnParis(requiredColumns) {
// for multiple matched field for one required column, return multiple
// combinations, e. g. if column a has 2 matched, column b has 3 matched
// 6 possible column pairs will be returned
var allKeys = Object.keys(requiredColumns);
var pointers = allKeys.map(function (k, i) {
return i === allKeys.length - 1 ? -1 : 0;
});
var countPerKey = allKeys.map(function (k) {
return requiredColumns[k].length;
});
var pairs = [];
/* eslint-disable no-loop-func */
while (incrementPointers(pointers, countPerKey, pointers.length - 1)) {
var newPair = pointers.reduce(function (prev, cuur, i) {
prev[allKeys[i]] = requiredColumns[allKeys[i]][cuur];
return prev;
}, {});
pairs.push(newPair);
}
/* eslint-enable no-loop-func */
// recursively increment pointers
function incrementPointers(pts, counts, index) {
if (index === 0 && pts[0] === counts[0] - 1) {
// nothing to increment
return false;
}
if (pts[index] + 1 < counts[index]) {
pts[index] = pts[index] + 1;
return true;
}
pts[index] = 0;
return incrementPointers(pts, counts, index - 1);
}
return pairs;
}
}, {
key: 'hexToRgb',
value: function hexToRgb(c) {
return (0, _colorUtils.hexToRgb)(c);
}
}]);
return Layer;
}();
exports.default = Layer;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9sYXllcnMvYmFzZS1sYXllci5qcyJdLCJuYW1lcyI6WyJnZW5lcmF0ZUNvbG9yIiwiTUFYX1NBTVBMRV9TSVpFIiwiT1ZFUkxBWV9UWVBFIiwiZGVja2dsIiwibWFwYm94Z2wiLCJsYXllckNvbG9ycyIsIk9iamVjdCIsInZhbHVlcyIsIkRhdGFWaXpDb2xvcnMiLCJtYXAiLCJoZXhUb1JnYiIsImluZGV4IiwibGVuZ3RoIiwiY29sb3JNYWtlciIsImRlZmF1bHRHZXRGaWVsZFZhbHVlIiwiZmllbGQiLCJkIiwidGFibGVGaWVsZEluZGV4IiwiTGF5ZXIiLCJwcm9wcyIsImlkIiwibWV0YSIsInZpc0NvbmZpZ1NldHRpbmdzIiwiY29uZmlnIiwiZ2V0RGVmYXVsdExheWVyQ29uZmlnIiwiY29sdW1ucyIsImdldExheWVyQ29sdW1ucyIsImRhdGFJZCIsImxhYmVsIiwiY29sb3IiLCJuZXh0IiwidmFsdWUiLCJpc1Zpc2libGUiLCJpc0NvbmZpZ0FjdGl2ZSIsImhpZ2hsaWdodENvbG9yIiwiY29sb3JGaWVsZCIsImNvbG9yRG9tYWluIiwiY29sb3JTY2FsZSIsInNpemVEb21haW4iLCJzaXplU2NhbGUiLCJzaXplRmllbGQiLCJ2aXNDb25maWciLCJ0ZXh0TGFiZWwiLCJzaXplIiwib2Zmc2V0IiwiYW5jaG9yIiwia2V5IiwidmlzdWFsQ2hhbm5lbHMiLCJyYW5nZSIsIm1lYXN1cmUiLCJuYW1lIiwiZGVmYXVsdE1lYXN1cmUiLCJ1cGRhdGUiLCJmaWVsZElkeCIsInBhaXIiLCJjb2x1bW5QYWlycyIsInBhcnRuZXJLZXkiLCJmaWVsZFBhaXJLZXkiLCJwYXJ0bmVyRmllbGRQYWlyS2V5Iiwiem9vbSIsInpvb21PZmZzZXQiLCJNYXRoIiwicG93IiwibWF4IiwiZGF0YSIsImFsbERhdGEiLCJmaWx0ZXJlZEluZGV4Iiwib2JqZWN0IiwiY29uZmlnVG9Db3B5Iiwibm90VG9EZWVwTWVyZ2UiLCJ2IiwicHVzaCIsIm5vdFRvQ29weSIsImRvbWFpbiIsImZvckVhY2giLCJncm91cCIsImN1cnJlbnRDb25maWciLCJjb3BpZWQiLCJjb3B5TGF5ZXJDb25maWciLCJ1cGRhdGVMYXllckNvbmZpZyIsImtleXMiLCJ2YWxpZGF0ZVZpc3VhbENoYW5uZWwiLCJjaGFubmVsIiwiaW5jbHVkZXMiLCJsYXllclZpc0NvbmZpZ3MiLCJpdGVtIiwiTEFZRVJfVklTX0NPTkZJR1MiLCJkZWZhdWx0VmFsdWUiLCJldmVyeSIsInAiLCJyZXF1aXJlZCIsInJlcXVpcmVkTGF5ZXJDb2x1bW5zIiwicmVkdWNlIiwiYWNjdSIsIm9wdGlvbmFsIiwib3B0aW9uYWxDb2x1bW5zIiwibmV3Q29uZmlnIiwibmV3VmlzQ29uZmlnIiwiQm9vbGVhbiIsImxheWVyRGF0YSIsInR5cGUiLCJoYXNBbGxDb2x1bW5zIiwiaGFzTGF5ZXJEYXRhIiwic2NhbGUiLCJmaXhlZCIsIlNDQUxFX0ZVTkMiLCJnZXRQb3NpdGlvbiIsInNhbXBsZURhdGEiLCJwb2ludHMiLCJsYXRCb3VuZHMiLCJsbmdCb3VuZHMiLCJib3VuZHMiLCJBcnJheSIsImlzQXJyYXkiLCJERUZBVUxUX0xJR0hUX1NFVFRJTkdTIiwibGlnaHRzUG9zaXRpb24iLCJzbGljZSIsIk5PX1ZBTFVFX0NPTE9SIiwiZ2V0VmFsdWUiLCJhdHRyaWJ1dGVWYWx1ZSIsIkFMTF9GSUVMRF9UWVBFUyIsInRpbWVzdGFtcCIsIkRhdGUiLCJkYXRhc2V0IiwibmV3RmlsdGVyIiwic2NhbGVUeXBlIiwiU0NBTEVfVFlQRVMiLCJvcmRpbmFsIiwidXBkYXRlZERvbWFpbiIsImNhbGN1bGF0ZUxheWVyRG9tYWluIiwidmFsaWRhdGVGaWVsZFR5cGUiLCJ2YWxpZGF0ZVNjYWxlIiwidmlzdWFsQ2hhbm5lbCIsImNoYW5uZWxTY2FsZVR5cGUiLCJzdXBwb3J0ZWRGaWVsZFR5cGVzIiwiY2hhbm5lbFN1cHBvcnRlZEZpZWxkVHlwZXMiLCJDSEFOTkVMX1NDQUxFX1NVUFBPUlRFRF9GSUVMRFMiLCJzY2FsZU9wdGlvbnMiLCJnZXRTY2FsZU9wdGlvbnMiLCJGSUVMRF9PUFRTIiwiZmlsdGVyZWRJbmRleEZvckRvbWFpbiIsImRlZmF1bHREb21haW4iLCJDb25zb2xlIiwiZXJyb3IiLCJpc1RpbWUiLCJ2YWx1ZUFjY2Vzc29yIiwibWF5YmVUb0RhdGUiLCJiaW5kIiwiZm9ybWF0IiwiaW5kZXhWYWx1ZUFjY2Vzc29yIiwiaSIsInNvcnRGdW5jdGlvbiIsInBvaW50IiwicXVhbnRpbGUiLCJxdWFudGl6ZSIsImxpbmVhciIsInNxcnQiLCJvYmplY3RJbmZvIiwibGF5ZXIiLCJwaWNrZWQiLCJtYXBTdGF0ZSIsImZpeGVkUmFkaXVzIiwicmFkaXVzQ2hhbm5lbCIsImZpbmQiLCJ2YyIsInByb3BlcnR5IiwidW5kZWZpbmVkIiwicmFkaXVzIiwiZ2V0Wm9vbUZhY3RvciIsInNvbWUiLCJub25lTGF5ZXJEYXRhQWZmZWN0aW5nUHJvcHMiLCJEZWZhdWx0TGF5ZXJJY29uIiwiQ0hBTk5FTF9TQ0FMRVMiLCJsYXQiLCJsbmciLCJsYXQwIiwibG5nMCIsImxhdDEiLCJsbmcxIiwiZmllbGRQYWlycyIsImRlZmF1bHRGaWVsZHMiLCJhbGxGaWVsZHMiLCJyZXF1aXJlZENvbHVtbnMiLCJwcmV2IiwicmVxdWlyZWRGaWVsZHMiLCJmaWx0ZXIiLCJmIiwiZ2V0QWxsUG9zc2libGVDb2x1bW5QYXJpcyIsImFsbEtleXMiLCJwb2ludGVycyIsImsiLCJjb3VudFBlcktleSIsInBhaXJzIiwiaW5jcmVtZW50UG9pbnRlcnMiLCJuZXdQYWlyIiwiY3V1ciIsInB0cyIsImNvdW50cyIsImMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFvQkE7O0FBQ0E7O0FBQ0E7Ozs7QUFDQTs7OztBQUVBOztBQVVBOztBQUNBOztBQUVBOztBQUVBOztBQU9BOzs7O3NEQWtCVUEsYSxHQWpFVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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