UNPKG

kepler.gl

Version:

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

1,110 lines (1,041 loc) 39 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. /* eslint-disable complexity */ import React, {Component, Fragment} from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import {FormattedMessage} from 'react-intl'; import {Button, Input, PanelLabel, SidePanelSection} from 'components/common/styled-components'; import ItemSelector from 'components/common/item-selector/item-selector'; import VisConfigByFieldSelector from './vis-config-by-field-selector'; import LayerColumnConfig from './layer-column-config'; import LayerTypeSelector from './layer-type-selector'; import DimensionScaleSelector from './dimension-scale-selector'; import ColorSelector from './color-selector'; import SourceDataSelectorFactory from 'components/side-panel/common/source-data-selector'; import VisConfigSwitch from './vis-config-switch'; import VisConfigSlider from './vis-config-slider'; import LayerConfigGroup, {ConfigGroupCollapsibleContent} from './layer-config-group'; import TextLabelPanel from './text-label-panel'; import {capitalizeFirstLetter} from 'utils/utils'; import {CHANNEL_SCALE_SUPPORTED_FIELDS, LAYER_TYPES} from 'constants/default-settings'; const StyledLayerConfigurator = styled.div.attrs({ className: 'layer-panel__config' })` position: relative; margin-top: 12px; `; const StyledLayerVisualConfigurator = styled.div.attrs({ className: 'layer-panel__config__visualC-config' })` margin-top: 12px; `; export const getLayerFields = (datasets, layer) => datasets[layer.config.dataId] ? datasets[layer.config.dataId].fields : []; export const getLayerConfiguratorProps = props => ({ layer: props.layer, fields: getLayerFields(props.datasets, props.layer), onChange: props.updateLayerConfig, setColorUI: props.updateLayerColorUI }); export const getVisConfiguratorProps = props => ({ layer: props.layer, fields: getLayerFields(props.datasets, props.layer), onChange: props.updateLayerVisConfig, setColorUI: props.updateLayerColorUI }); export const getLayerChannelConfigProps = props => ({ layer: props.layer, fields: getLayerFields(props.datasets, props.layer), onChange: props.updateLayerVisualChannelConfig }); LayerConfiguratorFactory.deps = [SourceDataSelectorFactory]; export default function LayerConfiguratorFactory(SourceDataSelector) { class LayerConfigurator extends Component { static propTypes = { layer: PropTypes.object.isRequired, datasets: PropTypes.object.isRequired, layerTypeOptions: PropTypes.arrayOf(PropTypes.any).isRequired, openModal: PropTypes.func.isRequired, updateLayerConfig: PropTypes.func.isRequired, updateLayerType: PropTypes.func.isRequired, updateLayerVisConfig: PropTypes.func.isRequired, updateLayerVisualChannelConfig: PropTypes.func.isRequired, updateLayerColorUI: PropTypes.func.isRequired }; _renderPointLayerConfig(props) { return this._renderScatterplotLayerConfig(props); } _renderIconLayerConfig(props) { return this._renderScatterplotLayerConfig(props); } _renderScatterplotLayerConfig({ layer, visConfiguratorProps, layerChannelConfigProps, layerConfiguratorProps }) { return ( <StyledLayerVisualConfigurator> {/* Fill Color */} <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* outline color */} {layer.type === LAYER_TYPES.point ? ( <LayerConfigGroup {...layer.visConfigSettings.outline} {...visConfiguratorProps} collapsible > {layer.config.strokeColorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" /> ) : ( <LayerColorSelector {...visConfiguratorProps} selectedColor={layer.config.visConfig.strokeColor} property="strokeColor" /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.strokeColor} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.thickness} {...visConfiguratorProps} label="Stroke Width (Pixels)" disabled={!layer.config.visConfig.outline} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* Radius */} <LayerConfigGroup label={'layer.radius'} collapsible> {!layer.config.sizeField ? ( <VisConfigSlider {...layer.visConfigSettings.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.sizeField)} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.sizeField || layer.config.visConfig.fixedRadius} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> {layer.config.sizeField ? ( <VisConfigSwitch {...layer.visConfigSettings.fixedRadius} {...visConfiguratorProps} /> ) : null} </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* text label */} <TextLabelPanel fields={visConfiguratorProps.fields} updateLayerTextLabel={this.props.updateLayerTextLabel} textLabel={layer.config.textLabel} colorPalette={visConfiguratorProps.colorPalette} setColorPaletteUI={visConfiguratorProps.setColorPaletteUI} /> </StyledLayerVisualConfigurator> ); } _renderClusterLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'layer.color'} collapsible> <LayerColorRangeSelector {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <AggrScaleSelector {...layerConfiguratorProps} channel={layer.visualChannels.color} /> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> {layer.visConfigSettings.colorAggregation.condition(layer.config) ? ( <AggregationTypeSelector {...layer.visConfigSettings.colorAggregation} {...layerChannelConfigProps} channel={layer.visualChannels.color} /> ) : null} <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Cluster Radius */} <LayerConfigGroup label={'layer.radius'} collapsible> <VisConfigSlider {...layer.visConfigSettings.clusterRadius} {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <VisConfigSlider {...layer.visConfigSettings.radiusRange} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderHeatmapLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'layer.color'} collapsible> <LayerColorRangeSelector {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Radius */} <LayerConfigGroup label={'layer.radius'}> <VisConfigSlider {...layer.visConfigSettings.radius} {...visConfiguratorProps} label={false} /> </LayerConfigGroup> {/* Weight */} <LayerConfigGroup label={'layer.weight'}> <ChannelByValueSelector channel={layer.visualChannels.weight} {...layerChannelConfigProps} /> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderGridLayerConfig(props) { return this._renderAggregationLayerConfig(props); } _renderHexagonLayerConfig(props) { return this._renderAggregationLayerConfig(props); } _renderAggregationLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const {config} = layer; const { visConfig: {enable3d} } = config; const elevationByDescription = 'layer.elevationByDescription'; const colorByDescription = 'layer.colorByDescription'; return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'layer.color'} collapsible> <LayerColorRangeSelector {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <AggrScaleSelector {...layerConfiguratorProps} channel={layer.visualChannels.color} /> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> {layer.visConfigSettings.colorAggregation.condition(layer.config) ? ( <AggregationTypeSelector {...layer.visConfigSettings.colorAggregation} {...layerChannelConfigProps} description={colorByDescription} channel={layer.visualChannels.color} /> ) : null} {layer.visConfigSettings.percentile && layer.visConfigSettings.percentile.condition(layer.config) ? ( <VisConfigSlider {...layer.visConfigSettings.percentile} {...visConfiguratorProps} /> ) : null} <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Cell size */} <LayerConfigGroup label={'layer.radius'} collapsible> <VisConfigSlider {...layer.visConfigSettings.worldUnitSize} {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <VisConfigSlider {...layer.visConfigSettings.coverage} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Elevation */} {layer.visConfigSettings.enable3d ? ( <LayerConfigGroup {...layer.visConfigSettings.enable3d} {...visConfiguratorProps} collapsible > <VisConfigSlider {...layer.visConfigSettings.elevationScale} {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <AggrScaleSelector {...layerConfiguratorProps} channel={layer.visualChannels.size} /> <VisConfigSlider {...layer.visConfigSettings.sizeRange} {...visConfiguratorProps} /> <ChannelByValueSelector {...layerChannelConfigProps} channel={layer.visualChannels.size} description={elevationByDescription} disabled={!enable3d} /> {layer.visConfigSettings.sizeAggregation.condition(layer.config) ? ( <AggregationTypeSelector {...layer.visConfigSettings.sizeAggregation} {...layerChannelConfigProps} channel={layer.visualChannels.size} /> ) : null} {layer.visConfigSettings.elevationPercentile.condition(layer.config) ? ( <VisConfigSlider {...layer.visConfigSettings.elevationPercentile} {...visConfiguratorProps} /> ) : null} </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} </StyledLayerVisualConfigurator> ); } // TODO: Shan move these into layer class _renderHexagonIdLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'layer.color'} collapsible> {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Coverage */} <LayerConfigGroup label={'layer.coverage'} collapsible> {!layer.config.coverageField ? ( <VisConfigSlider {...layer.visConfigSettings.coverage} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.coverageRange} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.coverage} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* height */} <LayerConfigGroup {...layer.visConfigSettings.enable3d} {...visConfiguratorProps} collapsible > <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> <ConfigGroupCollapsibleContent> <VisConfigSlider {...layer.visConfigSettings.elevationScale} {...visConfiguratorProps} /> <VisConfigSlider {...layer.visConfigSettings.sizeRange} {...visConfiguratorProps} label="layerVisConfigs.heightRange" /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderArcLayerConfig(args) { return this._renderLineLayerConfig(args); } _renderLineLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'layer.color'} collapsible> {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <ArcLayerColorSelector layer={layer} setColorUI={layerConfiguratorProps.setColorUI} onChangeConfig={layerConfiguratorProps.onChange} onChangeVisConfig={visConfiguratorProps.onChange} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* thickness */} <LayerConfigGroup label={'layer.stroke'} collapsible> {layer.config.sizeField ? ( <VisConfigSlider {...layer.visConfigSettings.sizeRange} {...visConfiguratorProps} disabled={!layer.config.sizeField} label={false} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderTripLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}} } = layer; return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'layer.color'} collapsible> {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Stroke Width */} <LayerConfigGroup {...visConfiguratorProps} label="layer.strokeWidth" collapsible> {layer.config.sizeField ? ( <VisConfigSlider {...layer.visConfigSettings.sizeRange} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Trail Length*/} <LayerConfigGroup {...visConfiguratorProps} {...(featureTypes.polygon ? layer.visConfigSettings.stroked : {})} label="layer.trailLength" description="layer.trailLengthDescription" > <VisConfigSlider {...layer.visConfigSettings.trailLength} {...visConfiguratorProps} label={false} /> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderGeojsonLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Fill Color */} {featureTypes.polygon || featureTypes.point ? ( <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="layer.fillColor" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* stroke color */} <LayerConfigGroup {...layer.visConfigSettings.stroked} {...visConfiguratorProps} label="layer.strokeColor" collapsible > {layer.config.strokeColorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" /> ) : ( <LayerColorSelector {...visConfiguratorProps} selectedColor={layer.config.visConfig.strokeColor} property="strokeColor" /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.strokeColor} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.strokeOpacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Stroke Width */} <LayerConfigGroup {...visConfiguratorProps} {...(featureTypes.polygon ? layer.visConfigSettings.stroked : {})} label="layer.strokeWidth" collapsible > {layer.config.sizeField ? ( <VisConfigSlider {...layer.visConfigSettings.sizeRange} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Elevation */} {featureTypes.polygon ? ( <LayerConfigGroup {...visConfiguratorProps} {...layer.visConfigSettings.enable3d} disabled={!visConfig.filled} collapsible > <VisConfigSlider {...layer.visConfigSettings.elevationScale} {...visConfiguratorProps} label={false} /> <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.height} {...layerChannelConfigProps} /> <VisConfigSwitch {...visConfiguratorProps} {...layer.visConfigSettings.wireframe} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* Radius */} {featureTypes.point ? ( <LayerConfigGroup label={'layer.radius'} collapsible> {!layer.config.radiusField ? ( <VisConfigSlider {...layer.visConfigSettings.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.radiusField)} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.radiusField} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.radius} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} </StyledLayerVisualConfigurator> ); } _render3DLayerConfig({layer, visConfiguratorProps}) { return ( <Fragment> <LayerConfigGroup label={'layer.3DModel'} collapsible> <Input type="file" accept=".glb,.gltf" onChange={e => { if (e.target.files && e.target.files[0]) { const url = URL.createObjectURL(e.target.files[0]); visConfiguratorProps.onChange({scenegraph: url}); } }} /> </LayerConfigGroup> <LayerConfigGroup label={'layer.3DModelOptions'} collapsible> <VisConfigSlider {...layer.visConfigSettings.sizeScale} {...visConfiguratorProps} disabled={false} /> <VisConfigSlider {...layer.visConfigSettings.angleX} {...visConfiguratorProps} disabled={false} /> <VisConfigSlider {...layer.visConfigSettings.angleY} {...visConfiguratorProps} disabled={false} /> <VisConfigSlider {...layer.visConfigSettings.angleZ} {...visConfiguratorProps} disabled={false} /> </LayerConfigGroup> </Fragment> ); } _renderS2LayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="layer.fillColor" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Stroke */} <LayerConfigGroup {...layer.visConfigSettings.stroked} {...visConfiguratorProps} label="layer.strokeColor" collapsible > {layer.config.strokeColorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" /> ) : ( <LayerColorSelector {...visConfiguratorProps} selectedColor={layer.config.visConfig.strokeColor} property="strokeColor" /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.strokeColor} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Stroke Width */} <LayerConfigGroup {...visConfiguratorProps} label="layer.strokeWidth" collapsible> {layer.config.sizeField ? ( <VisConfigSlider {...layer.visConfigSettings.sizeRange} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...layer.visConfigSettings.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Elevation */} <LayerConfigGroup {...visConfiguratorProps} {...layer.visConfigSettings.enable3d} disabled={!visConfig.filled} collapsible > <ChannelByValueSelector channel={layer.visualChannels.height} {...layerChannelConfigProps} /> <VisConfigSlider {...layer.visConfigSettings.elevationScale} {...visConfiguratorProps} label="layerVisConfigs.elevationScale" /> <ConfigGroupCollapsibleContent> <VisConfigSlider {...layer.visConfigSettings.heightRange} {...visConfiguratorProps} label="layerVisConfigs.heightRange" /> <VisConfigSwitch {...visConfiguratorProps} {...layer.visConfigSettings.wireframe} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } render() { const {layer, datasets, updateLayerConfig, layerTypeOptions, updateLayerType} = this.props; const {fields = [], fieldPairs} = layer.config.dataId ? datasets[layer.config.dataId] : {}; const {config} = layer; const visConfiguratorProps = getVisConfiguratorProps(this.props); const layerConfiguratorProps = getLayerConfiguratorProps(this.props); const layerChannelConfigProps = getLayerChannelConfigProps(this.props); const renderTemplate = layer.type && `_render${capitalizeFirstLetter(layer.type)}LayerConfig`; return ( <StyledLayerConfigurator> {layer.layerInfoModal ? ( <HowToButton onClick={() => this.props.openModal(layer.layerInfoModal)} /> ) : null} <LayerConfigGroup label={'layer.basic'} collapsible expanded={!layer.hasAllColumns()}> <LayerTypeSelector layer={layer} layerTypeOptions={layerTypeOptions} onSelect={updateLayerType} /> <ConfigGroupCollapsibleContent> {Object.keys(datasets).length > 1 && ( <SourceDataSelector datasets={datasets} id={layer.id} disabled={layer.type && config.columns} dataId={config.dataId} onSelect={value => updateLayerConfig({dataId: value})} /> )} <LayerColumnConfig columnPairs={layer.columnPairs} columns={layer.config.columns} assignColumnPairs={layer.assignColumnPairs.bind(layer)} assignColumn={layer.assignColumn.bind(layer)} columnLabels={layer.columnLabels} fields={fields} fieldPairs={fieldPairs} updateLayerConfig={updateLayerConfig} updateLayerType={this.props.updateLayerType} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {this[renderTemplate] && this[renderTemplate]({ layer, visConfiguratorProps, layerChannelConfigProps, layerConfiguratorProps })} </StyledLayerConfigurator> ); } } return LayerConfigurator; } /* * Componentize config component into pure functional components */ const StyledHowToButton = styled.div` position: absolute; right: 12px; top: -4px; `; export const HowToButton = ({onClick}) => ( <StyledHowToButton> <Button link small onClick={onClick}> <FormattedMessage id={'layerConfiguration.howTo'} /> </Button> </StyledHowToButton> ); export const LayerColorSelector = ({ layer, onChange, label, selectedColor, property = 'color', setColorUI }) => ( <SidePanelSection> <ColorSelector colorSets={[ { selectedColor: selectedColor || layer.config.color, setColor: rgbValue => onChange({[property]: rgbValue}) } ]} colorUI={layer.config.colorUI[property]} setColorUI={newConfig => setColorUI(property, newConfig)} /> </SidePanelSection> ); export const ArcLayerColorSelector = ({ layer, onChangeConfig, onChangeVisConfig, property = 'color', setColorUI }) => ( <SidePanelSection> <ColorSelector colorSets={[ { selectedColor: layer.config.color, setColor: rgbValue => onChangeConfig({color: rgbValue}), label: 'Source' }, { selectedColor: layer.config.visConfig.targetColor || layer.config.color, setColor: rgbValue => onChangeVisConfig({targetColor: rgbValue}), label: 'Target' } ]} colorUI={layer.config.colorUI[property]} setColorUI={newConfig => setColorUI(property, newConfig)} /> </SidePanelSection> ); export const LayerColorRangeSelector = ({layer, onChange, property = 'colorRange', setColorUI}) => ( <SidePanelSection> <ColorSelector colorSets={[ { selectedColor: layer.config.visConfig[property], isRange: true, setColor: colorRange => onChange({[property]: colorRange}) } ]} colorUI={layer.config.colorUI[property]} setColorUI={newConfig => setColorUI(property, newConfig)} /> </SidePanelSection> ); export const ChannelByValueSelector = ({layer, channel, onChange, fields, description}) => { const { channelScaleType, domain, field, key, property, range, scale, defaultMeasure, supportedFieldTypes } = channel; const channelSupportedFieldTypes = supportedFieldTypes || CHANNEL_SCALE_SUPPORTED_FIELDS[channelScaleType]; const supportedFields = fields.filter(({type}) => channelSupportedFieldTypes.includes(type)); const scaleOptions = layer.getScaleOptions(channel.key); const showScale = !layer.isAggregated && layer.config[scale] && scaleOptions.length > 1; const defaultDescription = 'layerConfiguration.defaultDescription'; return ( <VisConfigByFieldSelector channel={channel.key} description={description || defaultDescription} domain={layer.config[domain]} fields={supportedFields} id={layer.id} key={`${key}-channel-selector`} property={property} placeholder={defaultMeasure || 'placeholder.selectField'} range={layer.config.visConfig[range]} scaleOptions={scaleOptions} scaleType={scale ? layer.config[scale] : null} selectedField={layer.config[field]} showScale={showScale} updateField={val => onChange({[field]: val}, key)} updateScale={val => onChange({[scale]: val}, key)} /> ); }; export const AggrScaleSelector = ({channel, layer, onChange}) => { const {scale, key} = channel; const scaleOptions = layer.getScaleOptions(key); return Array.isArray(scaleOptions) && scaleOptions.length > 1 ? ( <DimensionScaleSelector label={`${key} Scale`} options={scaleOptions} scaleType={layer.config[scale]} onSelect={val => onChange({[scale]: val}, key)} /> ) : null; }; export const AggregationTypeSelector = ({layer, channel, onChange}) => { const {field, aggregation, key} = channel; const selectedField = layer.config[field]; const {visConfig} = layer.config; // aggregation should only be selectable when field is selected const aggregationOptions = layer.getAggregationOptions(key); return ( <SidePanelSection> <PanelLabel> <FormattedMessage id={'layer.aggregateBy'} values={{field: selectedField.name}} /> </PanelLabel> <ItemSelector selectedItems={visConfig[aggregation]} options={aggregationOptions} multiSelect={false} searchable={false} onChange={value => onChange( { visConfig: { ...layer.config.visConfig, [aggregation]: value } }, channel.key ) } /> </SidePanelSection> ); }; /* eslint-enable max-params */