@carto/kepler.gl 0.0.64 → 0.0.65-alpha.labels.10
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 +899 -0
- package/README.md +42 -651
- package/dist/components/side-panel/layer-panel/layer-config-group.js +3 -3
- package/dist/components/side-panel/layer-panel/layer-configurator.js +2 -1
- package/dist/components/side-panel/layer-panel/text-label-panel.js +15 -7
- package/dist/constants/default-settings.js +2 -2
- package/dist/layers/base-layer.js +73 -77
- package/dist/layers/layer-factory.js +38 -26
- package/dist/layers/layer-text-label.js +11 -31
- package/dist/layers/point-layer/point-layer.js +10 -10
- package/dist/localization/en.js +6 -3
- package/dist/processors/data-processor.js +1 -4
- package/dist/reducers/vis-state-updaters.js +16 -8
- package/package.json +13 -8
- package/src/.index.js.swp +0 -0
- package/src/components/side-panel/layer-panel/layer-config-group.js +2 -2
- package/src/components/side-panel/layer-panel/layer-configurator.js +1 -0
- package/src/components/side-panel/layer-panel/text-label-panel.js +45 -26
- package/src/layers/base-layer.js +83 -75
- package/src/layers/layer-factory.js +27 -4
- package/src/layers/layer-text-label.js +11 -47
- package/src/layers/point-layer/point-layer.js +8 -11
- package/src/localization/en.js +5 -2
- 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.65-alpha.labels.10",
|
|
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
|
}
|
|
Binary file
|
|
@@ -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 {
|
|
@@ -246,6 +246,7 @@ export default function LayerConfiguratorFactory(
|
|
|
246
246
|
{/* text label */}
|
|
247
247
|
<TextLabelPanel
|
|
248
248
|
fields={visConfiguratorProps.fields}
|
|
249
|
+
layer={layer}
|
|
249
250
|
updateLayerTextLabel={this.props.updateLayerTextLabel}
|
|
250
251
|
textLabel={layer.config.textLabel}
|
|
251
252
|
colorPalette={visConfiguratorProps.colorPalette}
|
|
@@ -65,8 +65,9 @@ function TextLabelPanelFactory(RangeSlider, LayerConfigGroup, FieldSelector, Col
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
render() {
|
|
68
|
-
const {updateLayerTextLabel, textLabel, fields, AddButton} = this.props;
|
|
68
|
+
const {layer, 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>
|
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
|
/**
|
|
@@ -27,6 +27,7 @@ export const PROPERTY_GROUPS = keyMirror({
|
|
|
27
27
|
color: null,
|
|
28
28
|
stroke: null,
|
|
29
29
|
customMarkers: null,
|
|
30
|
+
labels: null,
|
|
30
31
|
radius: null,
|
|
31
32
|
height: null,
|
|
32
33
|
angle: null,
|
|
@@ -43,13 +44,21 @@ export {DEFAULT_COLOR_RANGE};
|
|
|
43
44
|
/** @type {import('./layer-factory').LayerTextLabel} */
|
|
44
45
|
export const DEFAULT_TEXT_LABEL = {
|
|
45
46
|
field: null,
|
|
46
|
-
color: [
|
|
47
|
-
|
|
47
|
+
color: [44, 48, 50],
|
|
48
|
+
outlineColor: [255, 255, 255],
|
|
49
|
+
size: 12,
|
|
48
50
|
offset: [0, 0],
|
|
49
51
|
anchor: 'start',
|
|
50
52
|
alignment: 'center'
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
/** @type {import('./layer-factory').LayerTextLabel} */
|
|
56
|
+
export const DEFAULT_SECONDARY_TEXT_LABEL = {
|
|
57
|
+
...DEFAULT_TEXT_LABEL,
|
|
58
|
+
color: [128, 130, 132],
|
|
59
|
+
size: 10
|
|
60
|
+
};
|
|
61
|
+
|
|
53
62
|
/** @type {import('./layer-factory').ColorRange} */
|
|
54
63
|
export const DEFAULT_CUSTOM_PALETTE = {
|
|
55
64
|
name: 'color.customPalette',
|
|
@@ -387,6 +396,13 @@ export const LAYER_VIS_CONFIGS = {
|
|
|
387
396
|
group: PROPERTY_GROUPS.display,
|
|
388
397
|
property: 'filled'
|
|
389
398
|
},
|
|
399
|
+
labels: {
|
|
400
|
+
type: 'boolean',
|
|
401
|
+
label: 'layerVisConfigs.labels',
|
|
402
|
+
defaultValue: false,
|
|
403
|
+
group: PROPERTY_GROUPS.labels,
|
|
404
|
+
property: 'labels'
|
|
405
|
+
},
|
|
390
406
|
extruded: {
|
|
391
407
|
type: 'boolean',
|
|
392
408
|
defaultValue: false,
|
|
@@ -430,6 +446,13 @@ export const LAYER_VIS_CONFIGS = {
|
|
|
430
446
|
group: PROPERTY_GROUPS.customMarkers,
|
|
431
447
|
property: 'customMarkers'
|
|
432
448
|
},
|
|
449
|
+
labelsEnabled: {
|
|
450
|
+
type: 'boolean',
|
|
451
|
+
defaultValue: true,
|
|
452
|
+
label: 'layerVisConfigs.labelsEnabled',
|
|
453
|
+
group: PROPERTY_GROUPS.labels,
|
|
454
|
+
property: 'labelsEnabled'
|
|
455
|
+
},
|
|
433
456
|
customMarkersUrl: {
|
|
434
457
|
type: 'text',
|
|
435
458
|
defaultValue: '',
|
|
@@ -450,8 +473,8 @@ export const LAYER_VIS_CONFIGS = {
|
|
|
450
473
|
export const LAYER_TEXT_CONFIGS = {
|
|
451
474
|
fontSize: {
|
|
452
475
|
type: 'number',
|
|
453
|
-
range: [
|
|
454
|
-
value0:
|
|
476
|
+
range: [6, 32],
|
|
477
|
+
value0: 6,
|
|
455
478
|
step: 1,
|
|
456
479
|
isRanged: false,
|
|
457
480
|
label: 'Font size',
|
|
@@ -21,30 +21,25 @@
|
|
|
21
21
|
import {notNullorUndefined} from 'utils/data-utils';
|
|
22
22
|
import uniq from 'lodash.uniq';
|
|
23
23
|
|
|
24
|
-
export const defaultPadding = 20;
|
|
25
|
-
|
|
26
24
|
export function getTextOffsetByRadius(radiusScale, getRadius) {
|
|
27
25
|
return textLabel => {
|
|
28
26
|
const xMult = textLabel.anchor === 'middle' ? 0 : textLabel.anchor === 'start' ? 1 : -1;
|
|
29
27
|
const yMult = textLabel.alignment === 'center' ? 0 : textLabel.alignment === 'bottom' ? 1 : -1;
|
|
30
28
|
|
|
31
|
-
const sizeOffset =
|
|
32
|
-
textLabel.alignment === 'center'
|
|
33
|
-
? 0
|
|
34
|
-
: textLabel.alignment === 'bottom'
|
|
35
|
-
? textLabel.size
|
|
36
|
-
: textLabel.size;
|
|
29
|
+
const sizeOffset = Math.abs(yMult * textLabel.size);
|
|
37
30
|
|
|
38
|
-
const
|
|
31
|
+
const xPadding = textLabel.size / 4; // Padding based on font size (font size / 4)
|
|
32
|
+
const yPadding = textLabel.size;
|
|
33
|
+
const radiusPadding = 1 + 1 / 4; // Padding based on point radius (radius/ 4)
|
|
39
34
|
|
|
40
35
|
return typeof getRadius === 'function'
|
|
41
36
|
? d => [
|
|
42
|
-
xMult * (getRadius(d) * radiusScale +
|
|
43
|
-
yMult * (getRadius(d) * radiusScale
|
|
37
|
+
xMult * (getRadius(d) * radiusScale * radiusPadding + xPadding),
|
|
38
|
+
yMult * (getRadius(d) * radiusScale * radiusPadding + yPadding)
|
|
44
39
|
]
|
|
45
40
|
: [
|
|
46
|
-
xMult * (getRadius * radiusScale +
|
|
47
|
-
yMult * (getRadius * radiusScale
|
|
41
|
+
xMult * (getRadius * radiusScale * radiusPadding + xPadding),
|
|
42
|
+
yMult * (getRadius * radiusScale * radiusPadding + yPadding)
|
|
48
43
|
];
|
|
49
44
|
};
|
|
50
45
|
}
|
|
@@ -54,40 +49,9 @@ export const textLabelAccessor = textLabel => dc => d => {
|
|
|
54
49
|
return notNullorUndefined(val) ? String(val) : '';
|
|
55
50
|
};
|
|
56
51
|
|
|
57
|
-
export const formatTextLabelData = ({
|
|
58
|
-
textLabel,
|
|
59
|
-
triggerChanged,
|
|
60
|
-
oldLayerData,
|
|
61
|
-
data,
|
|
62
|
-
dataContainer
|
|
63
|
-
}) => {
|
|
52
|
+
export const formatTextLabelData = ({textLabel, dataContainer}) => {
|
|
64
53
|
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
|
-
};
|
|
54
|
+
const getText = tl.field ? textLabelAccessor(tl)(dataContainer) : null;
|
|
55
|
+
return {getText};
|
|
92
56
|
});
|
|
93
57
|
};
|
|
@@ -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),
|
|
@@ -47,6 +47,7 @@ export const pointVisConfigs = {
|
|
|
47
47
|
customMarkers: 'customMarkers',
|
|
48
48
|
customMarkersUrl: 'customMarkersUrl',
|
|
49
49
|
customMarkersRange: 'customMarkersRange',
|
|
50
|
+
labelsEnabled: 'labelsEnabled',
|
|
50
51
|
opacity: 'opacity',
|
|
51
52
|
outline: 'outline',
|
|
52
53
|
thickness: 'thickness',
|
|
@@ -242,13 +243,7 @@ export default class PointLayer extends Layer {
|
|
|
242
243
|
const getPosition = this.getPositionAccessor(dataContainer);
|
|
243
244
|
|
|
244
245
|
// get all distinct characters in the text labels
|
|
245
|
-
const textLabels = formatTextLabelData({
|
|
246
|
-
textLabel,
|
|
247
|
-
triggerChanged,
|
|
248
|
-
oldLayerData,
|
|
249
|
-
data,
|
|
250
|
-
dataContainer
|
|
251
|
-
});
|
|
246
|
+
const textLabels = formatTextLabelData({textLabel, dataContainer});
|
|
252
247
|
|
|
253
248
|
const accessors = this.getAttributeAccessors({dataContainer});
|
|
254
249
|
|
|
@@ -278,12 +273,12 @@ export default class PointLayer extends Layer {
|
|
|
278
273
|
// eslint-disable-next-line complexity, max-statements
|
|
279
274
|
renderLayer(opts) {
|
|
280
275
|
const {data, gpuFilter, objectHovered, interactionConfig} = opts;
|
|
276
|
+
const {customMarkers, customMarkersUrl, customMarkersRange} = this.config.visConfig;
|
|
281
277
|
|
|
282
278
|
const radiusScale = this.getRadiusScale();
|
|
283
279
|
|
|
284
280
|
const defaultLayerProps = this.getDefaultDeckLayerProps(opts);
|
|
285
281
|
const brushingProps = this.getBrushingExtensionProps(interactionConfig);
|
|
286
|
-
const getPixelOffset = getTextOffsetByRadius(radiusScale, data.getRadius);
|
|
287
282
|
const extensions = [...defaultLayerProps.extensions, brushingExtension];
|
|
288
283
|
|
|
289
284
|
const updateTriggers = {
|
|
@@ -296,6 +291,7 @@ export default class PointLayer extends Layer {
|
|
|
296
291
|
getFilterValue: data.getFilterValue,
|
|
297
292
|
extensions,
|
|
298
293
|
filterRange: defaultLayerProps.filterRange,
|
|
294
|
+
maskId: defaultLayerProps.maskId,
|
|
299
295
|
visible: defaultLayerProps.visible,
|
|
300
296
|
...brushingProps
|
|
301
297
|
};
|
|
@@ -305,7 +301,9 @@ export default class PointLayer extends Layer {
|
|
|
305
301
|
{
|
|
306
302
|
getPosition: data.getPosition,
|
|
307
303
|
sharedProps,
|
|
308
|
-
|
|
304
|
+
// TODO remove this scaling by half here and elsewhere
|
|
305
|
+
radiusScale: customMarkers ? radiusScale / 2 : radiusScale,
|
|
306
|
+
getRadius: data.getRadius,
|
|
309
307
|
updateTriggers
|
|
310
308
|
},
|
|
311
309
|
opts
|
|
@@ -319,7 +317,6 @@ export default class PointLayer extends Layer {
|
|
|
319
317
|
};
|
|
320
318
|
|
|
321
319
|
const customMarkersField = this.config.customMarkersField;
|
|
322
|
-
const {customMarkers, customMarkersUrl, customMarkersRange} = this.config.visConfig;
|
|
323
320
|
const customMarkersConfigured =
|
|
324
321
|
customMarkers && Boolean(customMarkersUrl || (customMarkersField && customMarkersRange));
|
|
325
322
|
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: {
|
|
@@ -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',
|
|
@@ -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') {
|