UNPKG

kepler.gl.geoiq

Version:

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

1,516 lines (1,434 loc) 51.5 kB
// Copyright (c) 2023 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 { Button, PanelLabel, SidePanelSection, Input } 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 {LAYER_VIS_CONFIGS} from 'layers/layer-factory'; import {capitalizeFirstLetter} from 'utils/utils'; import { LAYER_TYPES, CHANNEL_SCALE_SUPPORTED_FIELDS } 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> {/* Radius */} <LayerConfigGroup label={'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> ); } _renderArcLayerConfig(args) { return this._renderLineLayerConfig(args); } _renderLineLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'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_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* thickness */} <LayerConfigGroup label={'stroke'} collapsible> {layer.config.sizeField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.strokeWidthRange} {...visConfiguratorProps} disabled={!layer.config.sizeField} label={false} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderBackendPointLayerConfig(props) { return this._renderGeoPointLayerConfig(props); } _renderGeoPointLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Fill Color */} {featureTypes.polygon || featureTypes.point ? ( <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="Fill Color" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* Radius */} {featureTypes.point ? ( <LayerConfigGroup label={'radius'} collapsible> {!layer.config.radiusField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.radiusField)} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.radiusField} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.radius} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} </StyledLayerVisualConfigurator> ); } _renderPolygonLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Fill Color */} {featureTypes.polygon || featureTypes.point ? ( <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="Fill Color" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* Radius */} {featureTypes.point ? ( <LayerConfigGroup label={'radius'} collapsible> {!layer.config.radiusField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.radiusField)} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.radiusField} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.radius} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} <LayerConfigGroup {...visConfiguratorProps} {...(featureTypes.polygon ? LAYER_VIS_CONFIGS.stroked : {})} label="Stroke Width" collapsible > {layer.config.sizeField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.strokeWidthRange} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> )} {/* <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> */} </LayerConfigGroup> </StyledLayerVisualConfigurator> ); } _renderBackendGeojsonLayerConfig(props) { return this._renderPolygonLayerConfig(props); } _renderGeojsonLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Fill Color */} {featureTypes.polygon || featureTypes.point ? ( // || // layer.type === 'MVT' <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="Fill Color" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* stroke color */} {/* <LayerConfigGroup {...layer.visConfigSettings.stroked} {...visConfiguratorProps} label="Stroke Color" 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} {...(featureTypes.polygon ? LAYER_VIS_CONFIGS.stroked : {})} label="Stroke Width" collapsible > {layer.config.sizeField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.strokeWidthRange} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Elevation */} {/* {featureTypes.polygon && visConfig.filled ? ( <LayerConfigGroup {...visConfiguratorProps} {...LAYER_VIS_CONFIGS.enable3d} collapsible > <VisConfigSlider {...LAYER_VIS_CONFIGS.elevationScale} {...visConfiguratorProps} label={false} /> <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.height} {...layerChannelConfigProps} /> <VisConfigSwitch {...visConfiguratorProps} {...LAYER_VIS_CONFIGS.wireframe} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} */} {/* Radius */} {featureTypes.point ? ( <LayerConfigGroup label={'radius'} collapsible> {!layer.config.radiusField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.radiusField)} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.radiusField} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.radius} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} </StyledLayerVisualConfigurator> ); } _renderPincodeLayerConfig(props) { return this._renderAdminBoundaryLayerConfig(props); } _renderBoundaryLayerConfig(props) { return this._renderAdminBoundaryLayerConfig(props); } _renderDynamicLayerConfig(props) { const {layer} = props; const { meta: {featureTypes = {}}, config: {visConfig} } = layer; if (featureTypes.point) { return this._renderGeoBoundaryPointLayerConfig(props); } else if (featureTypes.polygon) { return this._renderGeoBoundaryLayerConfig(props); } } _renderGeoHashLayerConfig(props) { return this._renderGeoBoundaryLayerConfig(props); } _renderClusterLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'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={'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={'color'} collapsible> <LayerColorRangeSelector {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Radius */} <LayerConfigGroup label={'radius'}> <VisConfigSlider {...layer.visConfigSettings.radius} {...visConfiguratorProps} label={false} /> </LayerConfigGroup> {/* Weight */} <LayerConfigGroup label={'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 = 'When off, height is based on count of points'; const colorByDescription = 'When off, color is based on count of points'; return ( <StyledLayerVisualConfigurator> {/* Color */} <LayerConfigGroup label={'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={'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> ); } _renderGeoDynamicLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Fill Color */} {featureTypes.polygon || featureTypes.point ? ( <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="Fill Color" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* stroke color */} <LayerConfigGroup {...layer.visConfigSettings.stroked} {...visConfiguratorProps} label="Stroke Color" 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} {...(featureTypes.polygon ? LAYER_VIS_CONFIGS.stroked : {})} label="Stroke Width" collapsible > {layer.config.sizeField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.strokeWidthRange} {...visConfiguratorProps} label={false} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.size} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Elevation */} {/* {featureTypes.polygon && visConfig.filled ? ( <LayerConfigGroup {...visConfiguratorProps} {...LAYER_VIS_CONFIGS.enable3d} collapsible > <VisConfigSlider {...LAYER_VIS_CONFIGS.elevationScale} {...visConfiguratorProps} label={false} /> <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.height} {...layerChannelConfigProps} /> <VisConfigSwitch {...visConfiguratorProps} {...LAYER_VIS_CONFIGS.wireframe} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} */} {/* Radius */} {featureTypes.point ? ( <LayerConfigGroup label={'radius'} collapsible> {!layer.config.radiusField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.radiusField)} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.radiusField} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.radius} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} </StyledLayerVisualConfigurator> ); } _renderGeoBoundaryLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; const {enable3d} = visConfig; const elevationByDescription = 'When off, height is based on count of points'; const colorByDescription = 'When off, color is based on count of points'; return ( <StyledLayerVisualConfigurator> {/* Color By */} <LayerConfigGroup label={'color'} collapsible> <LayerColorRangeSelector {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <AggrColorScaleSelector {...layerConfiguratorProps} /> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> {layer.visConfigSettings.colorAggregation.condition( layer.config ) ? ( <AggregationTypeSelector {...layer.visConfigSettings.colorAggregation} {...layerChannelConfigProps} descreiption={colorByDescription} channel={layer.visualChannels.color} /> ) : null} <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Fill */} {featureTypes.polygon ? ( <LayerConfigGroup label={'fill'} {...visConfiguratorProps} {...layer.visConfigSettings.filled} /> ) : null} {/* Stroke Width */} {featureTypes.line || featureTypes.polygon ? ( <LayerConfigGroup label="stroke" {...visConfiguratorProps} {...(featureTypes.polygon ? LAYER_VIS_CONFIGS.stroked : {})} collapsible > <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> </LayerConfigGroup> ) : null} {/* high precision */} {/* <LayerConfigGroup {...LAYER_VIS_CONFIGS['hi-precision']} {...visConfiguratorProps} /> */} </StyledLayerVisualConfigurator> ); } _renderGeoBoundaryPointLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; return ( <StyledLayerVisualConfigurator> {/* Fill Color */} {featureTypes.polygon || featureTypes.point ? ( <LayerConfigGroup {...layer.visConfigSettings.filled} {...visConfiguratorProps} label="Fill Color" collapsible > {layer.config.colorField ? ( <LayerColorRangeSelector {...visConfiguratorProps} /> ) : ( <LayerColorSelector {...layerConfiguratorProps} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* Stroke Width */} {featureTypes.line || featureTypes.point ? ( <LayerConfigGroup label="stroke" {...visConfiguratorProps} {...(featureTypes.polygon ? LAYER_VIS_CONFIGS.stroked : {})} collapsible > <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> </LayerConfigGroup> ) : null} </StyledLayerVisualConfigurator> ); } _renderAdminBoundaryLayerConfig({ layer, visConfiguratorProps, layerConfiguratorProps, layerChannelConfigProps }) { const { meta: {featureTypes = {}}, config: {visConfig} } = layer; const {enable3d} = visConfig; const elevationByDescription = 'When off, height is based on count of points'; const colorByDescription = 'When off, color is based on count of points'; return ( <StyledLayerVisualConfigurator> <LayerConfigGroup label={layer.type === 'boundary' ? 'boundary' : ''}> <BoundaryTypeSelector {...layer.visConfigSettings.colorAggregation} {...layerConfiguratorProps} descreiption={colorByDescription} channel={layer.visualChannels.color} /> </LayerConfigGroup> {/* Color By */} <LayerConfigGroup label={'color'} collapsible> <ColorRangeConfig {...visConfiguratorProps} /> <ConfigGroupCollapsibleContent> <AggrColorScaleSelector {...layerConfiguratorProps} /> <ChannelByValueSelector channel={layer.visualChannels.color} {...layerChannelConfigProps} /> {layer.visConfigSettings.colorAggregation.condition( layer.config ) ? ( <AggregationTypeSelector {...layer.visConfigSettings.colorAggregation} {...layerChannelConfigProps} descreiption={colorByDescription} channel={layer.visualChannels.color} /> ) : null} <VisConfigSlider {...LAYER_VIS_CONFIGS.opacity} {...visConfiguratorProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> {/* Fill */} {featureTypes.polygon ? ( <LayerConfigGroup label={'fill'} {...visConfiguratorProps} {...LAYER_VIS_CONFIGS.filled} /> ) : null} {/* Stroke Width */} {featureTypes.line || featureTypes.polygon ? ( <LayerConfigGroup label="stroke" {...visConfiguratorProps} {...(featureTypes.polygon ? LAYER_VIS_CONFIGS.stroked : {})} collapsible > <VisConfigSlider {...LAYER_VIS_CONFIGS.thickness} {...visConfiguratorProps} label={false} /> </LayerConfigGroup> ) : null} {/* Elevation */} {featureTypes.polygon && visConfig.filled ? ( <LayerConfigGroup {...visConfiguratorProps} {...LAYER_VIS_CONFIGS.enable3d} collapsible > <VisConfigSlider {...LAYER_VIS_CONFIGS.elevationScale} {...visConfiguratorProps} label={false} /> <ConfigGroupCollapsibleContent> <ChannelByValueSelector {...layerChannelConfigProps} channel={layer.visualChannels.height} description={elevationByDescription} disabled={!enable3d} /> {layer.visConfigSettings.heightAggregation.condition( layer.config ) ? ( <AggregationTypeSelector {...layer.visConfigSettings.sizeAggregation} {...layerChannelConfigProps} channel={layer.visualChannels.height} /> ) : null} </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* Radius */} {featureTypes.point ? ( <LayerConfigGroup label={'radius'} collapsible> {!layer.config.radiusField ? ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radius} {...visConfiguratorProps} label={false} disabled={Boolean(layer.config.radiusField)} /> ) : ( <VisConfigSlider {...LAYER_VIS_CONFIGS.radiusRange} {...visConfiguratorProps} label={false} disabled={!layer.config.radiusField} /> )} <ConfigGroupCollapsibleContent> <ChannelByValueSelector channel={layer.visualChannels.radius} {...layerChannelConfigProps} /> </ConfigGroupCollapsibleContent> </LayerConfigGroup> ) : null} {/* high precision */} {/* <LayerConfigGroup {...LAYER_VIS_CONFIGS['hi-precision']} {...visConfiguratorProps} /> */} </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={'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={false} dataId={config.dataId} onSelect={value => updateLayerConfig({dataId: value})} /> )} {layer.shouldRenderColumnConfig() ? ( <LayerColumnConfig layer={layer} fields={fields} fieldPairs={fieldPairs} updateLayerConfig={updateLayerConfig} updateLayerType={this.props.updateLayerType} /> ) : null} </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}> How to </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, supportedFieldTypes } = channel; var {defaultMeasure} = channel; //inside dynamic layer point will have no default measure as there is no aggregation if (layer.meta.featureTypes && layer.meta.featureTypes.point) { // inside dynamic layer point will have no default measure as there is no aggregation // if (layer.meta.featureTypes.point) { defaultMeasure = null; } 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 = `Calculate ${property} based on selected field`; 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 || 'Select a field'} 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>{`Aggregate ${selectedField.name} by`}</PanelLabel> <ItemSelector selectedItems={visConfig[aggregation]} options={aggregationOptions} multiSelect={false} searchable={false} onChange={value => onChange( { visConfig: { ...layer.config.visConfig, [aggregation]: value } }, channel.key ) } /> </SidePanelSection> ); }; export const ColorRangeConfig = ({layer, onChange}) => ( <SidePanelSection> <ColorSelector colorSets={[ { selectedColor: layer.config.visConfig.colorRange, isRange: true, setColor: colorRange => onChange({colorRange}) } ]} /> </SidePanelSection> ); export const AggrColorScaleSelector = ({layer, onChange}) => { const scaleOptions = layer.getScaleOptions('color'); return Array.isArray(scaleOptions) && sc