@carto/kepler.gl 0.0.33-alpha1 → 0.0.34

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/dist/components/index.js +25 -2
  2. package/dist/components/side-panel/layer-panel/color-dimension-scale-selector.js +45 -0
  3. package/dist/components/side-panel/layer-panel/layer-configurator.js +108 -33
  4. package/dist/components/side-panel/layer-panel/vis-config-by-field-selector.js +23 -5
  5. package/dist/constants/default-settings.js +12 -9
  6. package/dist/constants/index.js +7 -1
  7. package/dist/deckgl-layers/layer-utils/cpu-aggregator.js +12 -9
  8. package/dist/layers/aggregation-layer.js +23 -1
  9. package/dist/layers/base-layer.js +120 -6
  10. package/dist/layers/cluster-layer/cluster-layer.js +2 -1
  11. package/dist/layers/h3-hexagon-layer/h3-hexagon-layer.js +16 -14
  12. package/dist/utils/data-scale-utils.js +2 -2
  13. package/dist/utils/data-utils.js +19 -1
  14. package/package.json +1 -1
  15. package/src/components/index.js +5 -0
  16. package/src/components/side-panel/layer-panel/color-dimension-scale-selector.js +33 -0
  17. package/src/components/side-panel/layer-panel/layer-configurator.js +101 -23
  18. package/src/components/side-panel/layer-panel/vis-config-by-field-selector.js +31 -3
  19. package/src/constants/default-settings.js +21 -13
  20. package/src/constants/index.js +2 -1
  21. package/src/deckgl-layers/layer-utils/cpu-aggregator.js +25 -8
  22. package/src/layers/aggregation-layer.js +19 -1
  23. package/src/layers/base-layer.js +82 -8
  24. package/src/layers/cluster-layer/cluster-layer.js +1 -0
  25. package/src/layers/h3-hexagon-layer/h3-hexagon-layer.js +14 -17
  26. package/src/utils/data-scale-utils.js +2 -4
  27. package/src/utils/data-utils.d.ts +1 -0
  28. package/src/utils/data-utils.js +14 -0
  29. package/umd/keplergl.min.js +31 -31
  30. package/CHANGELOG.md +0 -711
@@ -40,8 +40,10 @@ import TextLabelPanelFactory from './text-label-panel';
40
40
 
41
41
  import {capitalizeFirstLetter} from 'utils/utils';
42
42
 
43
- import {CHANNEL_SCALE_SUPPORTED_FIELDS} from 'constants/default-settings';
43
+ import {CHANNEL_SCALES, CHANNEL_SCALE_SUPPORTED_FIELDS} from 'constants/default-settings';
44
44
  import {LAYER_TYPES} from 'layers/types';
45
+ import {injectIntl} from 'react-intl';
46
+ import ColorDimensionScaleSelectorFactory from './color-dimension-scale-selector';
45
47
 
46
48
  const StyledLayerConfigurator = styled.div.attrs({
47
49
  className: 'layer-panel__config'
@@ -82,7 +84,8 @@ export const getVisConfiguratorProps = props => ({
82
84
  export const getLayerChannelConfigProps = props => ({
83
85
  layer: props.layer,
84
86
  fields: getLayerFields(props.datasets, props.layer),
85
- onChange: props.updateLayerVisualChannelConfig
87
+ onChange: props.updateLayerVisualChannelConfig,
88
+ onChangeVisConfig: props.updateLayerVisConfig
86
89
  });
87
90
 
88
91
  LayerConfiguratorFactory.deps = [
@@ -93,7 +96,8 @@ LayerConfiguratorFactory.deps = [
93
96
  ChannelByValueSelectorFactory,
94
97
  LayerColumnConfigFactory,
95
98
  LayerTypeSelectorFactory,
96
- VisConfigSwitchFactory
99
+ VisConfigSwitchFactory,
100
+ AggrScaleSelectorFactory
97
101
  ];
98
102
 
99
103
  export default function LayerConfiguratorFactory(
@@ -104,7 +108,8 @@ export default function LayerConfiguratorFactory(
104
108
  ChannelByValueSelector,
105
109
  LayerColumnConfig,
106
110
  LayerTypeSelector,
107
- VisConfigSwitch
111
+ VisConfigSwitch,
112
+ AggrScaleSelector
108
113
  ) {
109
114
  class LayerConfigurator extends Component {
110
115
  static propTypes = {
@@ -240,7 +245,11 @@ export default function LayerConfiguratorFactory(
240
245
  <LayerConfigGroup label={'layer.color'} collapsible>
241
246
  <LayerColorRangeSelector {...visConfiguratorProps} />
242
247
  <ConfigGroupCollapsibleContent>
243
- <AggrScaleSelector {...layerConfiguratorProps} channel={layer.visualChannels.color} />
248
+ <AggrScaleSelector
249
+ {...layerConfiguratorProps}
250
+ channel={layer.visualChannels.color}
251
+ onChangeVisConfig={layerChannelConfigProps.onChangeVisConfig}
252
+ />
244
253
  <ChannelByValueSelector
245
254
  channel={layer.visualChannels.color}
246
255
  {...layerChannelConfigProps}
@@ -328,7 +337,11 @@ export default function LayerConfiguratorFactory(
328
337
  <LayerConfigGroup label={'layer.color'} collapsible>
329
338
  <LayerColorRangeSelector {...visConfiguratorProps} />
330
339
  <ConfigGroupCollapsibleContent>
331
- <AggrScaleSelector {...layerConfiguratorProps} channel={layer.visualChannels.color} />
340
+ <AggrScaleSelector
341
+ {...layerConfiguratorProps}
342
+ channel={layer.visualChannels.color}
343
+ onChangeVisConfig={layerChannelConfigProps.onChangeVisConfig}
344
+ />
332
345
  <ChannelByValueSelector
333
346
  channel={layer.visualChannels.color}
334
347
  {...layerChannelConfigProps}
@@ -382,6 +395,7 @@ export default function LayerConfiguratorFactory(
382
395
  <AggrScaleSelector
383
396
  {...layerConfiguratorProps}
384
397
  channel={layer.visualChannels.size}
398
+ onChangeVisConfig={layerChannelConfigProps.onChangeVisConfig}
385
399
  />
386
400
  <VisConfigSlider
387
401
  {...layer.visConfigSettings.sizeRange}
@@ -1067,7 +1081,13 @@ export const LayerColorRangeSelector = ({layer, onChange, property = 'colorRange
1067
1081
  {
1068
1082
  selectedColor: layer.config.visConfig[property],
1069
1083
  isRange: true,
1070
- setColor: colorRange => onChange({[property]: colorRange})
1084
+ setColor: colorRange => {
1085
+ const {colorMap} = layer.config.visConfig[property];
1086
+ const colorRangeUpdated = colorMap
1087
+ ? layer.updateColorMap(property, colorMap, colorRange)
1088
+ : colorRange;
1089
+ onChange({[property]: colorRangeUpdated});
1090
+ }
1071
1091
  }
1072
1092
  ]}
1073
1093
  colorUI={layer.config.colorUI[property]}
@@ -1078,7 +1098,15 @@ export const LayerColorRangeSelector = ({layer, onChange, property = 'colorRange
1078
1098
 
1079
1099
  ChannelByValueSelectorFactory.deps = [VisConfigByFieldSelectorFactory];
1080
1100
  export function ChannelByValueSelectorFactory(VisConfigByFieldSelector) {
1081
- const ChannelByValueSelector = ({layer, channel, onChange, fields, description, isLoading}) => {
1101
+ const ChannelByValueSelector = ({
1102
+ layer,
1103
+ channel,
1104
+ onChange,
1105
+ onChangeVisConfig,
1106
+ fields,
1107
+ description,
1108
+ isLoading
1109
+ }) => {
1082
1110
  const {
1083
1111
  channelScaleType,
1084
1112
  domain,
@@ -1094,8 +1122,18 @@ export function ChannelByValueSelectorFactory(VisConfigByFieldSelector) {
1094
1122
  supportedFieldTypes || CHANNEL_SCALE_SUPPORTED_FIELDS[channelScaleType];
1095
1123
  const supportedFields = fields.filter(({type}) => channelSupportedFieldTypes.includes(type));
1096
1124
  const scaleOptions = layer.getScaleOptions(channel.key);
1097
- const showScale = !layer.isAggregated && layer.config[scale] && scaleOptions.length > 1;
1125
+ const showScaleCustomizable =
1126
+ channelScaleType === CHANNEL_SCALES.color &&
1127
+ layer.config[scale] &&
1128
+ Boolean(layer.config[field]) &&
1129
+ scaleOptions.length > 0;
1130
+ const showScale =
1131
+ !showScaleCustomizable &&
1132
+ !layer.isAggregated &&
1133
+ layer.config[scale] &&
1134
+ scaleOptions.length > 1;
1098
1135
  const defaultDescription = 'layerConfiguration.defaultDescription';
1136
+ const visRange = layer.config.visConfig[range];
1099
1137
 
1100
1138
  return (
1101
1139
  <VisConfigByFieldSelector
@@ -1107,13 +1145,20 @@ export function ChannelByValueSelectorFactory(VisConfigByFieldSelector) {
1107
1145
  key={`${key}-channel-selector`}
1108
1146
  property={property}
1109
1147
  placeholder={defaultMeasure || 'placeholder.selectField'}
1110
- range={layer.config.visConfig[range]}
1148
+ range={visRange}
1111
1149
  scaleOptions={scaleOptions}
1112
1150
  scaleType={scale ? layer.config[scale] : null}
1113
1151
  selectedField={layer.config[field]}
1114
1152
  showScale={showScale}
1115
- updateField={val => onChange({[field]: val}, key)}
1153
+ showScaleCustomizable={showScaleCustomizable}
1154
+ updateField={val => {
1155
+ if (visRange.colorMap) {
1156
+ onChangeVisConfig({[range]: {...visRange, colorMap: undefined}});
1157
+ }
1158
+ onChange({[field]: val}, key);
1159
+ }}
1116
1160
  updateScale={val => onChange({[scale]: val}, key)}
1161
+ updateCustomPalette={colorMap => onChangeVisConfig({[range]: {...visRange, colorMap}})}
1117
1162
  isLoading={isLoading}
1118
1163
  />
1119
1164
  );
@@ -1122,19 +1167,52 @@ export function ChannelByValueSelectorFactory(VisConfigByFieldSelector) {
1122
1167
  return ChannelByValueSelector;
1123
1168
  }
1124
1169
 
1125
- export const AggrScaleSelector = ({channel, layer, onChange}) => {
1126
- const {scale, key} = channel;
1127
- const scaleOptions = layer.getScaleOptions(key);
1170
+ AggrScaleSelectorFactory.deps = [ColorDimensionScaleSelectorFactory];
1128
1171
 
1129
- return Array.isArray(scaleOptions) && scaleOptions.length > 1 ? (
1130
- <DimensionScaleSelector
1131
- label={`${key} Scale`}
1132
- options={scaleOptions}
1133
- scaleType={layer.config[scale]}
1134
- onSelect={val => onChange({[scale]: val}, key)}
1135
- />
1136
- ) : null;
1137
- };
1172
+ function AggrScaleSelectorFactory(ColorDimensionScaleSelector) {
1173
+ class AggrScaleSelector extends Component {
1174
+ render() {
1175
+ const {channel, layer, onChange, onChangeVisConfig} = this.props;
1176
+ const {scale, key, channelScaleType, domain, range} = channel;
1177
+ const scaleOptions = layer.getScaleOptions(key);
1178
+ const visRange = layer.config.visConfig[range];
1179
+ const showScaleCustomizable =
1180
+ channelScaleType === CHANNEL_SCALES.colorAggr &&
1181
+ Array.isArray(scaleOptions) &&
1182
+ scaleOptions.length > 0;
1183
+ const showScale = Array.isArray(scaleOptions) && scaleOptions.length > 1;
1184
+
1185
+ if (showScaleCustomizable) {
1186
+ return (
1187
+ <SidePanelSection>
1188
+ <ColorDimensionScaleSelector
1189
+ label={`${key} Scale`}
1190
+ scaleType={layer.config[scale]}
1191
+ options={scaleOptions}
1192
+ domain={layer.config[domain]}
1193
+ range={visRange}
1194
+ onSelect={val => onChange({[scale]: val}, key)}
1195
+ onSetCustomPalette={colorMap => onChangeVisConfig({[range]: {...visRange, colorMap}})}
1196
+ />
1197
+ </SidePanelSection>
1198
+ );
1199
+ }
1200
+
1201
+ if (showScale) {
1202
+ return (
1203
+ <DimensionScaleSelector
1204
+ label={`${key} Scale`}
1205
+ options={scaleOptions}
1206
+ scaleType={layer.config[scale]}
1207
+ onSelect={val => onChange({[scale]: val}, key)}
1208
+ />
1209
+ );
1210
+ }
1211
+ return null;
1212
+ }
1213
+ }
1214
+ return injectIntl(AggrScaleSelector);
1215
+ }
1138
1216
 
1139
1217
  export const AggregationTypeSelector = ({layer, channel, onChange}) => {
1140
1218
  const {field, aggregation, key} = channel;
@@ -27,9 +27,14 @@ import InfoHelperFacotry from 'components/common/info-helper';
27
27
  import DimensionScaleSelector from './dimension-scale-selector';
28
28
  import {camelize} from 'utils/utils';
29
29
  import FieldSelectorFactory from '../../common/field-selector';
30
+ import ColorDimensionScaleSelectorFactory from './color-dimension-scale-selector';
30
31
 
31
- VisConfigByFieldSelectorFactory.deps = [InfoHelperFacotry, FieldSelectorFactory];
32
- function VisConfigByFieldSelectorFactory(InfoHelper, FieldSelector) {
32
+ VisConfigByFieldSelectorFactory.deps = [
33
+ InfoHelperFacotry,
34
+ FieldSelectorFactory,
35
+ ColorDimensionScaleSelectorFactory
36
+ ];
37
+ function VisConfigByFieldSelectorFactory(InfoHelper, FieldSelector, ColorDimensionScaleSelector) {
33
38
  class VisConfigByFieldSelector extends Component {
34
39
  static propTypes = {
35
40
  channel: PropTypes.string.isRequired,
@@ -37,8 +42,10 @@ function VisConfigByFieldSelectorFactory(InfoHelper, FieldSelector) {
37
42
  id: PropTypes.string.isRequired,
38
43
  property: PropTypes.string.isRequired,
39
44
  showScale: PropTypes.bool.isRequired,
45
+ showScaleCustomizable: PropTypes.bool.isRequired,
40
46
  updateField: PropTypes.func.isRequired,
41
47
  updateScale: PropTypes.func.isRequired,
48
+ updateCustomPalette: PropTypes.func.isRequired,
42
49
 
43
50
  // optional
44
51
  scaleType: PropTypes.string,
@@ -57,11 +64,14 @@ function VisConfigByFieldSelectorFactory(InfoHelper, FieldSelector) {
57
64
  const {
58
65
  property,
59
66
  showScale,
67
+ showScaleCustomizable,
60
68
  selectedField,
61
69
  description,
62
70
  label,
63
71
  intl,
64
- scaleOptions = []
72
+ scaleOptions = [],
73
+ domain,
74
+ range
65
75
  } = this.props;
66
76
 
67
77
  return (
@@ -109,6 +119,24 @@ function VisConfigByFieldSelectorFactory(InfoHelper, FieldSelector) {
109
119
  />
110
120
  ) : null}
111
121
  </div>
122
+ <div>
123
+ {showScaleCustomizable && !this.props.isLoading && (
124
+ <ColorDimensionScaleSelector
125
+ label={
126
+ <FormattedMessage
127
+ id={`scale.${camelize(`${property} scale`)}`}
128
+ defaultMessage={label}
129
+ />
130
+ }
131
+ scaleType={this.props.scaleType}
132
+ options={scaleOptions}
133
+ domain={domain}
134
+ range={range}
135
+ onSelect={this.props.updateScale}
136
+ onSetCustomPalette={this.props.updateCustomPalette}
137
+ />
138
+ )}
139
+ </div>
112
140
  </SidePanelSection>
113
141
  );
114
142
  }
@@ -28,7 +28,8 @@ import {
28
28
  scaleOrdinal,
29
29
  scaleSqrt,
30
30
  scaleLog,
31
- scalePoint
31
+ scalePoint,
32
+ scaleThreshold
32
33
  } from 'd3-scale';
33
34
  import {
34
35
  Layers,
@@ -306,7 +307,8 @@ export const SCALE_TYPES = keyMirror({
306
307
  log: null,
307
308
 
308
309
  // ordinal domain to linear range
309
- point: null
310
+ point: null,
311
+ custom: null
310
312
  });
311
313
 
312
314
  export const SCALE_FUNC = {
@@ -316,7 +318,8 @@ export const SCALE_FUNC = {
316
318
  [SCALE_TYPES.ordinal]: scaleOrdinal,
317
319
  [SCALE_TYPES.sqrt]: scaleSqrt,
318
320
  [SCALE_TYPES.log]: scaleLog,
319
- [SCALE_TYPES.point]: scalePoint
321
+ [SCALE_TYPES.point]: scalePoint,
322
+ [SCALE_TYPES.custom]: scaleThreshold
320
323
  };
321
324
 
322
325
  export const ALL_FIELD_TYPES = keyMirror({
@@ -449,20 +452,20 @@ export const AGGREGATION_TYPES = {
449
452
  };
450
453
 
451
454
  export const linearFieldScaleFunctions = {
452
- [CHANNEL_SCALES.color]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
455
+ [CHANNEL_SCALES.color]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
453
456
  [CHANNEL_SCALES.radius]: [SCALE_TYPES.sqrt],
454
457
  [CHANNEL_SCALES.size]: [SCALE_TYPES.linear, SCALE_TYPES.sqrt, SCALE_TYPES.log]
455
458
  };
456
459
 
457
460
  export const linearFieldAggrScaleFunctions = {
458
461
  [CHANNEL_SCALES.colorAggr]: {
459
- [AGGREGATION_TYPES.average]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
460
- [AGGREGATION_TYPES.maximum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
461
- [AGGREGATION_TYPES.minimum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
462
- [AGGREGATION_TYPES.median]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
463
- [AGGREGATION_TYPES.stdev]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
464
- [AGGREGATION_TYPES.sum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile],
465
- [AGGREGATION_TYPES.variance]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile]
462
+ [AGGREGATION_TYPES.average]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
463
+ [AGGREGATION_TYPES.maximum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
464
+ [AGGREGATION_TYPES.minimum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
465
+ [AGGREGATION_TYPES.median]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
466
+ [AGGREGATION_TYPES.stdev]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
467
+ [AGGREGATION_TYPES.sum]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom],
468
+ [AGGREGATION_TYPES.variance]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom]
466
469
  },
467
470
 
468
471
  [CHANNEL_SCALES.sizeAggr]: {
@@ -486,7 +489,11 @@ export const ordinalFieldAggrScaleFunctions = {
486
489
  // [CHANNEL_SCALES.colorAggr]: [SCALE_TYPES.ordinal, SCALE_TYPES.linear],
487
490
  [CHANNEL_SCALES.colorAggr]: {
488
491
  [AGGREGATION_TYPES.mode]: [SCALE_TYPES.ordinal],
489
- [AGGREGATION_TYPES.countUnique]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile]
492
+ [AGGREGATION_TYPES.countUnique]: [
493
+ SCALE_TYPES.quantize,
494
+ SCALE_TYPES.quantile,
495
+ SCALE_TYPES.custom
496
+ ]
490
497
  },
491
498
 
492
499
  // Currently doesn't support yet
@@ -509,7 +516,7 @@ export const notSupportAggrOpts = {
509
516
  */
510
517
  export const DEFAULT_AGGREGATION = {
511
518
  [CHANNEL_SCALES.colorAggr]: {
512
- [AGGREGATION_TYPES.count]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile]
519
+ [AGGREGATION_TYPES.count]: [SCALE_TYPES.quantize, SCALE_TYPES.quantile, SCALE_TYPES.custom]
513
520
  },
514
521
  [CHANNEL_SCALES.sizeAggr]: {
515
522
  [AGGREGATION_TYPES.count]: [SCALE_TYPES.linear, SCALE_TYPES.sqrt, SCALE_TYPES.log]
@@ -629,6 +636,7 @@ export const DEFAULT_LAYER_COLOR = {
629
636
  export const DEFAULT_TOOLTIP_FIELDS = [];
630
637
 
631
638
  export const NO_VALUE_COLOR = [0, 0, 0, 0];
639
+ export const UNKNOWN_COLOR = [134, 141, 145];
632
640
 
633
641
  export const LAYER_BLENDINGS = {
634
642
  additive: {
@@ -66,7 +66,8 @@ export {
66
66
  SPEED_CONTROL_RANGE,
67
67
  RESOLUTIONS,
68
68
  SORT_ORDER,
69
- MAP_CONTROLS
69
+ MAP_CONTROLS,
70
+ UNKNOWN_COLOR
70
71
  } from './default-settings';
71
72
 
72
73
  export {BUG_REPORT_LINK, USER_GUIDE_DOC} from './user-guides';
@@ -23,7 +23,12 @@ import {AGGREGATION_OPERATION, _BinSorter as BinSorter} from '@deck.gl/aggregati
23
23
  import {console as Console} from 'global/window';
24
24
 
25
25
  import {aggregate} from 'utils/aggregate-utils';
26
- import {AGGREGATION_TYPES, SCALE_FUNC} from 'constants/default-settings';
26
+ import {
27
+ AGGREGATION_TYPES,
28
+ SCALE_FUNC,
29
+ UNKNOWN_COLOR,
30
+ SCALE_TYPES
31
+ } from 'constants/default-settings';
27
32
 
28
33
  export const DECK_AGGREGATION_MAP = {
29
34
  [AGGREGATION_OPERATION.SUM]: AGGREGATION_TYPES.sum,
@@ -97,7 +102,10 @@ export function getDimensionValueDomain(step, props, dimensionUpdater) {
97
102
  [props[lowerPercentile.prop], props[upperPercentile.prop]]
98
103
  );
99
104
 
100
- this._setDimensionState(key, {valueDomain});
105
+ this._setDimensionState(key, {
106
+ // By default sortedBins order by ascending frecuency but if we've an ordinal scale we want to order by descending frecuency
107
+ valueDomain: props[scaleType.prop] === SCALE_TYPES.ordinal ? valueDomain.reverse() : valueDomain
108
+ });
101
109
  }
102
110
 
103
111
  export function getDimensionScale(step, props, dimensionUpdater) {
@@ -112,12 +120,20 @@ export function getDimensionScale(step, props, dimensionUpdater) {
112
120
  const dimensionRange = props[range.prop];
113
121
  const dimensionDomain = props[domain.prop] || this.state.dimensions[key].valueDomain;
114
122
 
115
- const scaleFunctor = getScaleFunctor(scaleType && props[scaleType.prop])();
123
+ const scaleTypeProp = scaleType && props[scaleType.prop];
124
+ const scaleFunctor = getScaleFunctor(scaleTypeProp)();
116
125
 
117
- const scaleFunc = scaleFunctor.domain(dimensionDomain).range(dimensionRange);
126
+ const scaleFunc = scaleFunctor
127
+ .domain(
128
+ scaleTypeProp === SCALE_TYPES.ordinal
129
+ ? dimensionDomain.slice(0, dimensionRange.length)
130
+ : dimensionDomain
131
+ )
132
+ .range(dimensionRange)
133
+ .unknown(UNKNOWN_COLOR);
118
134
 
119
135
  if (typeof onSet === 'object' && typeof props[onSet.props] === 'function') {
120
- props[onSet.props](scaleFunc.domain());
136
+ props[onSet.props](this.state.dimensions[key].valueDomain);
121
137
  }
122
138
  this._setDimensionState(key, {scaleFunc});
123
139
  }
@@ -180,12 +196,13 @@ function getSubLayerAccessor(dimensionState, dimension, layerProps) {
180
196
  }
181
197
 
182
198
  const cv = bin && bin.value;
183
- const domain = scaleFunc.domain();
199
+ // const domain = scaleFunc.domain();
184
200
 
185
- const isValueInDomain = cv >= domain[0] && cv <= domain[domain.length - 1];
201
+ // const isValueInDomain = cv >= domain[0] && cv <= domain[domain.length - 1];
186
202
 
187
203
  // if cell value is outside domain, set alpha to 0
188
- return isValueInDomain ? scaleFunc(cv) : dimension.nullValue;
204
+ // return isValueInDomain ? scaleFunc(cv) : dimension.nullValue;
205
+ return scaleFunc(cv);
189
206
  };
190
207
  }
191
208
 
@@ -53,7 +53,23 @@ export const getValueAggrFunc = (field, aggregation) => {
53
53
  export const getFilterDataFunc = (filterRange, getFilterValue) => pt =>
54
54
  getFilterValue(pt).every((val, i) => val >= filterRange[i][0] && val <= filterRange[i][1]);
55
55
 
56
- const getLayerColorRange = colorRange => colorRange.colors.map(hexToRgb);
56
+ const getLayerColorRange = colorRange => {
57
+ const {colorMap} = colorRange;
58
+
59
+ if (colorMap) {
60
+ return colorMap.map(cMap => hexToRgb(cMap[1]));
61
+ }
62
+ return colorRange.colors.map(hexToRgb);
63
+ };
64
+
65
+ const getLayerColorDomain = colorDomain => {
66
+ const {colorMap} = colorDomain;
67
+
68
+ if (colorMap) {
69
+ return colorMap.map(cMap => cMap[0]);
70
+ }
71
+ return null;
72
+ };
57
73
 
58
74
  export const aggregateRequiredColumns = ['lat', 'lng'];
59
75
 
@@ -64,6 +80,7 @@ export default class AggregationLayer extends Layer {
64
80
  this.getPositionAccessor = dataContainer =>
65
81
  pointPosAccessor(this.config.columns)(dataContainer);
66
82
  this.getColorRange = memoize(getLayerColorRange);
83
+ this.getColorDomain = memoize(getLayerColorDomain);
67
84
  }
68
85
 
69
86
  get isAggregated() {
@@ -315,6 +332,7 @@ export default class AggregationLayer extends Layer {
315
332
 
316
333
  // color
317
334
  colorRange: this.getColorRange(visConfig.colorRange),
335
+ colorDomain: this.getColorDomain(visConfig.colorRange),
318
336
  colorScaleType: this.config.colorScale,
319
337
  upperPercentile: visConfig.percentile[1],
320
338
  lowerPercentile: visConfig.percentile[0],
@@ -35,7 +35,8 @@ import {
35
35
  FIELD_OPTS,
36
36
  SCALE_FUNC,
37
37
  CHANNEL_SCALE_SUPPORTED_FIELDS,
38
- MAX_GPU_FILTERS
38
+ MAX_GPU_FILTERS,
39
+ UNKNOWN_COLOR
39
40
  } from 'constants/default-settings';
40
41
  import {COLOR_RANGES} from 'constants/color-ranges';
41
42
  import {DataVizColors} from 'constants/custom-color-ranges';
@@ -43,7 +44,6 @@ import {
43
44
  LAYER_VIS_CONFIGS,
44
45
  DEFAULT_TEXT_LABEL,
45
46
  DEFAULT_COLOR_UI,
46
- UNKNOWN_COLOR_KEY,
47
47
  DEFAULT_HIGHLIGHT_COLOR,
48
48
  DEFAULT_LAYER_LABEL
49
49
  } from './layer-factory';
@@ -636,6 +636,7 @@ class Layer {
636
636
  });
637
637
  }
638
638
 
639
+ // eslint-disable-next-line complexity
639
640
  updateColorRangeByColorUI(newConfig, previous, prop) {
640
641
  // only update colorRange if changes in UI is made to 'reversed', 'steps' or steps
641
642
  const shouldUpdate =
@@ -664,6 +665,10 @@ class Layer {
664
665
  if (update && colorRange.reversed) {
665
666
  update = reverseColorRange(true, update);
666
667
  }
668
+
669
+ if (update && colorRange.colorMap) {
670
+ update = this.updateColorMap(prop, colorRange.colorMap, update);
671
+ }
667
672
  }
668
673
  }
669
674
 
@@ -676,6 +681,69 @@ class Layer {
676
681
  }
677
682
  }
678
683
 
684
+ updateColorMap(prop, colorMap, colorRange) {
685
+ // @ts-ignore
686
+ const {field, domain} = Object.values(this.visualChannels).find(value => value.range === prop);
687
+ const type = this.config[field]?.type;
688
+
689
+ if (type === 'string' || type === 'boolean' || type === 'date') {
690
+ return this.updateCategoryColorMap(colorMap, this.config[domain], colorRange);
691
+ }
692
+
693
+ // If no type or type is not string, boolean or date
694
+ return this.updateNumericColorMap(colorMap, this.config[domain], colorRange);
695
+ }
696
+
697
+ updateCategoryColorMap(colorMap, domain, colorRange) {
698
+ const colors = colorRange.colors;
699
+ const assignedCategories = [];
700
+ const newColorMap = colorMap.slice(0, colors.length).map((cMap, index) => {
701
+ assignedCategories.push(cMap[0]);
702
+ return [cMap[0], colors[index]];
703
+ });
704
+ const unassignedColors = colors.slice(newColorMap.length, colors.length);
705
+
706
+ for (const color of unassignedColors) {
707
+ const category = domain.find(d => !assignedCategories.includes(d));
708
+ if (!category) {
709
+ break;
710
+ }
711
+ assignedCategories.push(category);
712
+ newColorMap.push([category, color]);
713
+ }
714
+ return {
715
+ ...colorRange,
716
+ colorMap: newColorMap
717
+ };
718
+ }
719
+
720
+ updateNumericColorMap(colorMap, domain, update) {
721
+ const colors = update.colors;
722
+ let newColorMap = colorMap.slice(0, colors.length);
723
+
724
+ newColorMap = newColorMap.map((cMap, index) => {
725
+ const value = index === newColorMap.length - 1 ? null : cMap[0];
726
+ return [value, colors[index]];
727
+ });
728
+ const unassignedColors = colors.slice(newColorMap.length, colors.length);
729
+
730
+ if (unassignedColors.length > 0) {
731
+ const maxValue = domain[domain.length - 1];
732
+ const prevValue = newColorMap[newColorMap.length - 2][0];
733
+ const step = (maxValue - prevValue) / (unassignedColors.length + 1);
734
+ newColorMap[newColorMap.length - 1][0] = prevValue + step;
735
+
736
+ for (const [i, color] of unassignedColors.entries()) {
737
+ const value = i === unassignedColors.length - 1 ? null : prevValue + (step * (i + 2));
738
+ newColorMap.push([value, color]);
739
+ }
740
+ }
741
+ return {
742
+ ...update,
743
+ colorMap: newColorMap
744
+ };
745
+ }
746
+
679
747
  /**
680
748
  * Check whether layer has all columns
681
749
  * @returns {boolean} yes or no
@@ -724,10 +792,10 @@ class Layer {
724
792
  });
725
793
 
726
794
  // @ts-ignore d3 scale
727
- const scale = SCALE_FUNC[SCALE_TYPES.ordinal]()
728
- .domain(cMap.keys())
729
- .range(cMap.values())
730
- .unknown(cMap.get(UNKNOWN_COLOR_KEY) || NO_VALUE_COLOR);
795
+ const scale = SCALE_FUNC[colorScale]()
796
+ .domain(Array.from(cMap.keys()))
797
+ .range(Array.from(cMap.values()))
798
+ .unknown(UNKNOWN_COLOR);
731
799
  return scale;
732
800
  }
733
801
 
@@ -795,6 +863,14 @@ class Layer {
795
863
  }
796
864
 
797
865
  getVisChannelScale(scale, domain, range, fixed) {
866
+ if (scale === SCALE_TYPES.ordinal) {
867
+ // @ts-ignore d3-scale type
868
+ return SCALE_FUNC[scale]()
869
+ .domain(domain.slice(0, range.length))
870
+ .range(range)
871
+ .unknown(UNKNOWN_COLOR);
872
+ }
873
+
798
874
  // @ts-ignore d3-scale type
799
875
  return SCALE_FUNC[fixed ? 'linear' : scale]()
800
876
  .domain(domain)
@@ -1058,8 +1134,6 @@ class Layer {
1058
1134
  return defaultDomain;
1059
1135
  }
1060
1136
 
1061
- // return dataset.getColumnLayerDomain(field, scaleType) || defaultDomain;
1062
-
1063
1137
  const dataSetField = dataset.fields.find(f => f.name === field.name);
1064
1138
  if (!dataSetField) {
1065
1139
  // if new dataset doesn't contain previously set field
@@ -93,6 +93,7 @@ export default class ClusterLayer extends AggregationLayer {
93
93
 
94
94
  // color
95
95
  colorRange: this.getColorRange(visConfig.colorRange),
96
+ colorDomain: this.getColorDomain(visConfig.colorRange),
96
97
  colorScaleType: this.config.colorScale,
97
98
  colorAggregation: visConfig.colorAggregation,
98
99