@carto/kepler.gl 0.0.71-alpha.1 → 0.0.71-alpha.3

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 (37) hide show
  1. package/dist/components/common/item-selector/accessor.js +2 -2
  2. package/dist/components/common/item-selector/dropdown-list.js +10 -8
  3. package/dist/components/common/item-selector/item-selector.js +2 -2
  4. package/dist/components/side-panel/layer-panel/color-range-selector.js +43 -8
  5. package/dist/components/side-panel/layer-panel/color-selector.js +7 -1
  6. package/dist/components/side-panel/layer-panel/hex-column-config.js +84 -0
  7. package/dist/components/side-panel/layer-panel/layer-configurator.js +45 -34
  8. package/dist/components/side-panel/layer-panel/vis-config-by-field-selector.js +2 -4
  9. package/dist/constants/color-ranges.js +12 -2
  10. package/dist/constants/default-settings.js +8 -8
  11. package/dist/layers/base-layer.js +111 -25
  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/dist/utils/custom-scales.js +28 -0
  17. package/dist/utils/table-utils/kepler-table.js +1 -2
  18. package/package.json +3 -3
  19. package/src/components/common/item-selector/accessor.js +1 -1
  20. package/src/components/common/item-selector/dropdown-list.js +24 -15
  21. package/src/components/common/item-selector/item-selector.js +1 -1
  22. package/src/components/side-panel/layer-panel/color-range-selector.js +37 -8
  23. package/src/components/side-panel/layer-panel/color-selector.js +7 -0
  24. package/src/components/side-panel/layer-panel/hex-column-config.js +40 -0
  25. package/src/components/side-panel/layer-panel/layer-configurator.js +68 -34
  26. package/src/components/side-panel/layer-panel/vis-config-by-field-selector.js +0 -2
  27. package/src/constants/color-ranges.js +9 -0
  28. package/src/constants/default-settings.js +8 -7
  29. package/src/layers/base-layer.js +93 -24
  30. package/src/layers/layer-factory.d.ts +1 -0
  31. package/src/layers/point-layer/point-layer.js +1 -1
  32. package/src/localization/en.js +4 -1
  33. package/src/reducers/vis-state-merger.js +13 -1
  34. package/src/schemas/vis-state-schema.js +1 -1
  35. package/src/utils/{custom-scale.js → custom-scales.js} +3 -5
  36. package/src/utils/table-utils/kepler-table.js +0 -1
  37. package/dist/utils/custom-scale.js +0 -30
@@ -41,12 +41,17 @@ import TextLabelPanelFactory from './text-label-panel';
41
41
 
42
42
  import {capitalizeFirstLetter} from 'utils/utils';
43
43
 
44
- import {CHANNEL_SCALES, CHANNEL_SCALE_SUPPORTED_FIELDS, SCALE_TYPES} from 'constants/default-settings';
44
+ import {
45
+ CHANNEL_SCALES,
46
+ CHANNEL_SCALE_SUPPORTED_FIELDS,
47
+ SCALE_TYPES
48
+ } from 'constants/default-settings';
45
49
  import {LAYER_TYPES} from 'layers/types';
46
50
  import {injectIntl} from 'react-intl';
47
51
  import ColorDimensionScaleSelectorFactory from './color-dimension-scale-selector';
48
52
  import ColorSelectorFactory from './color-selector';
49
53
  import LayerAggregationResolutionFactory from './layer-aggregation-resolution';
54
+ import {hexColorCustomPalette} from 'constants/color-ranges';
50
55
 
51
56
  const StyledLayerConfigurator = styled.div.attrs({
52
57
  className: 'layer-panel__config'
@@ -172,6 +177,8 @@ export default function LayerConfiguratorFactory(
172
177
  channel={layer.visualChannels.color}
173
178
  {...layerChannelConfigProps}
174
179
  />
180
+ </ConfigGroupCollapsibleContent>
181
+ <ConfigGroupCollapsibleContent>
175
182
  <VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} />
176
183
  </ConfigGroupCollapsibleContent>
177
184
  </LayerConfigGroup>
@@ -185,7 +192,11 @@ export default function LayerConfiguratorFactory(
185
192
  disabled={Boolean(layer.config.visConfig.customMarkers)}
186
193
  >
187
194
  {layer.config.strokeColorField ? (
188
- <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" />
195
+ <LayerColorRangeSelector
196
+ {...visConfiguratorProps}
197
+ property="strokeColorRange"
198
+ field="strokeColorField"
199
+ />
189
200
  ) : (
190
201
  <LayerColorSelector
191
202
  {...visConfiguratorProps}
@@ -701,7 +712,11 @@ export default function LayerConfiguratorFactory(
701
712
  collapsible
702
713
  >
703
714
  {layer.config.strokeColorField ? (
704
- <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" />
715
+ <LayerColorRangeSelector
716
+ {...visConfiguratorProps}
717
+ property="strokeColorRange"
718
+ field="strokeColorField"
719
+ />
705
720
  ) : (
706
721
  <LayerColorSelector
707
722
  {...visConfiguratorProps}
@@ -884,7 +899,11 @@ export default function LayerConfiguratorFactory(
884
899
  collapsible
885
900
  >
886
901
  {layer.config.strokeColorField ? (
887
- <LayerColorRangeSelector {...visConfiguratorProps} property="strokeColorRange" />
902
+ <LayerColorRangeSelector
903
+ {...visConfiguratorProps}
904
+ property="strokeColorRange"
905
+ field="strokeColorField"
906
+ />
888
907
  ) : (
889
908
  <LayerColorSelector
890
909
  {...visConfiguratorProps}
@@ -963,7 +982,6 @@ export default function LayerConfiguratorFactory(
963
982
  const layerConfiguratorProps = getLayerConfiguratorProps(this.props);
964
983
  const layerChannelConfigProps = getLayerChannelConfigProps(this.props);
965
984
  const dataset = getLayerDataset(datasets, layer);
966
- // TODO
967
985
  const renderTemplate = layer.type && `_render${capitalizeFirstLetter(layer.type)}LayerConfig`;
968
986
 
969
987
  return (
@@ -1049,13 +1067,14 @@ LayerColorSelectorFactory.deps = [ColorSelectorFactory];
1049
1067
  export function LayerColorSelectorFactory(ColorSelector) {
1050
1068
  class LayerColorSelector extends Component {
1051
1069
  render() {
1052
- const {layer, onChange, selectedColor, property = 'color', setColorUI} = this.props;
1070
+ const {layer, onChange, selectedColor, property = 'color', setColorUI, fields} = this.props;
1053
1071
  return (
1054
1072
  <SidePanelSection>
1055
1073
  <PanelLabel>
1056
1074
  <FormattedMessage id="layer.color" />
1057
1075
  </PanelLabel>
1058
1076
  <ColorSelector
1077
+ fields={fields}
1059
1078
  colorSets={[
1060
1079
  {
1061
1080
  selectedColor: selectedColor || layer.config.color,
@@ -1077,13 +1096,22 @@ ArcLayerColorSelectorFactory.deps = [ColorSelectorFactory];
1077
1096
  export function ArcLayerColorSelectorFactory(ColorSelector) {
1078
1097
  class ArcLayerColorSelector extends Component {
1079
1098
  render() {
1080
- const {layer, onChangeConfig, onChangeVisConfig, property = 'color', setColorUI} = this.props;
1099
+ const {
1100
+ layer,
1101
+ onChangeConfig,
1102
+ onChangeVisConfig,
1103
+ property = 'color',
1104
+ setColorUI,
1105
+ fields
1106
+ } = this.props;
1107
+
1081
1108
  return (
1082
1109
  <SidePanelSection>
1083
1110
  <PanelLabel>
1084
1111
  <FormattedMessage id="layer.colorRange" />
1085
1112
  </PanelLabel>
1086
1113
  <ColorSelector
1114
+ fields={fields}
1087
1115
  colorSets={[
1088
1116
  {
1089
1117
  selectedColor: layer.config.color,
@@ -1114,42 +1142,48 @@ export function LayerColorRangeSelectorFactory(ColorSelector) {
1114
1142
  layer,
1115
1143
  onChange,
1116
1144
  property = 'colorRange',
1117
- scaleProperty = 'colorScale',
1118
- domain = 'colorDomain',
1119
- setColorUI
1145
+ field = 'colorField',
1146
+ scale = 'colorScale',
1147
+ setColorUI,
1148
+ fields
1120
1149
  } = this.props;
1121
-
1122
- const colorSets = [
1123
- {
1124
- selectedColor: layer.config.visConfig[property],
1125
- isRange: true,
1126
- setColor: colorRange => {
1127
- const {colorMap} = layer.config.visConfig[property];
1128
- const colorRangeUpdated = colorMap
1129
- ? layer.updateColorMap(property, colorMap, colorRange)
1130
- : colorRange;
1131
- onChange({[property]: colorRangeUpdated});
1132
- }
1133
- }
1134
- ];
1135
-
1136
- const scale = layer.config[scaleProperty];
1137
- // TODO
1138
- if (scale === SCALE_TYPES.hexColor) {
1139
- colorSets[0].selectedColor = {
1140
- colors: layer.config[domain]
1141
- };
1142
- }
1143
-
1144
1150
  return (
1145
1151
  <SidePanelSection>
1146
1152
  <PanelLabel>
1147
1153
  <FormattedMessage id="layer.colorRange" />
1148
1154
  </PanelLabel>
1149
1155
  <ColorSelector
1150
- colorSets={colorSets}
1156
+ fields={fields}
1157
+ colorSets={[
1158
+ {
1159
+ selectedColor: layer.config.visConfig[property],
1160
+ isRange: true,
1161
+ setColor: colorRange => {
1162
+ layer.updateLayerConfig({
1163
+ [scale]: SCALE_TYPES.ordinal
1164
+ });
1165
+ const {colorMap} = layer.config.visConfig[property];
1166
+ const colorRangeUpdated = colorMap
1167
+ ? layer.updateColorMap(property, colorMap, colorRange)
1168
+ : colorRange;
1169
+ onChange({[property]: colorRangeUpdated});
1170
+ }
1171
+ }
1172
+ ]}
1151
1173
  colorUI={layer.config.colorUI[property]}
1152
1174
  setColorUI={newConfig => setColorUI(property, newConfig)}
1175
+ onSelectHexColorColumn={colorColumn => {
1176
+ layer.updateLayerConfig({
1177
+ [field]: {
1178
+ ...layer.config[field],
1179
+ colorColumn: colorColumn?.name,
1180
+ colorColumnIdx: colorColumn?.fieldIdx
1181
+ },
1182
+ [scale]: SCALE_TYPES.identity
1183
+ });
1184
+
1185
+ onChange({[property]: hexColorCustomPalette});
1186
+ }}
1153
1187
  />
1154
1188
  </SidePanelSection>
1155
1189
  );
@@ -144,14 +144,12 @@ function VisConfigByFieldSelectorFactory(InfoHelper, FieldSelector, ColorDimensi
144
144
  defaultMessage={label}
145
145
  />
146
146
  }
147
- layerId={this.props.id}
148
147
  scaleType={this.props.scaleType}
149
148
  options={scaleOptions}
150
149
  domain={domain}
151
150
  range={range}
152
151
  onSelect={this.props.updateScale}
153
152
  onSetCustomPalette={this.props.updateCustomPalette}
154
- fields={this.props.fields}
155
153
  />
156
154
  </div>
157
155
  )}
@@ -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
+ };
@@ -45,7 +45,7 @@ import {
45
45
  import {getHTMLMapModeTileUrl} from 'utils/utils';
46
46
  import {TOOLTIP_FORMAT_TYPES} from './tooltip';
47
47
  import {LAYER_TYPES} from 'layers/types';
48
- import {scaleHexColor} from 'utils/custom-scale';
48
+ import {scaleIdentity} from 'utils/custom-scales';
49
49
 
50
50
  export const ACTION_PREFIX = '@@kepler.gl/';
51
51
  export const CLOUDFRONT = 'https://d1a3f4spazzrp4.cloudfront.net/kepler.gl';
@@ -312,8 +312,7 @@ export const SCALE_TYPES = keyMirror({
312
312
  custom: null,
313
313
  // UI-only type, resolving as custom
314
314
  logarithmic: null,
315
- // Scale for HexColor column initiative
316
- hexColor: null
315
+ identity: null
317
316
  });
318
317
 
319
318
  export const SCALE_FUNC = {
@@ -325,7 +324,7 @@ export const SCALE_FUNC = {
325
324
  [SCALE_TYPES.log]: scaleLog,
326
325
  [SCALE_TYPES.point]: scalePoint,
327
326
  [SCALE_TYPES.custom]: scaleThreshold,
328
- [SCALE_TYPES.hexColor]: scaleHexColor
327
+ [SCALE_TYPES.identity]: scaleIdentity
329
328
  };
330
329
 
331
330
  export const ALL_FIELD_TYPES = keyMirror({
@@ -439,7 +438,8 @@ export const CHANNEL_SCALES = keyMirror({
439
438
  size: null,
440
439
  customMarker: null,
441
440
  colorAggr: null,
442
- sizeAggr: null
441
+ sizeAggr: null,
442
+ identity: null
443
443
  });
444
444
 
445
445
  export const AGGREGATION_TYPES = {
@@ -557,10 +557,11 @@ export const linearFieldAggrScaleFunctions = {
557
557
  };
558
558
 
559
559
  export const ordinalFieldScaleFunctions = {
560
- [CHANNEL_SCALES.color]: [SCALE_TYPES.ordinal, SCALE_TYPES.hexColor],
560
+ [CHANNEL_SCALES.color]: [SCALE_TYPES.ordinal],
561
561
  [CHANNEL_SCALES.radius]: [SCALE_TYPES.point],
562
562
  [CHANNEL_SCALES.size]: [SCALE_TYPES.point],
563
- [CHANNEL_SCALES.customMarker]: [SCALE_TYPES.ordinal]
563
+ [CHANNEL_SCALES.customMarker]: [SCALE_TYPES.ordinal],
564
+ [CHANNEL_SCALES.identity]: []
564
565
  };
565
566
 
566
567
  export const ordinalFieldAggrScaleFunctions = {
@@ -21,7 +21,7 @@
21
21
  import {console as Console} from 'global/window';
22
22
  import keymirror from 'keymirror';
23
23
  import {CollisionFilterExtension, DataFilterExtension} from '@deck.gl/extensions';
24
- import {COORDINATE_SYSTEM} from '@deck.gl/core';
24
+ import {COORDINATE_SYSTEM, Layer as DeckLayer} from '@deck.gl/core';
25
25
  import {_PointLabelLayer as PointLabelLayer} from '@deck.gl/carto';
26
26
  import DefaultLayerIcon from './default-layer-icon';
27
27
  import {diffUpdateTriggers} from './layer-update';
@@ -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,
@@ -76,6 +76,7 @@ const collisionFilterExtension = new CollisionFilterExtension();
76
76
 
77
77
  const defaultDataAccessor = dc => d => d;
78
78
  const defaultGetFieldValue = (field, d) => field.valueAccessor(d);
79
+ const scaleIdentity = v => v;
79
80
 
80
81
  export const OVERLAY_TYPE = keymirror({
81
82
  deckgl: null,
@@ -99,7 +100,6 @@ export const colorMaker = generateColor();
99
100
  class Layer {
100
101
  constructor(props = {}) {
101
102
  this.id = props.id || generateHashId(LAYER_ID_LENGTH);
102
-
103
103
  // meta
104
104
  this.meta = {};
105
105
 
@@ -608,8 +608,9 @@ class Layer {
608
608
  };
609
609
 
610
610
  this.updateLayerConfig({colorUI});
611
- // if colorUI[prop] is colorRange
612
- 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);
613
614
 
614
615
  if (isColorRange) {
615
616
  this.updateColorUIByColorRange(newConfig, prop);
@@ -662,8 +663,9 @@ class Layer {
662
663
  colorRangeConfig: {
663
664
  ...colorUI[prop].colorRangeConfig,
664
665
  type: visConfig[prop].type,
665
- steps: visConfig[prop].colors.length,
666
- reversed: Boolean(visConfig[prop].reversed)
666
+ steps: visConfig[prop].colors?.length,
667
+ reversed: Boolean(visConfig[prop].reversed),
668
+ hexColumn: this.isColoredByColorColumn(prop)
667
669
  }
668
670
  }
669
671
  }
@@ -731,6 +733,12 @@ class Layer {
731
733
  updateCategoryColorMap(colorMap, domain, colorRange) {
732
734
  const colors = colorRange.colors;
733
735
  const assignedCategories = [];
736
+ if (colorRange.type === hexColor) {
737
+ return {
738
+ ...colorRange,
739
+ colorMap: []
740
+ };
741
+ }
734
742
  const newColorMap = colorMap.slice(0, colors.length).map((cMap, index) => {
735
743
  assignedCategories.push(cMap[0]);
736
744
  return [cMap[0], colors[index]];
@@ -820,7 +828,11 @@ class Layer {
820
828
  }
821
829
 
822
830
  getColorScale(colorScale, colorDomain, colorRange) {
823
- 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)) {
824
836
  const cMap = new Map();
825
837
  colorRange.colorMap.forEach(([k, v]) => {
826
838
  cMap.set(k, typeof v === 'string' ? hexToRgb(v) : v);
@@ -901,7 +913,9 @@ class Layer {
901
913
  const aggregationValue = this.config.visConfig[aggregation];
902
914
 
903
915
  const scaleFunction =
904
- channelScaleType === CHANNEL_SCALES.color
916
+ channelScaleType === CHANNEL_SCALES.identity
917
+ ? scaleIdentity
918
+ : channelScaleType === CHANNEL_SCALES.color
905
919
  ? this.getColorScale(...args)
906
920
  : channelScaleType === CHANNEL_SCALES.customMarker
907
921
  ? this.getCustomMarkersScale(
@@ -912,10 +926,12 @@ class Layer {
912
926
 
913
927
  attributeAccessors[accessor] = d =>
914
928
  this.getEncodedChannelValue({
929
+ channel,
930
+ dataContainer,
915
931
  scale: scaleFunction,
916
932
  data: dataAccessor(dataContainer)(d),
917
933
  field: fieldConfig,
918
- aggregation: aggregationValue,
934
+ _aggregation: aggregationValue,
919
935
  nullValue
920
936
  });
921
937
  } else if (typeof getAttributeValue === 'function') {
@@ -934,7 +950,7 @@ class Layer {
934
950
  }
935
951
 
936
952
  getVisChannelScale(scale, domain, range, fixed) {
937
- if (scale === SCALE_TYPES.ordinal || scale === SCALE_TYPES.hexColor) {
953
+ if (scale === SCALE_TYPES.ordinal) {
938
954
  // @ts-ignore d3-scale type
939
955
  return SCALE_FUNC[scale]()
940
956
  .domain(domain.slice(0, range.length))
@@ -988,16 +1004,34 @@ class Layer {
988
1004
  }
989
1005
 
990
1006
  getEncodedChannelValue({
1007
+ channel,
991
1008
  scale,
992
1009
  data,
993
1010
  field,
1011
+ dataContainer,
994
1012
  // In builder we overwrite the getValue function and we use the _aggregation parameter in spatial index layers as the QuadkeyLayer.
995
- aggregation,
1013
+ _aggregation,
996
1014
  nullValue = NO_VALUE_COLOR,
997
1015
  getValue = defaultGetFieldValue
998
1016
  }) {
1017
+ let colorColumnValue;
999
1018
  const {type} = field;
1000
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
+ }
1001
1035
 
1002
1036
  if (!notNullorUndefined(value)) {
1003
1037
  return nullValue;
@@ -1007,9 +1041,9 @@ class Layer {
1007
1041
  if (type === ALL_FIELD_TYPES.timestamp) {
1008
1042
  // shouldn't need to convert here
1009
1043
  // scale Function should take care of it
1010
- attributeValue = scale(new Date(value));
1044
+ attributeValue = scale(new Date(value), colorColumnValue);
1011
1045
  } else {
1012
- attributeValue = scale(value);
1046
+ attributeValue = scale(value, colorColumnValue);
1013
1047
  }
1014
1048
 
1015
1049
  if (!notNullorUndefined(attributeValue)) {
@@ -1043,13 +1077,14 @@ class Layer {
1043
1077
  if (!this.config.dataId) {
1044
1078
  return {};
1045
1079
  }
1046
- const layerDataset = datasets[this.config.dataId];
1047
- const {dataContainer} = layerDataset;
1080
+ const dataset = this.getDataset(datasets);
1081
+ const {dataContainer} = dataset;
1048
1082
 
1049
- this.updateVisualChannelFields(layerDataset);
1083
+ this.updateVisualChannelFields(dataset);
1084
+ this.updateHexColorDomain(dataset);
1050
1085
 
1051
1086
  const getPosition = this.getPositionAccessor(dataContainer);
1052
- const dataUpdateTriggers = this.getDataUpdateTriggers(layerDataset);
1087
+ const dataUpdateTriggers = this.getDataUpdateTriggers(dataset);
1053
1088
  const triggerChanged = this.getChangedTriggers(dataUpdateTriggers);
1054
1089
 
1055
1090
  if (triggerChanged.getMeta) {
@@ -1062,7 +1097,7 @@ class Layer {
1062
1097
  // same data
1063
1098
  data = oldLayerData.data;
1064
1099
  } else {
1065
- data = this.calculateDataAttribute(layerDataset, getPosition);
1100
+ data = this.calculateDataAttribute(dataset, getPosition);
1066
1101
  }
1067
1102
 
1068
1103
  return {data, triggerChanged};
@@ -1074,12 +1109,20 @@ class Layer {
1074
1109
  * @param {Object} dataset
1075
1110
  */
1076
1111
  updateVisualChannelFields(dataset) {
1077
- for (const {field} of Object.values(this.visualChannels)) {
1112
+ for (const {field, range} of Object.values(this.visualChannels)) {
1078
1113
  const oldField = this.config[field];
1114
+ const isUsingHexColorCode = this.config.visConfig[range].hexColor
1079
1115
  if (!oldField) {
1080
1116
  return;
1081
1117
  }
1082
- 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
+ }
1083
1126
  this.updateLayerConfig({[field]: newDataSetField});
1084
1127
  }
1085
1128
  }
@@ -1100,12 +1143,12 @@ class Layer {
1100
1143
  Object.values(this.visualChannels).forEach(channel => {
1101
1144
  const {scale} = channel;
1102
1145
  const scaleType = this.config[scale];
1146
+
1103
1147
  // ordinal domain is based on dataContainer, if only filter changed
1104
1148
  // no need to update ordinal domain
1105
1149
  if (!newFilter || scaleType !== SCALE_TYPES.ordinal) {
1106
1150
  const {domain} = channel;
1107
1151
  const updatedDomain = this.calculateLayerDomain(table, channel);
1108
- console.log(this.name, updatedDomain, domain);
1109
1152
  this.updateLayerConfig({[domain]: updatedDomain});
1110
1153
  }
1111
1154
  });
@@ -1152,7 +1195,7 @@ class Layer {
1152
1195
  validateScale(channel) {
1153
1196
  const visualChannel = this.visualChannels[channel];
1154
1197
  const {scale} = visualChannel;
1155
- if (!scale) {
1198
+ if (!scale || this.config[scale] === SCALE_TYPES.identity) {
1156
1199
  // visualChannel doesn't have scale
1157
1200
  return;
1158
1201
  }
@@ -1222,6 +1265,24 @@ class Layer {
1222
1265
  return dataset.getColumnLayerDomain(dataSetField, scaleType) || defaultDomain;
1223
1266
  }
1224
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
+
1225
1286
  hasHoveredObject(objectInfo) {
1226
1287
  return this.isLayerHovered(objectInfo) && objectInfo.object ? objectInfo.object : null;
1227
1288
  }
@@ -1250,6 +1311,7 @@ class Layer {
1250
1311
  if (!radiusChannel || this.config[radiusChannel.field]) {
1251
1312
  return 1;
1252
1313
  }
1314
+
1253
1315
  return this.config.visConfig.radius;
1254
1316
  }
1255
1317
 
@@ -1312,7 +1374,7 @@ class Layer {
1312
1374
  {getPosition, getRadius, radiusScale, updateTriggers, sharedProps},
1313
1375
  renderOpts
1314
1376
  ) {
1315
- const {data} = renderOpts;
1377
+ const {data, mapState} = renderOpts;
1316
1378
  const {textLabel, visibilityByZoom} = this.config;
1317
1379
  const extensions = [...sharedProps.extensions, collisionFilterExtension];
1318
1380
 
@@ -1431,6 +1493,13 @@ class Layer {
1431
1493
  // implemented in subclasses
1432
1494
  return () => null;
1433
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
+ }
1434
1503
  }
1435
1504
 
1436
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
  }),
@@ -1,14 +1,12 @@
1
- import {hexToRgb} from './color-utils';
2
-
3
- export function scaleHexColor() {
1
+ export function scaleIdentity() {
4
2
  let unknown;
5
3
  function scale(x) {
6
- return x === null ? unknown : hexToRgb(x);
4
+ return x === null ? unknown : x;
7
5
  }
8
6
 
9
7
  scale.invert = scale;
10
8
 
11
- scale.domain = scale.range = scaleHexColor;
9
+ scale.domain = scale.range = scaleIdentity;
12
10
 
13
11
  scale.unknown = u => {
14
12
  if (u) {
@@ -324,7 +324,6 @@ class KeplerTable {
324
324
  switch (scaleType) {
325
325
  case SCALE_TYPES.ordinal:
326
326
  case SCALE_TYPES.point:
327
- case SCALE_TYPES.hexColor:
328
327
  // do not recalculate ordinal domain based on filtered data
329
328
  // don't need to update ordinal domain every time
330
329
  return getOrdinalDomain(dataContainer, valueAccessor);