@carto/kepler.gl 0.0.66 → 0.0.67
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.
- package/CHANGELOG.md +912 -0
- package/README.md +42 -652
- package/dist/components/plot-container.js +4 -2
- package/dist/components/side-panel/layer-panel/custom-marker-categories-selector.js +45 -0
- package/dist/components/side-panel/layer-panel/layer-config-group.js +3 -3
- package/dist/components/side-panel/layer-panel/text-label-panel.js +14 -7
- package/dist/constants/default-settings.js +4 -4
- package/dist/layers/base-layer.js +73 -77
- package/dist/layers/layer-factory.js +23 -26
- package/dist/layers/layer-text-label.js +2 -23
- package/dist/layers/point-layer/point-layer.js +9 -10
- package/dist/localization/en.js +8 -5
- package/dist/processors/data-processor.js +1 -4
- package/dist/reducers/vis-state-updaters.js +16 -8
- package/package.json +13 -8
- package/src/components/plot-container.js +1 -1
- package/src/components/side-panel/layer-panel/custom-marker-categories-selector.js +33 -0
- package/src/components/side-panel/layer-panel/layer-config-group.js +2 -2
- package/src/components/side-panel/layer-panel/text-label-panel.js +44 -25
- package/src/constants/default-settings.js +2 -2
- package/src/layers/base-layer.js +83 -75
- package/src/layers/layer-factory.js +12 -4
- package/src/layers/layer-text-label.js +3 -34
- package/src/layers/point-layer/point-layer.js +7 -11
- package/src/localization/en.js +7 -4
- package/src/processors/data-processor.js +1 -4
- package/src/reducers/vis-state-updaters.js +13 -10
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@carto/kepler.gl",
|
|
3
3
|
"author": "CARTO",
|
|
4
4
|
"homepage": "https://github.com/CartoDB/carto-kepler#readme",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.67",
|
|
6
6
|
"description": "kepler.gl is a webgl based application to visualize large scale location data in the browser",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"main": "dist/index.js",
|
|
@@ -238,13 +238,14 @@
|
|
|
238
238
|
"tough-cookie": "4.0.0"
|
|
239
239
|
},
|
|
240
240
|
"peerDependencies": {
|
|
241
|
-
"@deck.gl/aggregation-layers": "^8.
|
|
242
|
-
"@deck.gl/
|
|
243
|
-
"@deck.gl/
|
|
244
|
-
"@deck.gl/
|
|
245
|
-
"@deck.gl/layers": "^8.
|
|
246
|
-
"@deck.gl/
|
|
247
|
-
"@deck.gl/
|
|
241
|
+
"@deck.gl/aggregation-layers": "^8.9.5",
|
|
242
|
+
"@deck.gl/carto": "^8.9.5",
|
|
243
|
+
"@deck.gl/core": "^8.9.5",
|
|
244
|
+
"@deck.gl/extensions": "^8.9.5",
|
|
245
|
+
"@deck.gl/geo-layers": "^8.9.5",
|
|
246
|
+
"@deck.gl/layers": "^8.9.5",
|
|
247
|
+
"@deck.gl/mesh-layers": "^8.9.5",
|
|
248
|
+
"@deck.gl/react": "^8.9.5",
|
|
248
249
|
"@loaders.gl/core": "^3.1.5",
|
|
249
250
|
"@loaders.gl/csv": "^3.1.5",
|
|
250
251
|
"@loaders.gl/gltf": "^3.1.5",
|
|
@@ -270,6 +271,10 @@
|
|
|
270
271
|
"engines": {
|
|
271
272
|
"node": ">=12.0.0"
|
|
272
273
|
},
|
|
274
|
+
"maintainers": [
|
|
275
|
+
"Shan He <heshan0131@gmail.com>",
|
|
276
|
+
"Giuseppe Macri <gmacri@uber.com>"
|
|
277
|
+
],
|
|
273
278
|
"volta": {
|
|
274
279
|
"node": "12.19.0"
|
|
275
280
|
}
|
|
@@ -212,7 +212,7 @@ export default function PlotContainerFactory(MapContainer, MapsLayout) {
|
|
|
212
212
|
const mapContainers = !isSplit ? (
|
|
213
213
|
<MapContainer index={0} primary={true} {...mapProps} />
|
|
214
214
|
) : (
|
|
215
|
-
<MapsLayout>
|
|
215
|
+
<MapsLayout isExport={true}>
|
|
216
216
|
{splitMaps.map((settings, index) => (
|
|
217
217
|
<MapContainer
|
|
218
218
|
key={index}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) 2022 Uber Technologies, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in
|
|
11
|
+
// all copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
// THE SOFTWARE.
|
|
20
|
+
|
|
21
|
+
import React from 'react';
|
|
22
|
+
import {injectIntl} from 'react-intl';
|
|
23
|
+
|
|
24
|
+
CustomMarkerCategoriesSelectorFactory.deps = [];
|
|
25
|
+
function CustomMarkerCategoriesSelectorFactory() {
|
|
26
|
+
const CustomMarkerCategoriesSelector = () => {
|
|
27
|
+
return <div>Component replaced by cloud native</div>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return injectIntl(CustomMarkerCategoriesSelector);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default CustomMarkerCategoriesSelectorFactory;
|
|
@@ -40,7 +40,7 @@ export const ConfigGroupCollapsibleContent = styled.div.attrs({
|
|
|
40
40
|
overflow: visible;
|
|
41
41
|
transition: max-height 0.3s ease-out;
|
|
42
42
|
height: max-content;
|
|
43
|
-
max-height:
|
|
43
|
+
max-height: 650px;
|
|
44
44
|
`;
|
|
45
45
|
|
|
46
46
|
export const ConfigGroupCollapsibleHeader = styled.div.attrs({
|
|
@@ -62,7 +62,7 @@ export const StyledLayerConfigGroup = styled.div`
|
|
|
62
62
|
&.collapsed {
|
|
63
63
|
.layer-config-group__header__collapsible {
|
|
64
64
|
overflow: visible;
|
|
65
|
-
max-height:
|
|
65
|
+
max-height: 650px;
|
|
66
66
|
}
|
|
67
67
|
.layer-config-group__content {
|
|
68
68
|
.layer-config-group__content__collapsible {
|
|
@@ -67,6 +67,7 @@ function TextLabelPanelFactory(RangeSlider, LayerConfigGroup, FieldSelector, Col
|
|
|
67
67
|
render() {
|
|
68
68
|
const {updateLayerTextLabel, textLabel, fields, AddButton} = this.props;
|
|
69
69
|
const currentFields = textLabel.map(tl => tl.field && tl.field.name).filter(d => d);
|
|
70
|
+
|
|
70
71
|
return (
|
|
71
72
|
<LayerConfigGroup label={'panel.text.label'} collapsible>
|
|
72
73
|
<ConfigGroupCollapsibleHeader>
|
|
@@ -80,11 +81,11 @@ function TextLabelPanelFactory(RangeSlider, LayerConfigGroup, FieldSelector, Col
|
|
|
80
81
|
<ConfigGroupCollapsibleContent>
|
|
81
82
|
{textLabel.map((tl, idx) => (
|
|
82
83
|
<div
|
|
83
|
-
key={tl.field ? tl.field.name :
|
|
84
|
+
key={`${tl.field ? tl.field.name : 'null'}-${idx}`}
|
|
84
85
|
className="side-panel-section-group"
|
|
85
86
|
>
|
|
86
87
|
<PanelLabel>
|
|
87
|
-
<FormattedMessage id={
|
|
88
|
+
<FormattedMessage id={`panel.text.${idx === 0 ? 'main' : 'secondary'}Label`} />
|
|
88
89
|
</PanelLabel>
|
|
89
90
|
<SidePanelSection>
|
|
90
91
|
<FieldSelector
|
|
@@ -120,33 +121,51 @@ function TextLabelPanelFactory(RangeSlider, LayerConfigGroup, FieldSelector, Col
|
|
|
120
121
|
/>
|
|
121
122
|
</SidePanelSection>
|
|
122
123
|
<SidePanelSection>
|
|
123
|
-
<
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<SBFlexboxItem>
|
|
135
|
-
<PanelLabel>
|
|
136
|
-
<FormattedMessage id="panel.text.alignment" />
|
|
137
|
-
</PanelLabel>
|
|
138
|
-
<ItemSelector
|
|
139
|
-
{...LAYER_TEXT_CONFIGS.textAlignment}
|
|
140
|
-
selectedItems={tl.alignment}
|
|
141
|
-
onChange={val => updateLayerTextLabel(idx, 'alignment', val)}
|
|
142
|
-
/>
|
|
143
|
-
</SBFlexboxItem>
|
|
144
|
-
</SpaceBetweenFlexbox>
|
|
124
|
+
<PanelLabel>
|
|
125
|
+
<FormattedMessage id="panel.text.outlineColor" />
|
|
126
|
+
</PanelLabel>
|
|
127
|
+
<ColorSelector
|
|
128
|
+
colorSets={[
|
|
129
|
+
{
|
|
130
|
+
selectedColor: tl.outlineColor,
|
|
131
|
+
setColor: v => updateLayerTextLabel(idx, 'outlineColor', v)
|
|
132
|
+
}
|
|
133
|
+
]}
|
|
134
|
+
/>
|
|
145
135
|
</SidePanelSection>
|
|
136
|
+
{idx === 0 && (
|
|
137
|
+
<SidePanelSection>
|
|
138
|
+
<SpaceBetweenFlexbox>
|
|
139
|
+
<SBFlexboxItem>
|
|
140
|
+
<PanelLabel>
|
|
141
|
+
<FormattedMessage id="panel.text.textAnchor" />
|
|
142
|
+
</PanelLabel>
|
|
143
|
+
<ItemSelector
|
|
144
|
+
{...LAYER_TEXT_CONFIGS.textAnchor}
|
|
145
|
+
selectedItems={tl.anchor}
|
|
146
|
+
onChange={val => updateLayerTextLabel(idx, 'anchor', val)}
|
|
147
|
+
/>
|
|
148
|
+
</SBFlexboxItem>
|
|
149
|
+
<SBFlexboxItem>
|
|
150
|
+
<PanelLabel>
|
|
151
|
+
<FormattedMessage id="panel.text.alignment" />
|
|
152
|
+
</PanelLabel>
|
|
153
|
+
<ItemSelector
|
|
154
|
+
{...LAYER_TEXT_CONFIGS.textAlignment}
|
|
155
|
+
selectedItems={tl.alignment}
|
|
156
|
+
onChange={val => updateLayerTextLabel(idx, 'alignment', val)}
|
|
157
|
+
/>
|
|
158
|
+
</SBFlexboxItem>
|
|
159
|
+
</SpaceBetweenFlexbox>
|
|
160
|
+
</SidePanelSection>
|
|
161
|
+
)}
|
|
146
162
|
</div>
|
|
147
163
|
))}
|
|
148
164
|
<SidePanelSection>
|
|
149
|
-
<AddButton
|
|
165
|
+
<AddButton
|
|
166
|
+
disabled={textLabel.length >= 2}
|
|
167
|
+
onClick={val => updateLayerTextLabel(textLabel.length)}
|
|
168
|
+
/>
|
|
150
169
|
</SidePanelSection>
|
|
151
170
|
</ConfigGroupCollapsibleContent>
|
|
152
171
|
</LayerConfigGroup>
|
|
@@ -403,11 +403,11 @@ export const FILED_TYPE_DISPLAY = {
|
|
|
403
403
|
color: BLUE2
|
|
404
404
|
},
|
|
405
405
|
[ALL_FIELD_TYPES.integer]: {
|
|
406
|
-
label: '
|
|
406
|
+
label: 'number',
|
|
407
407
|
color: ORANGE
|
|
408
408
|
},
|
|
409
409
|
[ALL_FIELD_TYPES.real]: {
|
|
410
|
-
label: '
|
|
410
|
+
label: 'number',
|
|
411
411
|
color: ORANGE
|
|
412
412
|
},
|
|
413
413
|
[ALL_FIELD_TYPES.string]: {
|
package/src/layers/base-layer.js
CHANGED
|
@@ -20,40 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
import {console as Console} from 'global/window';
|
|
22
22
|
import keymirror from 'keymirror';
|
|
23
|
-
import {DataFilterExtension} from '@deck.gl/extensions';
|
|
23
|
+
import {CollisionFilterExtension, DataFilterExtension} from '@deck.gl/extensions';
|
|
24
24
|
import {COORDINATE_SYSTEM, Layer as DeckLayer} from '@deck.gl/core';
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
// Workaround until https://github.com/visgl/deck.gl/pull/7513 is released
|
|
28
|
-
DeckLayer.defaultProps.getFilterValue = {type: 'accessor', value: 0};
|
|
29
|
-
|
|
30
|
-
// Workaround until https://github.com/visgl/deck.gl/pull/7507 is released
|
|
31
|
-
function deepEqual(a, b) {
|
|
32
|
-
if (a === b) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
if (!a || !b) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
for (const key in a) {
|
|
39
|
-
const aValue = a[key];
|
|
40
|
-
const bValue = b[key];
|
|
41
|
-
const equals = aValue === bValue || deepEqual(aValue, bValue);
|
|
42
|
-
if (!equals) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
DeckLayer.defaultProps.loadOptions = {
|
|
50
|
-
type: 'object',
|
|
51
|
-
value: {},
|
|
52
|
-
optional: true,
|
|
53
|
-
compare: true,
|
|
54
|
-
equal: deepEqual
|
|
55
|
-
};
|
|
56
|
-
|
|
25
|
+
import {_PointLabelLayer as PointLabelLayer} from '@deck.gl/carto';
|
|
57
26
|
import DefaultLayerIcon from './default-layer-icon';
|
|
58
27
|
import {diffUpdateTriggers} from './layer-update';
|
|
59
28
|
|
|
@@ -103,6 +72,7 @@ const FALLBACK_ICON =
|
|
|
103
72
|
const MAX_SAMPLE_SIZE = 5000;
|
|
104
73
|
const defaultDomain = [0, 1];
|
|
105
74
|
const dataFilterExtension = new DataFilterExtension({filterSize: MAX_GPU_FILTERS});
|
|
75
|
+
const collisionFilterExtension = new CollisionFilterExtension();
|
|
106
76
|
|
|
107
77
|
const defaultDataAccessor = dc => d => d;
|
|
108
78
|
const defaultGetFieldValue = (field, d) => field.valueAccessor(d);
|
|
@@ -1341,51 +1311,89 @@ class Layer {
|
|
|
1341
1311
|
};
|
|
1342
1312
|
}
|
|
1343
1313
|
|
|
1344
|
-
renderTextLabelLayer(
|
|
1314
|
+
renderTextLabelLayer(
|
|
1315
|
+
{getPosition, getRadius, radiusScale, updateTriggers, sharedProps},
|
|
1316
|
+
renderOpts
|
|
1317
|
+
) {
|
|
1345
1318
|
const {data, mapState} = renderOpts;
|
|
1346
1319
|
const {textLabel, visibilityByZoom} = this.config;
|
|
1320
|
+
const extensions = [...sharedProps.extensions, collisionFilterExtension];
|
|
1347
1321
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1322
|
+
if (!data || !data.textLabels || !data.textLabels[0] || !data.textLabels[0].getText) {
|
|
1323
|
+
return [];
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
const [mainLabel, secondaryLabel] = textLabel;
|
|
1327
|
+
const {
|
|
1328
|
+
alignment,
|
|
1329
|
+
anchor,
|
|
1330
|
+
color: getColor,
|
|
1331
|
+
field: mainField,
|
|
1332
|
+
outlineColor,
|
|
1333
|
+
size: sizeScale
|
|
1334
|
+
} = mainLabel;
|
|
1335
|
+
const {
|
|
1336
|
+
color: getSecondaryColor,
|
|
1337
|
+
field: secondaryField,
|
|
1338
|
+
outlineColor: secondaryOutlineColor,
|
|
1339
|
+
size: secondarySizeScale
|
|
1340
|
+
} = secondaryLabel || {};
|
|
1341
|
+
|
|
1342
|
+
return [
|
|
1343
|
+
new PointLabelLayer({
|
|
1344
|
+
...sharedProps,
|
|
1345
|
+
|
|
1346
|
+
// Recreate layer when labels change otherwise rendering breaks
|
|
1347
|
+
// TODO could be more efficient with updateTriggers?
|
|
1348
|
+
id: `${this.id}-${mainField?.name}-${secondaryField?.name}-label`,
|
|
1349
|
+
data: data.data,
|
|
1350
|
+
visibilityByZoom,
|
|
1351
|
+
extensions,
|
|
1352
|
+
|
|
1353
|
+
characterSet: 'auto',
|
|
1354
|
+
collisionEnabled: true,
|
|
1355
|
+
collisionGroup: `${this.id}-labels`,
|
|
1356
|
+
|
|
1357
|
+
getText: data.textLabels[0].getText,
|
|
1358
|
+
getColor,
|
|
1359
|
+
sizeScale,
|
|
1360
|
+
outlineColor,
|
|
1361
|
+
|
|
1362
|
+
...(secondaryField && {
|
|
1363
|
+
getSecondaryText: data.textLabels[1].getText,
|
|
1364
|
+
getSecondaryColor,
|
|
1365
|
+
secondarySizeScale,
|
|
1366
|
+
secondaryOutlineColor
|
|
1367
|
+
}),
|
|
1368
|
+
|
|
1369
|
+
// Position
|
|
1370
|
+
getPosition,
|
|
1371
|
+
getRadius,
|
|
1372
|
+
radiusScale,
|
|
1373
|
+
getTextAnchor: anchor,
|
|
1374
|
+
getAlignmentBaseline: alignment,
|
|
1375
|
+
|
|
1376
|
+
// Style
|
|
1377
|
+
fontFamily: 'Inter, sans',
|
|
1378
|
+
fontSettings: {sdf: true},
|
|
1379
|
+
fontWeight: 500,
|
|
1380
|
+
outlineWidth: 4,
|
|
1381
|
+
parameters: {
|
|
1382
|
+
// text will always show on top of all layers
|
|
1383
|
+
depthTest: false
|
|
1384
|
+
},
|
|
1385
|
+
|
|
1386
|
+
getFilterValue: data.getFilterValue,
|
|
1387
|
+
updateTriggers: {
|
|
1388
|
+
...updateTriggers,
|
|
1389
|
+
getText: mainField?.name,
|
|
1390
|
+
getColor: mainField?.color,
|
|
1391
|
+
getTextAnchor: mainLabel.anchor,
|
|
1392
|
+
getAlignmentBaseline: mainLabel.alignment,
|
|
1393
|
+
getSecondaryText: secondaryField?.name
|
|
1394
|
+
}
|
|
1395
|
+
})
|
|
1396
|
+
];
|
|
1389
1397
|
}
|
|
1390
1398
|
|
|
1391
1399
|
/**
|
|
@@ -43,13 +43,21 @@ export {DEFAULT_COLOR_RANGE};
|
|
|
43
43
|
/** @type {import('./layer-factory').LayerTextLabel} */
|
|
44
44
|
export const DEFAULT_TEXT_LABEL = {
|
|
45
45
|
field: null,
|
|
46
|
-
color: [
|
|
47
|
-
|
|
46
|
+
color: [44, 48, 50],
|
|
47
|
+
outlineColor: [255, 255, 255],
|
|
48
|
+
size: 12,
|
|
48
49
|
offset: [0, 0],
|
|
49
50
|
anchor: 'start',
|
|
50
51
|
alignment: 'center'
|
|
51
52
|
};
|
|
52
53
|
|
|
54
|
+
/** @type {import('./layer-factory').LayerTextLabel} */
|
|
55
|
+
export const DEFAULT_SECONDARY_TEXT_LABEL = {
|
|
56
|
+
...DEFAULT_TEXT_LABEL,
|
|
57
|
+
color: [128, 130, 132],
|
|
58
|
+
size: 10
|
|
59
|
+
};
|
|
60
|
+
|
|
53
61
|
/** @type {import('./layer-factory').ColorRange} */
|
|
54
62
|
export const DEFAULT_CUSTOM_PALETTE = {
|
|
55
63
|
name: 'color.customPalette',
|
|
@@ -450,8 +458,8 @@ export const LAYER_VIS_CONFIGS = {
|
|
|
450
458
|
export const LAYER_TEXT_CONFIGS = {
|
|
451
459
|
fontSize: {
|
|
452
460
|
type: 'number',
|
|
453
|
-
range: [
|
|
454
|
-
value0:
|
|
461
|
+
range: [6, 32],
|
|
462
|
+
value0: 6,
|
|
455
463
|
step: 1,
|
|
456
464
|
isRanged: false,
|
|
457
465
|
label: 'Font size',
|
|
@@ -54,40 +54,9 @@ export const textLabelAccessor = textLabel => dc => d => {
|
|
|
54
54
|
return notNullorUndefined(val) ? String(val) : '';
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
export const formatTextLabelData = ({
|
|
58
|
-
textLabel,
|
|
59
|
-
triggerChanged,
|
|
60
|
-
oldLayerData,
|
|
61
|
-
data,
|
|
62
|
-
dataContainer
|
|
63
|
-
}) => {
|
|
57
|
+
export const formatTextLabelData = ({textLabel, dataContainer}) => {
|
|
64
58
|
return textLabel.map((tl, i) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
getText: null,
|
|
69
|
-
characterSet: []
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const getText = textLabelAccessor(tl)(dataContainer);
|
|
74
|
-
let characterSet;
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
!triggerChanged[`getLabelCharacterSet-${i}`] &&
|
|
78
|
-
oldLayerData &&
|
|
79
|
-
oldLayerData.textLabels &&
|
|
80
|
-
oldLayerData.textLabels[i]
|
|
81
|
-
) {
|
|
82
|
-
characterSet = oldLayerData.textLabels[i].characterSet;
|
|
83
|
-
} else {
|
|
84
|
-
const allLabels = tl.field ? data.map(getText) : [];
|
|
85
|
-
characterSet = uniq(allLabels.join(''));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
characterSet,
|
|
90
|
-
getText
|
|
91
|
-
};
|
|
59
|
+
const getText = tl.field ? textLabelAccessor(tl)(dataContainer) : null;
|
|
60
|
+
return {getText};
|
|
92
61
|
});
|
|
93
62
|
};
|
|
@@ -29,7 +29,7 @@ import {findDefaultColorField} from 'utils/dataset-utils';
|
|
|
29
29
|
import PointLayerIcon from './point-layer-icon';
|
|
30
30
|
import {DEFAULT_LAYER_COLOR, CHANNEL_SCALES, UNKNOWN_COLOR} from 'constants/default-settings';
|
|
31
31
|
|
|
32
|
-
import {
|
|
32
|
+
import {formatTextLabelData} from '../layer-text-label';
|
|
33
33
|
|
|
34
34
|
export const pointPosAccessor = ({lat, lng, altitude}) => dc => d => [
|
|
35
35
|
dc.valueAt(d.index, lng.fieldIdx),
|
|
@@ -242,13 +242,7 @@ export default class PointLayer extends Layer {
|
|
|
242
242
|
const getPosition = this.getPositionAccessor(dataContainer);
|
|
243
243
|
|
|
244
244
|
// get all distinct characters in the text labels
|
|
245
|
-
const textLabels = formatTextLabelData({
|
|
246
|
-
textLabel,
|
|
247
|
-
triggerChanged,
|
|
248
|
-
oldLayerData,
|
|
249
|
-
data,
|
|
250
|
-
dataContainer
|
|
251
|
-
});
|
|
245
|
+
const textLabels = formatTextLabelData({textLabel, dataContainer});
|
|
252
246
|
|
|
253
247
|
const accessors = this.getAttributeAccessors({dataContainer});
|
|
254
248
|
|
|
@@ -278,12 +272,12 @@ export default class PointLayer extends Layer {
|
|
|
278
272
|
// eslint-disable-next-line complexity, max-statements
|
|
279
273
|
renderLayer(opts) {
|
|
280
274
|
const {data, gpuFilter, objectHovered, interactionConfig} = opts;
|
|
275
|
+
const {customMarkers, customMarkersUrl, customMarkersRange} = this.config.visConfig;
|
|
281
276
|
|
|
282
277
|
const radiusScale = this.getRadiusScale();
|
|
283
278
|
|
|
284
279
|
const defaultLayerProps = this.getDefaultDeckLayerProps(opts);
|
|
285
280
|
const brushingProps = this.getBrushingExtensionProps(interactionConfig);
|
|
286
|
-
const getPixelOffset = getTextOffsetByRadius(radiusScale, data.getRadius);
|
|
287
281
|
const extensions = [...defaultLayerProps.extensions, brushingExtension];
|
|
288
282
|
|
|
289
283
|
const updateTriggers = {
|
|
@@ -296,6 +290,7 @@ export default class PointLayer extends Layer {
|
|
|
296
290
|
getFilterValue: data.getFilterValue,
|
|
297
291
|
extensions,
|
|
298
292
|
filterRange: defaultLayerProps.filterRange,
|
|
293
|
+
maskId: defaultLayerProps.maskId,
|
|
299
294
|
visible: defaultLayerProps.visible,
|
|
300
295
|
...brushingProps
|
|
301
296
|
};
|
|
@@ -305,7 +300,9 @@ export default class PointLayer extends Layer {
|
|
|
305
300
|
{
|
|
306
301
|
getPosition: data.getPosition,
|
|
307
302
|
sharedProps,
|
|
308
|
-
|
|
303
|
+
// TODO remove this scaling by half here and elsewhere
|
|
304
|
+
radiusScale: customMarkers ? radiusScale / 2 : radiusScale,
|
|
305
|
+
getRadius: data.getRadius,
|
|
309
306
|
updateTriggers
|
|
310
307
|
},
|
|
311
308
|
opts
|
|
@@ -319,7 +316,6 @@ export default class PointLayer extends Layer {
|
|
|
319
316
|
};
|
|
320
317
|
|
|
321
318
|
const customMarkersField = this.config.customMarkersField;
|
|
322
|
-
const {customMarkers, customMarkersUrl, customMarkersRange} = this.config.visConfig;
|
|
323
319
|
const customMarkersConfigured =
|
|
324
320
|
customMarkers && Boolean(customMarkersUrl || (customMarkersField && customMarkersRange));
|
|
325
321
|
const customMarkersMisConfigured = customMarkers && !customMarkersConfigured;
|
package/src/localization/en.js
CHANGED
|
@@ -68,12 +68,14 @@ export default {
|
|
|
68
68
|
panel: {
|
|
69
69
|
text: {
|
|
70
70
|
label: 'label',
|
|
71
|
-
|
|
71
|
+
mainLabel: 'Main Label',
|
|
72
|
+
secondaryLabel: 'Secondary Label',
|
|
72
73
|
fontSize: 'Font size',
|
|
73
74
|
fontColor: 'Font color',
|
|
75
|
+
outlineColor: 'Outline color',
|
|
74
76
|
textAnchor: 'Text anchor',
|
|
75
77
|
alignment: 'Alignment',
|
|
76
|
-
addMoreLabel: 'Add
|
|
78
|
+
addMoreLabel: 'Add secondary label'
|
|
77
79
|
}
|
|
78
80
|
},
|
|
79
81
|
sidebar: {
|
|
@@ -81,7 +83,7 @@ export default {
|
|
|
81
83
|
layer: 'Layers',
|
|
82
84
|
filter: 'Filters',
|
|
83
85
|
interaction: 'Interactions',
|
|
84
|
-
basemap: '
|
|
86
|
+
basemap: 'Basemap'
|
|
85
87
|
}
|
|
86
88
|
},
|
|
87
89
|
layer: {
|
|
@@ -157,6 +159,7 @@ export default {
|
|
|
157
159
|
highPrecisionRenderingDescription: 'High precision will result in slower performance',
|
|
158
160
|
height: 'Height',
|
|
159
161
|
heightDescription: 'Click button at top right of the map to switch to 3d view',
|
|
162
|
+
labels: 'Labels',
|
|
160
163
|
fill: 'Fill',
|
|
161
164
|
enablePolygonHeight: 'Enable Polygon Height',
|
|
162
165
|
showWireframe: 'Show Wireframe',
|
|
@@ -213,7 +216,7 @@ export default {
|
|
|
213
216
|
hideLayerPanel: 'Hide layer panel',
|
|
214
217
|
showLayerPanel: 'Show layer panel',
|
|
215
218
|
moveToTop: 'Move to top of data layers',
|
|
216
|
-
selectBaseMapStyle: 'Select
|
|
219
|
+
selectBaseMapStyle: 'Select Basemap Style',
|
|
217
220
|
delete: 'Delete',
|
|
218
221
|
timePlayback: 'Time Playback',
|
|
219
222
|
cloudStorage: 'Cloud Storage',
|
|
@@ -288,10 +288,7 @@ export function getFieldsFromData(data, fieldOrder) {
|
|
|
288
288
|
// add a check for epoch timestamp
|
|
289
289
|
const metadata = Analyzer.computeColMeta(
|
|
290
290
|
data,
|
|
291
|
-
[
|
|
292
|
-
{regex: /.*geojson|all_points/g, dataType: 'GEOMETRY'},
|
|
293
|
-
{regex: /.*census/g, dataType: 'STRING'}
|
|
294
|
-
],
|
|
291
|
+
[{regex: /.*geojson|all_points/g, dataType: 'GEOMETRY'}],
|
|
295
292
|
{ignoredDataTypes: IGNORE_DATA_TYPES}
|
|
296
293
|
);
|
|
297
294
|
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
} from 'utils/split-map-utils';
|
|
77
77
|
|
|
78
78
|
import {Layer, LayerClasses, LAYER_ID_LENGTH} from 'layers';
|
|
79
|
-
import {DEFAULT_TEXT_LABEL} from 'layers/layer-factory';
|
|
79
|
+
import {DEFAULT_TEXT_LABEL, DEFAULT_SECONDARY_TEXT_LABEL} from 'layers/layer-factory';
|
|
80
80
|
import {EDITOR_MODES, SORT_ORDER, FILTER_TYPES} from 'constants/default-settings';
|
|
81
81
|
import {pick_, merge_, swap_} from './composer-helpers';
|
|
82
82
|
import {processFileContent} from 'actions/vis-state-actions';
|
|
@@ -315,16 +315,19 @@ function addOrRemoveTextLabels(newFields, textLabel) {
|
|
|
315
315
|
|
|
316
316
|
// delete
|
|
317
317
|
newTextLabel = newTextLabel.filter(tl => tl.field && !deleteFields.includes(tl.field.name));
|
|
318
|
-
newTextLabel = !newTextLabel.length ? [DEFAULT_TEXT_LABEL] : newTextLabel;
|
|
319
318
|
|
|
320
319
|
// add
|
|
321
|
-
newTextLabel =
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
320
|
+
newTextLabel = newTextLabel.filter(tl => tl.field);
|
|
321
|
+
const defaultLabel = newTextLabel.length ? DEFAULT_SECONDARY_TEXT_LABEL : DEFAULT_TEXT_LABEL;
|
|
322
|
+
newTextLabel = [...newTextLabel, ...addFields.map(af => ({...defaultLabel, field: af}))];
|
|
323
|
+
|
|
324
|
+
// limit to 2 labels (overwrite 2nd label with 3rd)
|
|
325
|
+
if (newTextLabel.length > 2) {
|
|
326
|
+
newTextLabel = [newTextLabel[0], newTextLabel[2]];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// default
|
|
330
|
+
newTextLabel = !newTextLabel.length ? [DEFAULT_TEXT_LABEL] : newTextLabel;
|
|
328
331
|
|
|
329
332
|
return newTextLabel;
|
|
330
333
|
}
|
|
@@ -359,7 +362,7 @@ export function layerTextLabelChangeUpdater(state, action) {
|
|
|
359
362
|
let newTextLabel = textLabel.slice();
|
|
360
363
|
if (!textLabel[idx] && idx === textLabel.length) {
|
|
361
364
|
// if idx is set to length, add empty text label
|
|
362
|
-
newTextLabel = [...textLabel, DEFAULT_TEXT_LABEL];
|
|
365
|
+
newTextLabel = [...textLabel, idx === 0 ? DEFAULT_TEXT_LABEL : DEFAULT_SECONDARY_TEXT_LABEL];
|
|
363
366
|
}
|
|
364
367
|
|
|
365
368
|
if (idx === 'all' && prop === 'fields') {
|