@carto/kepler.gl 0.0.70 → 0.0.71-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +938 -0
  2. package/dist/components/common/item-selector/accessor.js +2 -2
  3. package/dist/components/common/item-selector/dropdown-list.js +10 -8
  4. package/dist/components/common/item-selector/item-selector.js +2 -2
  5. package/dist/components/side-panel/layer-panel/color-range-selector.js +43 -8
  6. package/dist/components/side-panel/layer-panel/color-selector.js +7 -1
  7. package/dist/components/side-panel/layer-panel/hex-column-config.js +84 -0
  8. package/dist/components/side-panel/layer-panel/layer-configurator.js +30 -10
  9. package/dist/constants/color-ranges.js +12 -2
  10. package/dist/constants/default-settings.js +2 -2
  11. package/dist/layers/base-layer.js +138 -44
  12. package/dist/layers/point-layer/point-layer.js +2 -3
  13. package/dist/localization/en.js +5 -2
  14. package/dist/reducers/vis-state-merger.js +16 -2
  15. package/dist/schemas/vis-state-schema.js +2 -2
  16. package/package.json +1 -1
  17. package/src/components/common/item-selector/accessor.js +1 -1
  18. package/src/components/common/item-selector/dropdown-list.js +24 -15
  19. package/src/components/common/item-selector/item-selector.js +1 -1
  20. package/src/components/side-panel/layer-panel/color-range-selector.js +37 -8
  21. package/src/components/side-panel/layer-panel/color-selector.js +7 -0
  22. package/src/components/side-panel/layer-panel/hex-column-config.js +40 -0
  23. package/src/components/side-panel/layer-panel/layer-configurator.js +50 -6
  24. package/src/constants/color-ranges.js +9 -0
  25. package/src/layers/base-layer.js +92 -26
  26. package/src/layers/layer-factory.d.ts +1 -0
  27. package/src/layers/point-layer/point-layer.js +1 -1
  28. package/src/localization/en.js +4 -1
  29. package/src/reducers/vis-state-merger.js +13 -1
  30. package/src/schemas/vis-state-schema.js +1 -1
@@ -29,16 +29,18 @@ import {PanelLabel, Button, Tooltip} from 'components/common/styled-components';
29
29
  import Switch from 'components/common/switch';
30
30
  import ColorPalette from './color-palette';
31
31
  import CustomPalette from './custom-palette';
32
- import {COLOR_RANGES} from 'constants/color-ranges';
32
+ import {COLOR_RANGES, hexColor} from 'constants/color-ranges';
33
33
  import {numberSort} from 'utils/data-utils';
34
34
  import {reverseColorRange} from 'utils/color-utils';
35
35
  import {FormattedMessage} from 'localization';
36
36
  import {SwapHorizontal} from 'components/common/icons';
37
+ import HexColumnConfig from './hex-column-config';
37
38
 
38
39
  export const ALL_TYPES = uniq([
39
40
  'all',
40
41
  ...COLOR_RANGES.map(c => c.type).filter(ctype => ctype),
41
- 'custom'
42
+ 'custom',
43
+ {value: hexColor, divider: true}
42
44
  ]);
43
45
 
44
46
  export const ALL_STEPS = uniq(COLOR_RANGES.map(d => d.colors.length)).sort(numberSort);
@@ -95,9 +97,11 @@ ColorRangeSelectFactory.deps = [ColorPaletteGroupFactory, PaletteConfigFactory];
95
97
  export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig) {
96
98
  class ColorRangeSelect extends Component {
97
99
  static propTypes = {
100
+ fields: PropTypes.arrayOf(PropTypes.any),
98
101
  colorPaletteUI: PropTypes.object.isRequired,
99
102
  selectedColorRange: PropTypes.object.isRequired,
100
103
  onSelectColorRange: PropTypes.func.isRequired,
104
+ onSelectColorColumn: PropTypes.func.isRequired,
101
105
  setColorPaletteUI: PropTypes.func.isRequired,
102
106
  // optional
103
107
  colorRanges: PropTypes.arrayOf(PropTypes.any)
@@ -119,7 +123,7 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
119
123
  (colorRanges, type, steps) => {
120
124
  return colorRanges.filter(colorRange => {
121
125
  const isType = type === 'all' || type === colorRange.type;
122
- const isStep = Number(steps) === colorRange.colors.length;
126
+ const isStep = Number(steps || 6) === colorRange.colors.length;
123
127
 
124
128
  return isType && isStep;
125
129
  });
@@ -129,7 +133,7 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
129
133
  _updateConfig = ({key, value}) => {
130
134
  this._setColorRangeConfig({
131
135
  [key]: value,
132
- ...(key === 'type' && {custom: value === 'custom'})
136
+ ...(key === 'type' && {custom: value === 'custom', hexColumn: value === hexColor})
133
137
  });
134
138
  };
135
139
 
@@ -139,6 +143,12 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
139
143
  });
140
144
  };
141
145
 
146
+ _onSetHexColorColumn = config => {
147
+ this.props.setColorPaletteUI({
148
+ customPalette: config
149
+ });
150
+ };
151
+
142
152
  _setColorRangeConfig = newConfig => {
143
153
  this.props.setColorPaletteUI({
144
154
  colorRangeConfig: newConfig
@@ -148,7 +158,7 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
148
158
  _onCustomPaletteCancel = newConfig => {
149
159
  this.props.setColorPaletteUI({
150
160
  showSketcher: false,
151
- colorRangeConfig: {custom: false}
161
+ colorRangeConfig: {custom: false, hexColumn: false}
152
162
  });
153
163
  };
154
164
 
@@ -158,6 +168,18 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
158
168
  });
159
169
  };
160
170
 
171
+ _onSelectColumn = column => {
172
+ this.props.onSelectColorColumn(column);
173
+ this._setColorRangeConfig({
174
+ type: hexColor,
175
+ hexColumn: column?.name
176
+ });
177
+ };
178
+
179
+ _handleOnChangePaletteType = ({key, value}) => {
180
+ this._updateConfig({key, value});
181
+ };
182
+
161
183
  render() {
162
184
  const {customPalette, showSketcher, colorRangeConfig} = this.props.colorPaletteUI;
163
185
  const filteredColorRanges = this.filteredColorRange(this.props);
@@ -168,7 +190,8 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
168
190
  {Object.keys(colorRangeConfig)
169
191
  .filter(
170
192
  key =>
171
- Boolean(CONFIG_SETTINGS[key]) && (colorRangeConfig.custom ? key === 'type' : true)
193
+ Boolean(CONFIG_SETTINGS[key]) &&
194
+ (colorRangeConfig.custom || colorRangeConfig.hexColumn ? key === 'type' : true)
172
195
  )
173
196
  .map(key => {
174
197
  return (
@@ -176,8 +199,8 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
176
199
  key={key}
177
200
  label={CONFIG_SETTINGS[key].label || key}
178
201
  config={CONFIG_SETTINGS[key]}
179
- value={colorRangeConfig[key]}
180
- onChange={value => this._updateConfig({key, value})}
202
+ value={colorRangeConfig[key] || 6}
203
+ onChange={value => this._handleOnChangePaletteType({key, value})}
181
204
  />
182
205
  );
183
206
  })}
@@ -193,6 +216,12 @@ export default function ColorRangeSelectFactory(ColorPaletteGroup, PaletteConfig
193
216
  setCustomPalette={this._onSetCustomPalette}
194
217
  onCancel={this._onCustomPaletteCancel}
195
218
  />
219
+ ) : colorRangeConfig.hexColumn ? (
220
+ <HexColumnConfig
221
+ fields={this.props.fields}
222
+ value={colorRangeConfig.hexColumn}
223
+ onSelectColumn={this._onSelectColumn}
224
+ />
196
225
  ) : (
197
226
  <ColorPaletteGroup
198
227
  colorRanges={filteredColorRanges}
@@ -64,6 +64,7 @@ ColorSelectorFactory.deps = [SingleColorPaletteFactory, ColorRangeSelectFactory]
64
64
  function ColorSelectorFactory(SingleColorPalette, ColorRangeSelector) {
65
65
  class ColorSelector extends Component {
66
66
  static propTypes = {
67
+ fields: PropTypes.arrayOf(PropTypes.any),
67
68
  colorSets: PropTypes.arrayOf(
68
69
  PropTypes.shape({
69
70
  selectedColor: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.any), PropTypes.object]),
@@ -124,6 +125,10 @@ function ColorSelectorFactory(SingleColorPalette, ColorRangeSelector) {
124
125
  }
125
126
  };
126
127
 
128
+ _onSelectColorColumn = column => {
129
+ this.props.onSelectHexColorColumn(column);
130
+ };
131
+
127
132
  _showDropdown = (e, i) => {
128
133
  e.stopPropagation();
129
134
  e.preventDefault();
@@ -172,7 +177,9 @@ function ColorSelectorFactory(SingleColorPalette, ColorRangeSelector) {
172
177
  <ColorRangeSelector
173
178
  selectedColorRange={colorSets[editing].selectedColor}
174
179
  onSelectColorRange={this._onSelectColor}
180
+ onSelectColorColumn={this._onSelectColorColumn}
175
181
  setColorPaletteUI={this.props.setColorUI}
182
+ fields={this.props.fields}
176
183
  colorPaletteUI={colorUI}
177
184
  />
178
185
  ) : (
@@ -0,0 +1,40 @@
1
+ import {FieldSelector} from 'components';
2
+ import PropTypes from 'prop-types';
3
+ import {PanelLabel} from 'components/common/styled-components';
4
+ import {FormattedMessage} from 'localization';
5
+ import React, {Component} from 'react';
6
+
7
+ class HexColumnConfig extends Component {
8
+ static propTypes = {
9
+ fields: PropTypes.arrayOf(PropTypes.any),
10
+ value: PropTypes.string,
11
+ onSelectColumn: PropTypes.func.isRequired
12
+ };
13
+
14
+ render() {
15
+ const {fields, value, onSelectColumn} = this.props;
16
+
17
+ return (
18
+ <>
19
+ <div className="color-palette__config__label">
20
+ <PanelLabel>
21
+ <FormattedMessage id={`color.hexColumn.field`} />
22
+ </PanelLabel>
23
+ </div>
24
+ <div>
25
+ <FieldSelector
26
+ fields={fields}
27
+ value={value}
28
+ placeholder={''}
29
+ onSelect={onSelectColumn}
30
+ erasable
31
+ onFocus={() => null}
32
+ onBlur={() => null}
33
+ />
34
+ </div>
35
+ </>
36
+ );
37
+ }
38
+ }
39
+
40
+ export default HexColumnConfig;
@@ -47,6 +47,7 @@ import {injectIntl} from 'react-intl';
47
47
  import ColorDimensionScaleSelectorFactory from './color-dimension-scale-selector';
48
48
  import ColorSelectorFactory from './color-selector';
49
49
  import LayerAggregationResolutionFactory from './layer-aggregation-resolution';
50
+ import {hexColorCustomPalette} from 'constants/color-ranges';
50
51
 
51
52
  const StyledLayerConfigurator = styled.div.attrs({
52
53
  className: 'layer-panel__config'
@@ -172,6 +173,8 @@ export default function LayerConfiguratorFactory(
172
173
  channel={layer.visualChannels.color}
173
174
  {...layerChannelConfigProps}
174
175
  />
176
+ </ConfigGroupCollapsibleContent>
177
+ <ConfigGroupCollapsibleContent>
175
178
  <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} />
176
179
  </ConfigGroupCollapsibleContent>
177
180
  </LayerConfigGroup>
@@ -185,7 +188,11 @@ export default function LayerConfiguratorFactory(
185
188
  disabled={Boolean(layer.config.visConfig.customMarkers)}
186
189
  >
187
190
  {layer.config.strokeColorField ? (
188
- <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" />
191
+ <LayerColorRangeSelector
192
+ {...visConfiguratorProps}
193
+ property="strokeColorRange"
194
+ field="strokeColorField"
195
+ />
189
196
  ) : (
190
197
  <LayerColorSelector
191
198
  {...visConfiguratorProps}
@@ -701,7 +708,11 @@ export default function LayerConfiguratorFactory(
701
708
  collapsible
702
709
  >
703
710
  {layer.config.strokeColorField ? (
704
- <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" />
711
+ <LayerColorRangeSelector
712
+ {...visConfiguratorProps}
713
+ property="strokeColorRange"
714
+ field="strokeColorField"
715
+ />
705
716
  ) : (
706
717
  <LayerColorSelector
707
718
  {...visConfiguratorProps}
@@ -884,7 +895,11 @@ export default function LayerConfiguratorFactory(
884
895
  collapsible
885
896
  >
886
897
  {layer.config.strokeColorField ? (
887
- <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" />
898
+ <LayerColorRangeSelector
899
+ {...visConfiguratorProps}
900
+ property="strokeColorRange"
901
+ field="strokeColorField"
902
+ />
888
903
  ) : (
889
904
  <LayerColorSelector
890
905
  {...visConfiguratorProps}
@@ -1048,13 +1063,14 @@ LayerColorSelectorFactory.deps = [ColorSelectorFactory];
1048
1063
  export function LayerColorSelectorFactory(ColorSelector) {
1049
1064
  class LayerColorSelector extends Component {
1050
1065
  render() {
1051
- const {layer, onChange, selectedColor, property = 'color', setColorUI} = this.props;
1066
+ const {layer, onChange, selectedColor, property = 'color', setColorUI, fields} = this.props;
1052
1067
  return (
1053
1068
  <SidePanelSection>
1054
1069
  <PanelLabel>
1055
1070
  <FormattedMessage id="layer.color" />
1056
1071
  </PanelLabel>
1057
1072
  <ColorSelector
1073
+ fields={fields}
1058
1074
  colorSets={[
1059
1075
  {
1060
1076
  selectedColor: selectedColor || layer.config.color,
@@ -1076,13 +1092,22 @@ ArcLayerColorSelectorFactory.deps = [ColorSelectorFactory];
1076
1092
  export function ArcLayerColorSelectorFactory(ColorSelector) {
1077
1093
  class ArcLayerColorSelector extends Component {
1078
1094
  render() {
1079
- const {layer, onChangeConfig, onChangeVisConfig, property = 'color', setColorUI} = this.props;
1095
+ const {
1096
+ layer,
1097
+ onChangeConfig,
1098
+ onChangeVisConfig,
1099
+ property = 'color',
1100
+ setColorUI,
1101
+ fields
1102
+ } = this.props;
1103
+
1080
1104
  return (
1081
1105
  <SidePanelSection>
1082
1106
  <PanelLabel>
1083
1107
  <FormattedMessage id="layer.colorRange" />
1084
1108
  </PanelLabel>
1085
1109
  <ColorSelector
1110
+ fields={fields}
1086
1111
  colorSets={[
1087
1112
  {
1088
1113
  selectedColor: layer.config.color,
@@ -1109,13 +1134,21 @@ LayerColorRangeSelectorFactory.deps = [ColorSelectorFactory];
1109
1134
  export function LayerColorRangeSelectorFactory(ColorSelector) {
1110
1135
  class LayerColorRangeSelector extends Component {
1111
1136
  render() {
1112
- const {layer, onChange, property = 'colorRange', setColorUI} = this.props;
1137
+ const {
1138
+ layer,
1139
+ onChange,
1140
+ property = 'colorRange',
1141
+ field = 'colorField',
1142
+ setColorUI,
1143
+ fields
1144
+ } = this.props;
1113
1145
  return (
1114
1146
  <SidePanelSection>
1115
1147
  <PanelLabel>
1116
1148
  <FormattedMessage id="layer.colorRange" />
1117
1149
  </PanelLabel>
1118
1150
  <ColorSelector
1151
+ fields={fields}
1119
1152
  colorSets={[
1120
1153
  {
1121
1154
  selectedColor: layer.config.visConfig[property],
@@ -1131,6 +1164,17 @@ export function LayerColorRangeSelectorFactory(ColorSelector) {
1131
1164
  ]}
1132
1165
  colorUI={layer.config.colorUI[property]}
1133
1166
  setColorUI={newConfig => setColorUI(property, newConfig)}
1167
+ onSelectHexColorColumn={colorColumn => {
1168
+ layer.updateLayerConfig({
1169
+ [field]: {
1170
+ ...layer.config[field],
1171
+ colorColumn: colorColumn?.name,
1172
+ colorColumnIdx: colorColumn?.fieldIdx
1173
+ }
1174
+ });
1175
+
1176
+ onChange({[property]: hexColorCustomPalette});
1177
+ }}
1134
1178
  />
1135
1179
  </SidePanelSection>
1136
1180
  );
@@ -61,3 +61,12 @@ export const DEFAULT_COLOR_RANGE = colorRanges.find(({name}) => name === 'Global
61
61
  category: 'Uber',
62
62
  colors: ['#5A1846', '#900C3F', '#C70039', '#E3611C', '#F1920E', '#FFC300']
63
63
  };
64
+
65
+ export const hexColor = 'hexColor';
66
+ export const hexColorCustomPalette = {
67
+ name: hexColor,
68
+ type: hexColor,
69
+ colors: [],
70
+ category: 'CARTO',
71
+ hexColor: true
72
+ };
@@ -38,7 +38,7 @@ import {
38
38
  UNKNOWN_COLOR,
39
39
  ZOOM_LEVEL_LIMITS
40
40
  } from 'constants/default-settings';
41
- import {COLOR_RANGES} from 'constants/color-ranges';
41
+ import {COLOR_RANGES, hexColor} from 'constants/color-ranges';
42
42
  import {DataVizColors} from 'constants/custom-color-ranges';
43
43
  import {
44
44
  LAYER_VIS_CONFIGS,
@@ -100,7 +100,6 @@ export const colorMaker = generateColor();
100
100
  class Layer {
101
101
  constructor(props = {}) {
102
102
  this.id = props.id || generateHashId(LAYER_ID_LENGTH);
103
-
104
103
  // meta
105
104
  this.meta = {};
106
105
 
@@ -609,8 +608,9 @@ class Layer {
609
608
  };
610
609
 
611
610
  this.updateLayerConfig({colorUI});
612
- // if colorUI[prop] is colorRange
613
- const isColorRange = visConfig[prop] && visConfig[prop].colors;
611
+ // if colorUI[prop] is colorRange. If type is hexColor then it's also a range
612
+ const isColorRange =
613
+ visConfig[prop] && (visConfig[prop].colors || visConfig[prop].type === hexColor);
614
614
 
615
615
  if (isColorRange) {
616
616
  this.updateColorUIByColorRange(newConfig, prop);
@@ -663,8 +663,9 @@ class Layer {
663
663
  colorRangeConfig: {
664
664
  ...colorUI[prop].colorRangeConfig,
665
665
  type: visConfig[prop].type,
666
- steps: visConfig[prop].colors.length,
667
- reversed: Boolean(visConfig[prop].reversed)
666
+ steps: visConfig[prop].colors?.length,
667
+ reversed: Boolean(visConfig[prop].reversed),
668
+ hexColumn: this.isColoredByColorColumn(prop)
668
669
  }
669
670
  }
670
671
  }
@@ -732,6 +733,12 @@ class Layer {
732
733
  updateCategoryColorMap(colorMap, domain, colorRange) {
733
734
  const colors = colorRange.colors;
734
735
  const assignedCategories = [];
736
+ if (colorRange.type === hexColor) {
737
+ return {
738
+ ...colorRange,
739
+ colorMap: []
740
+ };
741
+ }
735
742
  const newColorMap = colorMap.slice(0, colors.length).map((cMap, index) => {
736
743
  assignedCategories.push(cMap[0]);
737
744
  return [cMap[0], colors[index]];
@@ -821,7 +828,11 @@ class Layer {
821
828
  }
822
829
 
823
830
  getColorScale(colorScale, colorDomain, colorRange) {
824
- if (Array.isArray(colorRange.colorMap)) {
831
+ if (colorRange.type === hexColor) {
832
+ return (_, color) => {
833
+ return hexToRgb(color);
834
+ };
835
+ } else if (Array.isArray(colorRange.colorMap)) {
825
836
  const cMap = new Map();
826
837
  colorRange.colorMap.forEach(([k, v]) => {
827
838
  cMap.set(k, typeof v === 'string' ? hexToRgb(v) : v);
@@ -914,13 +925,15 @@ class Layer {
914
925
  : this.getVisChannelScale(...args, isFixed);
915
926
 
916
927
  attributeAccessors[accessor] = d =>
917
- this.getEncodedChannelValue(
918
- scaleFunction,
919
- dataAccessor(dataContainer)(d),
920
- fieldConfig,
921
- aggregationValue,
928
+ this.getEncodedChannelValue({
929
+ channel,
930
+ dataContainer,
931
+ scale: scaleFunction,
932
+ data: dataAccessor(dataContainer)(d),
933
+ field: fieldConfig,
934
+ _aggregation: aggregationValue,
922
935
  nullValue
923
- );
936
+ });
924
937
  } else if (typeof getAttributeValue === 'function') {
925
938
  attributeAccessors[accessor] = getAttributeValue(this.config);
926
939
  } else {
@@ -990,17 +1003,35 @@ class Layer {
990
1003
  return triggerChanged;
991
1004
  }
992
1005
 
993
- getEncodedChannelValue(
1006
+ getEncodedChannelValue({
1007
+ channel,
994
1008
  scale,
995
1009
  data,
996
1010
  field,
1011
+ dataContainer,
997
1012
  // In builder we overwrite the getValue function and we use the _aggregation parameter in spatial index layers as the QuadkeyLayer.
998
1013
  _aggregation,
999
1014
  nullValue = NO_VALUE_COLOR,
1000
1015
  getValue = defaultGetFieldValue
1001
- ) {
1016
+ }) {
1017
+ let colorColumnValue;
1002
1018
  const {type} = field;
1003
1019
  const value = getValue(field, data);
1020
+ const channelConfig = this.config.visConfig[this.visualChannels[channel].range];
1021
+ const channelField = this.config[this.visualChannels[channel].field];
1022
+
1023
+ if (channelConfig.type === hexColor) {
1024
+ const columnField = {
1025
+ id: channelField.colorColumn,
1026
+ name: channelField.colorColumn,
1027
+ fieldIdx: channelField.colorColumnIdx,
1028
+ valueAccessor: d => {
1029
+ return dataContainer.valueAt(d.index, channelField.colorColumnIdx);
1030
+ }
1031
+ };
1032
+
1033
+ colorColumnValue = getValue(columnField, data);
1034
+ }
1004
1035
 
1005
1036
  if (!notNullorUndefined(value)) {
1006
1037
  return nullValue;
@@ -1010,9 +1041,9 @@ class Layer {
1010
1041
  if (type === ALL_FIELD_TYPES.timestamp) {
1011
1042
  // shouldn't need to convert here
1012
1043
  // scale Function should take care of it
1013
- attributeValue = scale(new Date(value));
1044
+ attributeValue = scale(new Date(value), colorColumnValue);
1014
1045
  } else {
1015
- attributeValue = scale(value);
1046
+ attributeValue = scale(value, colorColumnValue);
1016
1047
  }
1017
1048
 
1018
1049
  if (!notNullorUndefined(attributeValue)) {
@@ -1046,13 +1077,14 @@ class Layer {
1046
1077
  if (!this.config.dataId) {
1047
1078
  return {};
1048
1079
  }
1049
- const layerDataset = datasets[this.config.dataId];
1050
- const {dataContainer} = layerDataset;
1080
+ const dataset = this.getDataset(datasets);
1081
+ const {dataContainer} = dataset;
1051
1082
 
1052
- this.updateVisualChannelFields(layerDataset);
1083
+ this.updateVisualChannelFields(dataset);
1084
+ this.updateHexColorDomain(dataset);
1053
1085
 
1054
1086
  const getPosition = this.getPositionAccessor(dataContainer);
1055
- const dataUpdateTriggers = this.getDataUpdateTriggers(layerDataset);
1087
+ const dataUpdateTriggers = this.getDataUpdateTriggers(dataset);
1056
1088
  const triggerChanged = this.getChangedTriggers(dataUpdateTriggers);
1057
1089
 
1058
1090
  if (triggerChanged.getMeta) {
@@ -1065,7 +1097,7 @@ class Layer {
1065
1097
  // same data
1066
1098
  data = oldLayerData.data;
1067
1099
  } else {
1068
- data = this.calculateDataAttribute(layerDataset, getPosition);
1100
+ data = this.calculateDataAttribute(dataset, getPosition);
1069
1101
  }
1070
1102
 
1071
1103
  return {data, triggerChanged};
@@ -1077,12 +1109,20 @@ class Layer {
1077
1109
  * @param {Object} dataset
1078
1110
  */
1079
1111
  updateVisualChannelFields(dataset) {
1080
- for (const {field} of Object.values(this.visualChannels)) {
1112
+ for (const {field, range} of Object.values(this.visualChannels)) {
1081
1113
  const oldField = this.config[field];
1114
+ const isUsingHexColorCode = this.config.visConfig[range].hexColor
1082
1115
  if (!oldField) {
1083
1116
  return;
1084
1117
  }
1085
- const newDataSetField = dataset.fields.find(fd => fd.name === oldField.name) || null;
1118
+ let newDataSetField = dataset.fields.find(fd => fd.name === oldField.name) || null;
1119
+ if (isUsingHexColorCode) {
1120
+ newDataSetField = {
1121
+ ...newDataSetField,
1122
+ colorColumn: newDataSetField.colorColumn || oldField.colorColumn,
1123
+ colorColumnIdx: newDataSetField.colorColumnIdx || oldField.colorColumnIdx
1124
+ };
1125
+ }
1086
1126
  this.updateLayerConfig({[field]: newDataSetField});
1087
1127
  }
1088
1128
  }
@@ -1103,6 +1143,7 @@ class Layer {
1103
1143
  Object.values(this.visualChannels).forEach(channel => {
1104
1144
  const {scale} = channel;
1105
1145
  const scaleType = this.config[scale];
1146
+
1106
1147
  // ordinal domain is based on dataContainer, if only filter changed
1107
1148
  // no need to update ordinal domain
1108
1149
  if (!newFilter || scaleType !== SCALE_TYPES.ordinal) {
@@ -1224,6 +1265,24 @@ class Layer {
1224
1265
  return dataset.getColumnLayerDomain(dataSetField, scaleType) || defaultDomain;
1225
1266
  }
1226
1267
 
1268
+ updateHexColorDomain(dataset) {
1269
+ if (!dataset) {
1270
+ return this;
1271
+ }
1272
+ Object.values(this.visualChannels).forEach(channel => {
1273
+ const channelConfig = this.config.visConfig[channel.range];
1274
+ const field = this.config[channel.field];
1275
+
1276
+ if (channelConfig?.type === hexColor) {
1277
+ const dataSetField = dataset.fields.find(f => f.name === field.colorColumn);
1278
+ const colors = dataset.getColumnLayerDomain(dataSetField, SCALE_TYPES.ordinal);
1279
+ this.updateLayerVisConfig({[channel.range]: {...channelConfig, colors}});
1280
+ }
1281
+ });
1282
+
1283
+ return this;
1284
+ }
1285
+
1227
1286
  hasHoveredObject(objectInfo) {
1228
1287
  return this.isLayerHovered(objectInfo) && objectInfo.object ? objectInfo.object : null;
1229
1288
  }
@@ -1251,9 +1310,9 @@ class Layer {
1251
1310
 
1252
1311
  if (!radiusChannel || this.config[radiusChannel.field]) {
1253
1312
  return 1;
1254
- } else {
1255
- return this.config.visConfig.radius;
1256
1313
  }
1314
+
1315
+ return this.config.visConfig.radius;
1257
1316
  }
1258
1317
 
1259
1318
  getMaxMarkerSize() {
@@ -1434,6 +1493,13 @@ class Layer {
1434
1493
  // implemented in subclasses
1435
1494
  return () => null;
1436
1495
  }
1496
+
1497
+ isColoredByColorColumn(range) {
1498
+ const field = Object.values(this.visualChannels)?.find(value => value.range === range)?.field;
1499
+ if (field) {
1500
+ return this.config[field].colorColumn;
1501
+ }
1502
+ }
1437
1503
  }
1438
1504
 
1439
1505
  export default Layer;
@@ -31,6 +31,7 @@ export type ColorUI = {
31
31
  steps: number;
32
32
  reversed: boolean;
33
33
  custom: boolean;
34
+ hexColumn: boolean;
34
35
  };
35
36
  };
36
37
 
@@ -238,7 +238,7 @@ export default class PointLayer extends Layer {
238
238
  formatLayerData(datasets, oldLayerData) {
239
239
  const {textLabel} = this.config;
240
240
  const {gpuFilter, dataContainer} = datasets[this.config.dataId];
241
- const {data, triggerChanged} = this.updateData(datasets, oldLayerData);
241
+ const {data} = this.updateData(datasets, oldLayerData);
242
242
  const getPosition = this.getPositionAccessor(dataContainer);
243
243
 
244
244
  // get all distinct characters in the text labels
@@ -448,7 +448,10 @@ export default {
448
448
  customPalette: 'Custom Palette',
449
449
  steps: 'steps',
450
450
  type: 'type',
451
- reversed: 'reversed'
451
+ reversed: 'reversed',
452
+ hexColumn: {
453
+ field: 'Color field'
454
+ }
452
455
  },
453
456
  customPalette: {
454
457
  apply: 'Apply',
@@ -423,6 +423,7 @@ export function validateSavedTextLabel(fields, [layerTextLabel], savedTextLabel)
423
423
  export function validateSavedVisualChannels(fields, newLayer, savedLayer) {
424
424
  Object.values(newLayer.visualChannels).forEach(({field, scale, key}) => {
425
425
  let foundField;
426
+ const colorFieldProps = {};
426
427
  if (savedLayer.config) {
427
428
  if (savedLayer.config[field]) {
428
429
  foundField = fields.find(
@@ -430,8 +431,19 @@ export function validateSavedVisualChannels(fields, newLayer, savedLayer) {
430
431
  );
431
432
  }
432
433
 
434
+ if (savedLayer.config[field]?.colorColumn) {
435
+ const colorColumnField = fields.find(
436
+ fd => savedLayer.config && fd.name === savedLayer.config[field].colorColumn
437
+ );
438
+
439
+ if (colorColumnField) {
440
+ colorFieldProps.colorColumn = colorColumnField.name;
441
+ colorFieldProps.colorColumnIdx = colorColumnField.fieldIdx;
442
+ }
443
+ }
444
+
433
445
  const foundChannel = {
434
- ...(foundField ? {[field]: foundField} : {}),
446
+ ...(foundField ? {[field]: {...foundField, ...colorFieldProps}} : {}),
435
447
  ...(savedLayer.config[scale] ? {[scale]: savedLayer.config[scale]} : {})
436
448
  };
437
449
  if (Object.keys(foundChannel).length) {
@@ -340,7 +340,7 @@ class VisualChannelSchemaV1 extends Schema {
340
340
  (accu, key) => ({
341
341
  ...accu,
342
342
  [visualChannels[key].field]: layer.config[visualChannels[key].field]
343
- ? pick(layer.config[visualChannels[key].field], ['name', 'type'])
343
+ ? pick(layer.config[visualChannels[key].field], ['name', 'type', 'colorColumn'])
344
344
  : null,
345
345
  [visualChannels[key].scale]: layer.config[visualChannels[key].scale]
346
346
  }),