@mwater/visualization 5.6.0 → 5.6.1
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/lib/ColorComponent.js +2 -2
- package/lib/TranslationsTabComponent.d.ts +34 -0
- package/lib/TranslationsTabComponent.js +256 -0
- package/lib/dashboards/DashboardComponent.js +1 -1
- package/lib/dashboards/ServerDashboardDataSource.d.ts +0 -1
- package/lib/dashboards/ServerDashboardDataSource.js +0 -15
- package/lib/dashboards/SettingsModalComponent.js +9 -233
- package/lib/datagrids/DatagridComponent.js +5 -0
- package/lib/datagrids/DatagridViewComponent.js +30 -4
- package/lib/maps/BufferLayer.d.ts +0 -13
- package/lib/maps/BufferLayer.js +12 -237
- package/lib/maps/BufferLayerDesignerComponent.d.ts +1 -1
- package/lib/maps/BufferLayerDesignerComponent.js +0 -5
- package/lib/maps/ChoroplethLayer.d.ts +1 -16
- package/lib/maps/ChoroplethLayer.js +13 -358
- package/lib/maps/ClusterLayer.d.ts +0 -9
- package/lib/maps/ClusterLayer.js +0 -250
- package/lib/maps/DirectMapDataSource.js +1 -38
- package/lib/maps/GridLayer.d.ts +0 -15
- package/lib/maps/GridLayer.js +0 -212
- package/lib/maps/Layer.d.ts +1 -26
- package/lib/maps/Layer.js +0 -13
- package/lib/maps/MapComponent.d.ts +19 -35
- package/lib/maps/MapComponent.js +135 -76
- package/lib/maps/MapControlComponent.d.ts +4 -5
- package/lib/maps/MapControlComponent.js +5 -12
- package/lib/maps/MapDesign.d.ts +8 -0
- package/lib/maps/MapDesignerComponent.d.ts +2 -0
- package/lib/maps/MapDesignerComponent.js +7 -2
- package/lib/maps/MapLayerDataSource.d.ts +0 -4
- package/lib/maps/MapLayerViewDesignerComponent.d.ts +3 -1
- package/lib/maps/MapLayerViewDesignerComponent.js +5 -1
- package/lib/maps/MapLayersDesignerComponent.d.ts +2 -0
- package/lib/maps/MapLayersDesignerComponent.js +2 -1
- package/lib/maps/MapTranslationsTab.d.ts +15 -0
- package/lib/maps/MapTranslationsTab.js +47 -0
- package/lib/maps/MapUtils.d.ts +11 -0
- package/lib/maps/MapUtils.js +47 -0
- package/lib/maps/MapViewComponent.d.ts +1 -1
- package/lib/maps/MapViewComponent.js +1 -8
- package/lib/maps/MarkersLayer.d.ts +1 -14
- package/lib/maps/MarkersLayer.js +71 -252
- package/lib/maps/MarkersLayerDesign.d.ts +4 -0
- package/lib/maps/MarkersLayerDesignerComponent.d.ts +20 -16
- package/lib/maps/MarkersLayerDesignerComponent.js +77 -23
- package/lib/maps/ServerMapDataSource.d.ts +0 -1
- package/lib/maps/ServerMapDataSource.js +0 -15
- package/lib/maps/SwitchableTileUrlLayer.d.ts +0 -2
- package/lib/maps/SwitchableTileUrlLayer.js +0 -9
- package/lib/maps/TileUrlLayer.d.ts +0 -1
- package/lib/maps/TileUrlLayer.js +0 -5
- package/lib/maps/VectorMapViewComponent.js +12 -1
- package/lib/maps/vectorMaps.d.ts +5 -6
- package/lib/maps/vectorMaps.js +13 -9
- package/lib/widgets/MapWidget.js +2 -1
- package/package.json +2 -2
- package/src/ColorComponent.tsx +2 -2
- package/src/TranslationsTabComponent.tsx +429 -0
- package/src/dashboards/DashboardComponent.tsx +1 -1
- package/src/dashboards/ServerDashboardDataSource.ts +0 -19
- package/src/dashboards/SettingsModalComponent.tsx +27 -383
- package/src/datagrids/DatagridComponent.tsx +6 -0
- package/src/datagrids/DatagridViewComponent.tsx +41 -5
- package/src/maps/BufferLayer.ts +16 -262
- package/src/maps/BufferLayerDesignerComponent.tsx +0 -6
- package/src/maps/ChoroplethLayer.ts +16 -393
- package/src/maps/ClusterLayer.ts +0 -274
- package/src/maps/DirectMapDataSource.ts +2 -49
- package/src/maps/GridLayer.ts +0 -224
- package/src/maps/Layer.ts +1 -35
- package/src/maps/MapComponent.tsx +448 -0
- package/src/maps/MapControlComponent.tsx +41 -0
- package/src/maps/MapDesign.ts +6 -0
- package/src/maps/MapDesignerComponent.tsx +18 -1
- package/src/maps/MapLayerDataSource.ts +0 -5
- package/src/maps/MapLayerViewDesignerComponent.ts +9 -2
- package/src/maps/MapLayersDesignerComponent.ts +4 -1
- package/src/maps/MapTranslationsTab.tsx +53 -0
- package/src/maps/MapUtils.ts +48 -0
- package/src/maps/MapViewComponent.tsx +2 -8
- package/src/maps/MarkersLayer.ts +79 -270
- package/src/maps/MarkersLayerDesign.ts +6 -0
- package/src/maps/MarkersLayerDesignerComponent.tsx +114 -38
- package/src/maps/ServerMapDataSource.ts +0 -19
- package/src/maps/SwitchableTileUrlLayer.tsx +0 -11
- package/src/maps/TileUrlLayer.tsx +0 -6
- package/src/maps/VectorMapViewComponent.tsx +13 -2
- package/src/maps/vectorMaps.tsx +12 -9
- package/src/widgets/MapWidget.tsx +2 -0
- package/src/maps/MapComponent.ts +0 -311
- package/src/maps/MapControlComponent.ts +0 -46
- package/src/maps/RasterMapViewComponent.ts +0 -345
package/src/maps/MapUtils.ts
CHANGED
|
@@ -8,6 +8,7 @@ import LayerFactory from "./LayerFactory"
|
|
|
8
8
|
import { MapDesign } from "./MapDesign"
|
|
9
9
|
import { produce } from "immer"
|
|
10
10
|
import { HoverOverItem } from "./maps"
|
|
11
|
+
import { Axis } from "../axes/Axis"
|
|
11
12
|
|
|
12
13
|
export interface MapScope {
|
|
13
14
|
name: string
|
|
@@ -172,6 +173,53 @@ export function getTranslatableStrings(design: MapDesign, schema: Schema): strin
|
|
|
172
173
|
return _.uniq(strings)
|
|
173
174
|
}
|
|
174
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Get translatable strings from an axis's categoryLabels and nullLabel.
|
|
178
|
+
* Always includes "None" since it's the default label for null values in AxisBuilder.
|
|
179
|
+
*/
|
|
180
|
+
export function getTranslatableStringsFromAxis(axis: Axis | null | undefined): string[] {
|
|
181
|
+
const strings: string[] = []
|
|
182
|
+
if (axis?.categoryLabels) {
|
|
183
|
+
strings.push(...Object.values(axis.categoryLabels))
|
|
184
|
+
}
|
|
185
|
+
if (axis?.nullLabel) {
|
|
186
|
+
strings.push(axis.nullLabel)
|
|
187
|
+
} else {
|
|
188
|
+
// Always include "None" as it's the default nullLabel in AxisBuilder
|
|
189
|
+
strings.push("None")
|
|
190
|
+
}
|
|
191
|
+
return strings
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Translate an axis's category labels and null label.
|
|
196
|
+
* If no nullLabel is set, translates the default "None" and sets it so AxisBuilder uses it.
|
|
197
|
+
*/
|
|
198
|
+
export function translateAxis(
|
|
199
|
+
axis: Axis | null | undefined,
|
|
200
|
+
translate: (input: string) => string
|
|
201
|
+
): Axis | null | undefined {
|
|
202
|
+
if (!axis) return axis
|
|
203
|
+
|
|
204
|
+
return produce(axis, draft => {
|
|
205
|
+
if (draft.categoryLabels) {
|
|
206
|
+
for (const key in draft.categoryLabels) {
|
|
207
|
+
draft.categoryLabels[key] = translate(draft.categoryLabels[key])
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (draft.nullLabel) {
|
|
211
|
+
draft.nullLabel = translate(draft.nullLabel)
|
|
212
|
+
} else {
|
|
213
|
+
// Translate the default "None" and set it so AxisBuilder uses it
|
|
214
|
+
// instead of falling back to T`None` which uses the global locale
|
|
215
|
+
const translatedNone = translate("None")
|
|
216
|
+
if (translatedNone !== "None") {
|
|
217
|
+
draft.nullLabel = translatedNone
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
175
223
|
/**
|
|
176
224
|
* Convenience function to get hover over data for a map given an id and a list of hover over items
|
|
177
225
|
*/
|
|
@@ -6,8 +6,6 @@ import { MapDesign } from "./MapDesign"
|
|
|
6
6
|
import { MapDataSource } from "./MapDataSource"
|
|
7
7
|
import { VectorMapViewComponent } from "./VectorMapViewComponent"
|
|
8
8
|
import { MapScope } from "./MapUtils"
|
|
9
|
-
import RasterMapViewComponent from "./RasterMapViewComponent"
|
|
10
|
-
import { areVectorMapsEnabled } from "./vectorMaps"
|
|
11
9
|
|
|
12
10
|
export interface MapViewComponentProps {
|
|
13
11
|
schema: Schema
|
|
@@ -50,7 +48,7 @@ export interface MapViewComponentProps {
|
|
|
50
48
|
/** Locale to use. Overrides map design locale */
|
|
51
49
|
locale?: string
|
|
52
50
|
|
|
53
|
-
/** Translate function to use for display
|
|
51
|
+
/** Translate function to use for display */
|
|
54
52
|
translate?: (input: string) => string
|
|
55
53
|
|
|
56
54
|
/** Increment to force refresh */
|
|
@@ -62,9 +60,5 @@ export interface MapViewComponentProps {
|
|
|
62
60
|
|
|
63
61
|
/** Component that displays just the map */
|
|
64
62
|
export function MapViewComponent(props: MapViewComponentProps) {
|
|
65
|
-
|
|
66
|
-
return <VectorMapViewComponent {...props} />
|
|
67
|
-
} else {
|
|
68
|
-
return <RasterMapViewComponent {...props} />
|
|
69
|
-
}
|
|
63
|
+
return <VectorMapViewComponent {...props} />
|
|
70
64
|
}
|
package/src/maps/MarkersLayer.ts
CHANGED
|
@@ -20,7 +20,7 @@ import Widget from "../widgets/Widget"
|
|
|
20
20
|
import { WidgetDataSource } from "../widgets/WidgetDataSource"
|
|
21
21
|
import BlocksLayoutManager from "../layouts/blocks/BlocksLayoutManager"
|
|
22
22
|
import { getTranslatableStringsFromLayoutManager } from "../dashboards/DashboardUtils"
|
|
23
|
-
import { getSimpleHoverOverData } from "./MapUtils"
|
|
23
|
+
import { getSimpleHoverOverData, getTranslatableStringsFromAxis, translateAxis } from "./MapUtils"
|
|
24
24
|
|
|
25
25
|
export default class MarkersLayer extends Layer<MarkersLayerDesign> {
|
|
26
26
|
/** Gets the type of layer definition */
|
|
@@ -138,6 +138,53 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
|
|
|
138
138
|
})
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
// Add labels layer if label axis is defined (points only)
|
|
142
|
+
if (design.axes.label) {
|
|
143
|
+
// Determine text-anchor and text-offset based on labelPosition
|
|
144
|
+
let textAnchor: "top" | "bottom" | "left" | "right"
|
|
145
|
+
let textOffset: [number, number]
|
|
146
|
+
switch (design.labelPosition) {
|
|
147
|
+
case "top":
|
|
148
|
+
textAnchor = "bottom"
|
|
149
|
+
textOffset = [0, -0.8]
|
|
150
|
+
break
|
|
151
|
+
case "left":
|
|
152
|
+
textAnchor = "right"
|
|
153
|
+
textOffset = [-0.8, 0]
|
|
154
|
+
break
|
|
155
|
+
case "right":
|
|
156
|
+
textAnchor = "left"
|
|
157
|
+
textOffset = [0.8, 0]
|
|
158
|
+
break
|
|
159
|
+
case "bottom":
|
|
160
|
+
default:
|
|
161
|
+
textAnchor = "top"
|
|
162
|
+
textOffset = [0, 0.8]
|
|
163
|
+
break
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
mapLayers.push({
|
|
167
|
+
id: `${sourceId}:labels`,
|
|
168
|
+
type: "symbol",
|
|
169
|
+
source: sourceId,
|
|
170
|
+
"source-layer": "main",
|
|
171
|
+
layout: {
|
|
172
|
+
"text-field": ["to-string", ["get", "label"]],
|
|
173
|
+
"text-size": 10,
|
|
174
|
+
"text-anchor": textAnchor,
|
|
175
|
+
"text-offset": textOffset,
|
|
176
|
+
"text-allow-overlap": false
|
|
177
|
+
},
|
|
178
|
+
paint: {
|
|
179
|
+
"text-color": compileColorToMapbox("#000000", design.axes.color?.excludedValues),
|
|
180
|
+
"text-halo-color": compileColorToMapbox("rgba(255, 255, 255, 0.8)", design.axes.color?.excludedValues),
|
|
181
|
+
"text-halo-width": 1.5,
|
|
182
|
+
"text-opacity": opacity
|
|
183
|
+
},
|
|
184
|
+
filter: addFilter(["==", ["geometry-type"], "Point"])
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
|
|
141
188
|
return {
|
|
142
189
|
sourceLayers: [{ id: "main", jsonql }],
|
|
143
190
|
ctes: [],
|
|
@@ -180,6 +227,12 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
|
|
|
180
227
|
basequery.selects.push({ type: "select", expr: colorExpr, alias: "color" })
|
|
181
228
|
}
|
|
182
229
|
|
|
230
|
+
// Add label select if label axis
|
|
231
|
+
if (design.axes.label) {
|
|
232
|
+
const labelExpr = axisBuilder.compileAxis({ axis: design.axes.label, tableAlias: "basequery" })
|
|
233
|
+
basequery.selects.push({ type: "select", expr: labelExpr, alias: "label" })
|
|
234
|
+
}
|
|
235
|
+
|
|
183
236
|
// Create filters
|
|
184
237
|
let whereClauses: JsonQLExpr[] = []
|
|
185
238
|
|
|
@@ -209,269 +262,6 @@ export default class MarkersLayer extends Layer<MarkersLayerDesign> {
|
|
|
209
262
|
return markersQuery
|
|
210
263
|
}
|
|
211
264
|
|
|
212
|
-
// Gets the layer definition as JsonQL + CSS in format:
|
|
213
|
-
// {
|
|
214
|
-
// layers: array of { id: layer id, jsonql: jsonql that includes "the_webmercator_geom" as a column }
|
|
215
|
-
// css: carto css
|
|
216
|
-
// interactivity: (optional) { layer: id of layer, fields: array of field names }
|
|
217
|
-
// }
|
|
218
|
-
// arguments:
|
|
219
|
-
// design: design of layer
|
|
220
|
-
// schema: schema to use
|
|
221
|
-
// filters: array of filters to apply. Each is { table: table id, jsonql: jsonql condition with {alias} for tableAlias. Use injectAlias to put in table alias
|
|
222
|
-
getJsonQLCss(design: MarkersLayerDesign, schema: Schema, filters: JsonQLFilter[]) {
|
|
223
|
-
// Create design
|
|
224
|
-
const layerDef = {
|
|
225
|
-
layers: [
|
|
226
|
-
{
|
|
227
|
-
id: "layer0",
|
|
228
|
-
jsonql: this.createMapnikJsonQL(design, schema, filters)
|
|
229
|
-
}
|
|
230
|
-
],
|
|
231
|
-
css: this.createCss(design),
|
|
232
|
-
interactivity: {
|
|
233
|
-
layer: "layer0",
|
|
234
|
-
fields: ["id"]
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return layerDef
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
createMapnikJsonQL(design: MarkersLayerDesign, schema: Schema, filters: JsonQLFilter[]): JsonQLQuery {
|
|
242
|
-
const axisBuilder = new AxisBuilder({ schema })
|
|
243
|
-
const exprCompiler = new ExprCompiler(schema)
|
|
244
|
-
|
|
245
|
-
// Compile geometry axis
|
|
246
|
-
let geometryExpr = axisBuilder.compileAxis({ axis: design.axes.geometry, tableAlias: "innerquery" })
|
|
247
|
-
|
|
248
|
-
// row_number() over (partition by round(ST_XMin(location)/!(pixel_width!*5)), round(ST_YMin(location)/(!pixel_height!*5))) AS r
|
|
249
|
-
const cluster: JsonQLSelect = {
|
|
250
|
-
type: "select",
|
|
251
|
-
expr: {
|
|
252
|
-
type: "op",
|
|
253
|
-
op: "row_number",
|
|
254
|
-
exprs: [],
|
|
255
|
-
over: {
|
|
256
|
-
partitionBy: [
|
|
257
|
-
{
|
|
258
|
-
type: "op",
|
|
259
|
-
op: "round",
|
|
260
|
-
exprs: [
|
|
261
|
-
{
|
|
262
|
-
type: "op",
|
|
263
|
-
op: "/",
|
|
264
|
-
exprs: [
|
|
265
|
-
{ type: "op", op: "ST_XMin", exprs: [geometryExpr] },
|
|
266
|
-
{ type: "op", op: "*", exprs: [{ type: "token", token: "!pixel_width!" }, 5] }
|
|
267
|
-
]
|
|
268
|
-
}
|
|
269
|
-
]
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
type: "op",
|
|
273
|
-
op: "round",
|
|
274
|
-
exprs: [
|
|
275
|
-
{
|
|
276
|
-
type: "op",
|
|
277
|
-
op: "/",
|
|
278
|
-
exprs: [
|
|
279
|
-
{ type: "op", op: "ST_YMin", exprs: [geometryExpr] },
|
|
280
|
-
{ type: "op", op: "*", exprs: [{ type: "token", token: "!pixel_height!" }, 5] }
|
|
281
|
-
]
|
|
282
|
-
}
|
|
283
|
-
]
|
|
284
|
-
}
|
|
285
|
-
]
|
|
286
|
-
}
|
|
287
|
-
},
|
|
288
|
-
alias: "r"
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Select _id, location and clustered row number
|
|
292
|
-
const innerquery: JsonQLSelectQuery = {
|
|
293
|
-
type: "query",
|
|
294
|
-
selects: [
|
|
295
|
-
{
|
|
296
|
-
type: "select",
|
|
297
|
-
expr: { type: "field", tableAlias: "innerquery", column: schema.getTable(design.table)!.primaryKey },
|
|
298
|
-
alias: "id"
|
|
299
|
-
}, // main primary key as id
|
|
300
|
-
{ type: "select", expr: geometryExpr, alias: "the_geom_webmercator" }, // geometry as the_geom_webmercator
|
|
301
|
-
cluster
|
|
302
|
-
],
|
|
303
|
-
from: exprCompiler.compileTable(design.table, "innerquery")
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Add color select if color axis
|
|
307
|
-
if (design.axes.color) {
|
|
308
|
-
const colorExpr = axisBuilder.compileAxis({ axis: design.axes.color, tableAlias: "innerquery" })
|
|
309
|
-
innerquery.selects.push({ type: "select", expr: colorExpr, alias: "color" })
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Create filters. First limit to bounding box
|
|
313
|
-
let whereClauses: JsonQLExpr[] = [
|
|
314
|
-
{
|
|
315
|
-
type: "op",
|
|
316
|
-
op: "&&",
|
|
317
|
-
exprs: [geometryExpr, { type: "token", token: "!bbox!" }]
|
|
318
|
-
}
|
|
319
|
-
]
|
|
320
|
-
|
|
321
|
-
// Then add filters baked into layer
|
|
322
|
-
if (design.filter) {
|
|
323
|
-
whereClauses.push(exprCompiler.compileExpr({ expr: design.filter, tableAlias: "innerquery" }))
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Then add extra filters passed in, if relevant
|
|
327
|
-
// Get relevant filters
|
|
328
|
-
const relevantFilters = _.where(filters, { table: design.table })
|
|
329
|
-
for (let filter of relevantFilters) {
|
|
330
|
-
whereClauses.push(injectTableAlias(filter.jsonql, "innerquery"))
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
whereClauses = _.compact(whereClauses)
|
|
334
|
-
|
|
335
|
-
// Wrap if multiple
|
|
336
|
-
if (whereClauses.length > 1) {
|
|
337
|
-
innerquery.where = { type: "op", op: "and", exprs: whereClauses }
|
|
338
|
-
} else {
|
|
339
|
-
innerquery.where = whereClauses[0]
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Create outer query which takes where r <= 3 to limit # of points in a cluster
|
|
343
|
-
const outerquery: JsonQLQuery = {
|
|
344
|
-
type: "query",
|
|
345
|
-
selects: [
|
|
346
|
-
{
|
|
347
|
-
type: "select",
|
|
348
|
-
expr: { type: "field", tableAlias: "innerquery", column: "id" },
|
|
349
|
-
alias: "id"
|
|
350
|
-
}, // innerquery._id as id
|
|
351
|
-
{
|
|
352
|
-
type: "select",
|
|
353
|
-
expr: { type: "field", tableAlias: "innerquery", column: "the_geom_webmercator" },
|
|
354
|
-
alias: "the_geom_webmercator"
|
|
355
|
-
}, // innerquery.the_geom_webmercator as the_geom_webmercator
|
|
356
|
-
{
|
|
357
|
-
type: "select",
|
|
358
|
-
expr: {
|
|
359
|
-
type: "op",
|
|
360
|
-
op: "ST_GeometryType",
|
|
361
|
-
exprs: [{ type: "field", tableAlias: "innerquery", column: "the_geom_webmercator" }]
|
|
362
|
-
},
|
|
363
|
-
alias: "geometry_type"
|
|
364
|
-
} // ST_GeometryType(innerquery.the_geom_webmercator) as geometry_type
|
|
365
|
-
],
|
|
366
|
-
from: { type: "subquery", query: innerquery, alias: "innerquery" },
|
|
367
|
-
where: { type: "op", op: "<=", exprs: [{ type: "field", tableAlias: "innerquery", column: "r" }, 3] }
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Add color select if color axis
|
|
371
|
-
if (design.axes.color) {
|
|
372
|
-
outerquery.selects.push({
|
|
373
|
-
type: "select",
|
|
374
|
-
expr: { type: "field", tableAlias: "innerquery", column: "color" },
|
|
375
|
-
alias: "color"
|
|
376
|
-
}) // innerquery.color as color
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return outerquery
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Creates CartoCSS
|
|
383
|
-
createCss(design: MarkersLayerDesign) {
|
|
384
|
-
let stroke, symbol
|
|
385
|
-
let css = ""
|
|
386
|
-
|
|
387
|
-
if (design.symbol) {
|
|
388
|
-
symbol = `marker-file: url(${design.symbol});`
|
|
389
|
-
stroke = "marker-line-width: 60;"
|
|
390
|
-
} else {
|
|
391
|
-
symbol = "marker-type: ellipse;"
|
|
392
|
-
stroke = "marker-line-width: 1;"
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Should only display markers when it is a point geometry
|
|
396
|
-
css +=
|
|
397
|
-
`\
|
|
398
|
-
#layer0[geometry_type='ST_Point'] {
|
|
399
|
-
marker-fill: ` +
|
|
400
|
-
(design.color || "#666666") +
|
|
401
|
-
`;
|
|
402
|
-
marker-width: ` +
|
|
403
|
-
(design.markerSize || 10) +
|
|
404
|
-
`;
|
|
405
|
-
marker-line-color: white;\
|
|
406
|
-
` +
|
|
407
|
-
stroke +
|
|
408
|
-
`\
|
|
409
|
-
marker-line-opacity: 0.6;
|
|
410
|
-
marker-placement: point;\
|
|
411
|
-
` +
|
|
412
|
-
symbol +
|
|
413
|
-
`\
|
|
414
|
-
marker-allow-overlap: true;
|
|
415
|
-
}
|
|
416
|
-
#layer0 {
|
|
417
|
-
line-color: ` +
|
|
418
|
-
(design.color || "#666666") +
|
|
419
|
-
`;
|
|
420
|
-
line-width: ` +
|
|
421
|
-
(design.lineWidth != null ? design.lineWidth : "3") +
|
|
422
|
-
`;
|
|
423
|
-
}
|
|
424
|
-
#layer0[geometry_type='ST_Polygon'],#layer0[geometry_type='ST_MultiPolygon'] {
|
|
425
|
-
polygon-fill: ` +
|
|
426
|
-
(design.color || "#666666") +
|
|
427
|
-
`;
|
|
428
|
-
polygon-opacity: ${design.polygonFillOpacity ?? 0.25};
|
|
429
|
-
}
|
|
430
|
-
\
|
|
431
|
-
`
|
|
432
|
-
|
|
433
|
-
// If color axes, add color conditions
|
|
434
|
-
if (design.axes.color && design.axes.color.colorMap) {
|
|
435
|
-
for (let item of design.axes.color.colorMap) {
|
|
436
|
-
// If invisible
|
|
437
|
-
if (_.includes(design.axes.color.excludedValues || [], item.value)) {
|
|
438
|
-
css +=
|
|
439
|
-
`\
|
|
440
|
-
#layer0[color=` +
|
|
441
|
-
JSON.stringify(item.value) +
|
|
442
|
-
`] { line-opacity: 0; marker-line-opacity: 0; marker-fill-opacity: 0; polygon-opacity: 0; }\
|
|
443
|
-
`
|
|
444
|
-
} else {
|
|
445
|
-
css +=
|
|
446
|
-
`\
|
|
447
|
-
#layer0[color=` +
|
|
448
|
-
JSON.stringify(item.value) +
|
|
449
|
-
"] { line-color: " +
|
|
450
|
-
item.color +
|
|
451
|
-
` }
|
|
452
|
-
#layer0[color=` +
|
|
453
|
-
JSON.stringify(item.value) +
|
|
454
|
-
"][geometry_type='ST_Point'] { marker-fill: " +
|
|
455
|
-
item.color +
|
|
456
|
-
` }
|
|
457
|
-
#layer0[color=` +
|
|
458
|
-
JSON.stringify(item.value) +
|
|
459
|
-
"][geometry_type='ST_Polygon'],#layer0[color=" +
|
|
460
|
-
JSON.stringify(item.value) +
|
|
461
|
-
`][geometry_type='ST_MultiPolygon'] {
|
|
462
|
-
polygon-fill: ` +
|
|
463
|
-
item.color +
|
|
464
|
-
`;\
|
|
465
|
-
${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" : ""}\
|
|
466
|
-
}\
|
|
467
|
-
`
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return css
|
|
473
|
-
}
|
|
474
|
-
|
|
475
265
|
// same as onGridClick but handles hover over
|
|
476
266
|
onGridHoverOver(
|
|
477
267
|
ev: { data: any; event: any },
|
|
@@ -652,6 +442,15 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
|
|
|
652
442
|
}
|
|
653
443
|
|
|
654
444
|
const axisBuilder = new AxisBuilder({ schema })
|
|
445
|
+
|
|
446
|
+
// Clean and translate axis
|
|
447
|
+
const axis = translateAxis(axisBuilder.cleanAxis({
|
|
448
|
+
axis: design.axes.color || null,
|
|
449
|
+
table: design.table,
|
|
450
|
+
types: ["enum", "text", "boolean", "date"],
|
|
451
|
+
aggrNeed: "none"
|
|
452
|
+
}), translate)
|
|
453
|
+
|
|
655
454
|
return React.createElement(LayerLegendComponent, {
|
|
656
455
|
schema,
|
|
657
456
|
defaultColor: design.color,
|
|
@@ -659,12 +458,7 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
|
|
|
659
458
|
markerSize: design.markerSize,
|
|
660
459
|
name: translate(name),
|
|
661
460
|
filters: _.compact(_filters),
|
|
662
|
-
axis
|
|
663
|
-
axis: design.axes.color || null,
|
|
664
|
-
table: design.table,
|
|
665
|
-
types: ["enum", "text", "boolean", "date"],
|
|
666
|
-
aggrNeed: "none"
|
|
667
|
-
}),
|
|
461
|
+
axis,
|
|
668
462
|
locale
|
|
669
463
|
})
|
|
670
464
|
}
|
|
@@ -739,6 +533,12 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
|
|
|
739
533
|
types: ["enum", "text", "boolean", "date"],
|
|
740
534
|
aggrNeed: "none"
|
|
741
535
|
})!
|
|
536
|
+
draft.axes.label = axisBuilder.cleanAxis({
|
|
537
|
+
axis: draft.axes.label ? original(draft.axes.label) || null : null,
|
|
538
|
+
table: design.table,
|
|
539
|
+
types: ["text", "number"],
|
|
540
|
+
aggrNeed: "none"
|
|
541
|
+
}) || undefined
|
|
742
542
|
|
|
743
543
|
draft.filter = exprCleaner.cleanExpr(design.filter || null, { table: draft.table })
|
|
744
544
|
|
|
@@ -783,6 +583,12 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
|
|
|
783
583
|
return error
|
|
784
584
|
}
|
|
785
585
|
|
|
586
|
+
// Validate label
|
|
587
|
+
error = axisBuilder.validateAxis({ axis: design.axes.label || null })
|
|
588
|
+
if (error) {
|
|
589
|
+
return error
|
|
590
|
+
}
|
|
591
|
+
|
|
786
592
|
// Check that doesn't compile to null (persistent bug that haven't been able to track down)
|
|
787
593
|
if (!axisBuilder.compileAxis({ axis: design.axes.geometry, tableAlias: "innerquery" })) {
|
|
788
594
|
return "Null geometry axis"
|
|
@@ -801,6 +607,9 @@ ${design.polygonBorderColor ? "line-color: " + design.polygonBorderColor + ";" :
|
|
|
801
607
|
getTranslatableStrings(design: MarkersLayerDesign, schema: Schema): string[] {
|
|
802
608
|
const strings: string[] = []
|
|
803
609
|
|
|
610
|
+
// Add strings from axis category labels and null labels
|
|
611
|
+
strings.push(...getTranslatableStringsFromAxis(design.axes.color))
|
|
612
|
+
|
|
804
613
|
// Add strings from hoverOver items
|
|
805
614
|
if (design.hoverOver && design.hoverOver.items) {
|
|
806
615
|
for (const item of design.hoverOver.items) {
|
|
@@ -16,8 +16,14 @@ export interface MarkersLayerDesign {
|
|
|
16
16
|
|
|
17
17
|
/** Color axis (to split into series based on a color) */
|
|
18
18
|
color?: Axis
|
|
19
|
+
|
|
20
|
+
/** Label expression to display on/near markers (points only) */
|
|
21
|
+
label?: Axis
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
/** Position of label relative to marker. Default "bottom" */
|
|
25
|
+
labelPosition?: "top" | "bottom" | "left" | "right"
|
|
26
|
+
|
|
21
27
|
/** Optional logical expression to filter by */
|
|
22
28
|
filter?: Expr
|
|
23
29
|
|