@record-evolution/widget-mapbox 1.4.11
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/README.md +48 -0
- package/dist/src/types.d.ts +28 -0
- package/dist/src/widget-mapbox.d.ts +28 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/widget-mapbox.js +2617 -0
- package/dist/widget-mapbox.js.map +1 -0
- package/package.json +66 -0
- package/src/default-data.json +391 -0
- package/src/definition-schema.json +219 -0
- package/src/types.ts +33 -0
- package/src/widget-mapbox.ts +550 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { property, state } from 'lit/decorators.js';
|
|
3
|
+
import { repeat } from 'lit/directives/repeat.js'
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
// import mapboxgl from 'https://cdn.skypack.dev/-/mapbox-gl@v2.15.0-iKfohePv9lgutCMNih0d/dist=es2020,mode=imports,min/optimized/mapbox-gl.js'
|
|
6
|
+
import mapboxgl from 'https://esm.run/mapbox-gl@3.0.1';
|
|
7
|
+
import * as GeoJSON from 'geojson';
|
|
8
|
+
import tinycolor from "tinycolor2";
|
|
9
|
+
import { InputData, Dataseries, Point } from './types.js'
|
|
10
|
+
|
|
11
|
+
export class WidgetMapbox extends LitElement {
|
|
12
|
+
|
|
13
|
+
@property({type: Object})
|
|
14
|
+
inputData?: InputData = undefined
|
|
15
|
+
|
|
16
|
+
@state()
|
|
17
|
+
private map: any | undefined = undefined;
|
|
18
|
+
|
|
19
|
+
@state()
|
|
20
|
+
private dataSets: Dataseries[] = []
|
|
21
|
+
|
|
22
|
+
@state()
|
|
23
|
+
dataSources: any = new Map()
|
|
24
|
+
|
|
25
|
+
@state()
|
|
26
|
+
colors: any = new Map()
|
|
27
|
+
|
|
28
|
+
version: string = 'versionplaceholder'
|
|
29
|
+
|
|
30
|
+
resizeObserver: ResizeObserver
|
|
31
|
+
mapStyle?: string
|
|
32
|
+
constructor() {
|
|
33
|
+
super()
|
|
34
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
35
|
+
this.map?.resize()
|
|
36
|
+
this.fitBounds()
|
|
37
|
+
})
|
|
38
|
+
mapboxgl.accessToken = 'pk.eyJ1IjoibWFya29wZSIsImEiOiJjazc1OWlsNjkwN2pyM2VxajV1eGRnYzgwIn0.3lVksk1nej_0KnWjCkBDAA'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
update(changedProperties: Map<string, any>) {
|
|
42
|
+
changedProperties.forEach((propName: string) => {
|
|
43
|
+
if (propName === 'inputData') {
|
|
44
|
+
this.transformInputData()
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
super.update(changedProperties)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
firstUpdated() {
|
|
51
|
+
|
|
52
|
+
this.transformInputData()
|
|
53
|
+
this.createMap()
|
|
54
|
+
this.resizeObserver.observe(this.map._container)
|
|
55
|
+
this.fitBounds()
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fitBounds() {
|
|
60
|
+
const bounds = new mapboxgl.LngLatBounds()
|
|
61
|
+
this.dataSources.forEach((col: GeoJSON.FeatureCollection) => {
|
|
62
|
+
col.features.forEach(f => {
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
if (f.geometry.coordinates?.length) bounds.extend(f.geometry.coordinates)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
if (!bounds.isEmpty()) {
|
|
68
|
+
this.map.fitBounds(bounds, { maxZoom: 14, padding: 16, duration: 100, })
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
transformInputData() {
|
|
73
|
+
if(!this?.inputData?.settings || !this?.inputData?.dataseries?.length) return
|
|
74
|
+
|
|
75
|
+
if (this.map && this.inputData.settings.style !== this.mapStyle) {
|
|
76
|
+
this.createMap()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// choose random color if dataseries has none and store it for furure updates
|
|
80
|
+
this.inputData.dataseries.forEach(ds => {
|
|
81
|
+
if (!this.colors.has(ds.label)) {
|
|
82
|
+
ds.color = ds.color ?? tinycolor.random().toString()
|
|
83
|
+
this.colors.set(ds.label, ds.color)
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
// console.log('The input data', this.inputData.dataseries[0], this.inputData.dataseries[1])
|
|
87
|
+
// Pivot inputData if required
|
|
88
|
+
this.dataSets = []
|
|
89
|
+
this.inputData.dataseries.forEach(ds => {
|
|
90
|
+
const color = this.colors.get(ds.label)
|
|
91
|
+
const distincts = [...new Set(ds.data.map((d: Point) => d.pivot))]
|
|
92
|
+
const derivedColors = tinycolor(color).monochromatic(distincts.length).map((c: any) => c.toHexString())
|
|
93
|
+
if (distincts.length > 1) {
|
|
94
|
+
distincts.forEach((piv, i) => {
|
|
95
|
+
const pds: any = {
|
|
96
|
+
label: `${ds.label} ${piv}`,
|
|
97
|
+
order: ds.order,
|
|
98
|
+
type: ds.type,
|
|
99
|
+
latestValues: ds.latestValues,
|
|
100
|
+
color: derivedColors[i],
|
|
101
|
+
config: ds.config,
|
|
102
|
+
data: ds.data.filter(d => d.pivot === piv)
|
|
103
|
+
}
|
|
104
|
+
this.dataSets.push(pds)
|
|
105
|
+
})
|
|
106
|
+
} else {
|
|
107
|
+
ds.color = ds.color ?? this.colors[ds.label]
|
|
108
|
+
this.dataSets.push(ds)
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
this.inputData.dataseries = []
|
|
113
|
+
|
|
114
|
+
// Filter for latest Values
|
|
115
|
+
this.dataSets.forEach(ds => {
|
|
116
|
+
if (ds.latestValues > 0) ds.data = ds.data.splice(-ds.latestValues)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// console.log('mapbox datasets', this.dataSets)
|
|
120
|
+
|
|
121
|
+
// create geojson sources
|
|
122
|
+
this.dataSets.sort((a, b) => b.order - a.order).forEach(ds => {
|
|
123
|
+
|
|
124
|
+
this.dataSources.set('input:' + ds.label, {
|
|
125
|
+
type: 'FeatureCollection',
|
|
126
|
+
features: this.createGEOJson(ds)
|
|
127
|
+
} as GeoJSON.FeatureCollection)
|
|
128
|
+
|
|
129
|
+
if (this.map) this.syncDataLayers()
|
|
130
|
+
// console.log('mapbox DataLayers', this.dataSources)
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
createGEOJson(ds: Dataseries): GeoJSON.Feature[] {
|
|
135
|
+
if (ds.type !== 'line') {
|
|
136
|
+
const features: GeoJSON.Feature[] = ds.data
|
|
137
|
+
.filter(p =>
|
|
138
|
+
p.lon !== undefined
|
|
139
|
+
&& p.lat !== undefined
|
|
140
|
+
&& p.value !== undefined
|
|
141
|
+
&& typeof p.lon === 'number'
|
|
142
|
+
&& typeof p.lat === 'number'
|
|
143
|
+
&& typeof p.value === 'number')
|
|
144
|
+
.map(p => {
|
|
145
|
+
const point: GeoJSON.Feature = {
|
|
146
|
+
type: 'Feature',
|
|
147
|
+
geometry: {
|
|
148
|
+
type: 'Point',
|
|
149
|
+
coordinates: [p.lon, p.lat]
|
|
150
|
+
},
|
|
151
|
+
properties: {
|
|
152
|
+
value: Math.round(p.value)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return point
|
|
156
|
+
})
|
|
157
|
+
return features
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const line: number[][] = ds.data.reverse()
|
|
161
|
+
.filter(p => p.lon !== undefined && p.lat !== undefined)
|
|
162
|
+
.map(p => [p.lon, p.lat, p.alt])
|
|
163
|
+
|
|
164
|
+
const feature: GeoJSON.Feature = {
|
|
165
|
+
type: 'Feature',
|
|
166
|
+
geometry: {
|
|
167
|
+
type: 'LineString',
|
|
168
|
+
coordinates: line
|
|
169
|
+
},
|
|
170
|
+
properties: {}
|
|
171
|
+
}
|
|
172
|
+
return [feature]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
addCircleLayer(dataSet: Dataseries) {
|
|
176
|
+
if (!dataSet) return
|
|
177
|
+
const layerConfig = {
|
|
178
|
+
'id': dataSet.label + ':circle',
|
|
179
|
+
'type': 'circle',
|
|
180
|
+
'source': 'input:' + dataSet.label,
|
|
181
|
+
'paint': {
|
|
182
|
+
...dataSet.config['circle'],
|
|
183
|
+
"circle-radius": ['get', 'value'],
|
|
184
|
+
"circle-radius-transition": {
|
|
185
|
+
duration: 1000,
|
|
186
|
+
delay: 0
|
|
187
|
+
},
|
|
188
|
+
"circle-color": dataSet.color
|
|
189
|
+
},
|
|
190
|
+
// Place polygons under labels, roads and buildings.
|
|
191
|
+
// 'aeroway-polygon'
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.map?.addLayer(layerConfig)
|
|
195
|
+
|
|
196
|
+
if (!dataSet.config['symbol']) return
|
|
197
|
+
const layerConfig2 = {
|
|
198
|
+
'id': dataSet.label + ':symbol',
|
|
199
|
+
'type': 'symbol',
|
|
200
|
+
'source': 'input:' + dataSet.label,
|
|
201
|
+
layout: {
|
|
202
|
+
'text-field': ['get', 'value'],
|
|
203
|
+
'text-size': dataSet.config['symbol']['text-size'],
|
|
204
|
+
'text-anchor': 'center',
|
|
205
|
+
},
|
|
206
|
+
paint: {
|
|
207
|
+
'text-color': dataSet.config['symbol']['text-color'],
|
|
208
|
+
}
|
|
209
|
+
// Place polygons under labels, roads and buildings.
|
|
210
|
+
// 'aeroway-polygon'
|
|
211
|
+
}
|
|
212
|
+
this.map?.addLayer(layerConfig2)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
addSymbolLayer(dataSet: Dataseries) {
|
|
216
|
+
if (!dataSet) return
|
|
217
|
+
const layerConfig = {
|
|
218
|
+
'id': dataSet.label + ':symbol',
|
|
219
|
+
'type': 'symbol',
|
|
220
|
+
'source': 'input:' + dataSet.label,
|
|
221
|
+
layout: {
|
|
222
|
+
'text-field': ['get', 'value'],
|
|
223
|
+
'text-size': dataSet.config['symbol']['text-size'],
|
|
224
|
+
'text-anchor': 'center',
|
|
225
|
+
'icon-image': dataSet.config.symbol['icon-image'],
|
|
226
|
+
'icon-size': dataSet.config.symbol['icon-size']
|
|
227
|
+
},
|
|
228
|
+
paint: {
|
|
229
|
+
'text-color': dataSet.config['symbol']['text-color'],
|
|
230
|
+
}
|
|
231
|
+
// Place polygons under labels, roads and buildings.
|
|
232
|
+
// 'aeroway-polygon'
|
|
233
|
+
}
|
|
234
|
+
this.map?.addLayer(layerConfig)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
addHeatmapLayer(dataSet: Dataseries) {
|
|
238
|
+
if (!dataSet) return
|
|
239
|
+
|
|
240
|
+
const min = Math.min(...dataSet.data.map(p => p.value))
|
|
241
|
+
const max = Math.max(...dataSet.data.map(p => p.value))
|
|
242
|
+
const layerConfig = {
|
|
243
|
+
'id': dataSet.label + ':heatmap',
|
|
244
|
+
'type': 'heatmap',
|
|
245
|
+
'source': 'input:' + dataSet.label,
|
|
246
|
+
paint: {
|
|
247
|
+
...dataSet.config.heatmap,
|
|
248
|
+
'heatmap-color': [
|
|
249
|
+
"interpolate",
|
|
250
|
+
["linear"],
|
|
251
|
+
["heatmap-density"],
|
|
252
|
+
0,"rgba(0, 0, 255, 0)",
|
|
253
|
+
0.1, "royalblue",
|
|
254
|
+
0.3, "cyan",
|
|
255
|
+
0.5, "lime",
|
|
256
|
+
0.7, "yellow",
|
|
257
|
+
1, "tomato"
|
|
258
|
+
],
|
|
259
|
+
// Increase the heatmap weight based on frequency and property magnitude
|
|
260
|
+
'heatmap-weight': [
|
|
261
|
+
'interpolate',
|
|
262
|
+
['linear'],
|
|
263
|
+
['get', 'value'],
|
|
264
|
+
min, 0,
|
|
265
|
+
max, 3
|
|
266
|
+
],
|
|
267
|
+
// // Increase the heatmap color weight weight by zoom level
|
|
268
|
+
// // heatmap-intensity is a multiplier on top of heatmap-weight
|
|
269
|
+
// 'heatmap-intensity': [
|
|
270
|
+
// 'interpolate',
|
|
271
|
+
// ['linear'],
|
|
272
|
+
// ['zoom'],
|
|
273
|
+
// 0, 1,
|
|
274
|
+
// 9, 3
|
|
275
|
+
// ],
|
|
276
|
+
// Adjust the heatmap radius by zoom level
|
|
277
|
+
'heatmap-radius': [
|
|
278
|
+
'interpolate',
|
|
279
|
+
['linear'],
|
|
280
|
+
['get', 'value'],
|
|
281
|
+
min, 30,
|
|
282
|
+
max, 30 + dataSet.config.heatmap['heatmap-radius']
|
|
283
|
+
],
|
|
284
|
+
'heatmap-radius-transition': {
|
|
285
|
+
duration: 1000,
|
|
286
|
+
delay: 0
|
|
287
|
+
}
|
|
288
|
+
// // Transition from heatmap to circle layer by zoom level
|
|
289
|
+
// 'heatmap-opacity': [
|
|
290
|
+
// 'interpolate',
|
|
291
|
+
// ['linear'],
|
|
292
|
+
// ['zoom'],
|
|
293
|
+
// 7, 1,
|
|
294
|
+
// 9, 0
|
|
295
|
+
// ]
|
|
296
|
+
}
|
|
297
|
+
// Place polygons under labels, roads and buildings.
|
|
298
|
+
// 'aeroway-polygon'
|
|
299
|
+
}
|
|
300
|
+
this.map?.addLayer(layerConfig)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
addLineLayer(dataSet: Dataseries) {
|
|
304
|
+
if (!dataSet) return
|
|
305
|
+
const layerConfig = {
|
|
306
|
+
'id': dataSet.label + ':line',
|
|
307
|
+
'type': 'line',
|
|
308
|
+
'source': 'input:' + dataSet.label,
|
|
309
|
+
layout: {
|
|
310
|
+
'line-cap': 'round',
|
|
311
|
+
},
|
|
312
|
+
paint: {
|
|
313
|
+
...dataSet.config.line,
|
|
314
|
+
"line-color": dataSet.color,
|
|
315
|
+
}
|
|
316
|
+
// Place polygons under labels, roads and buildings.
|
|
317
|
+
// 'aeroway-polygon'
|
|
318
|
+
}
|
|
319
|
+
this.map?.addLayer(layerConfig)
|
|
320
|
+
|
|
321
|
+
if (!dataSet.config.symbol['icon-image']) return
|
|
322
|
+
|
|
323
|
+
const layerConfig2 = {
|
|
324
|
+
'id': dataSet.label + ':symbol',
|
|
325
|
+
'type': 'symbol',
|
|
326
|
+
'source': 'input:' + dataSet.label,
|
|
327
|
+
layout: {
|
|
328
|
+
'icon-image': dataSet.config.symbol['icon-image'],
|
|
329
|
+
'icon-size': dataSet.config.symbol['icon-size'],
|
|
330
|
+
},
|
|
331
|
+
paint: {
|
|
332
|
+
'icon-color': dataSet.color
|
|
333
|
+
}
|
|
334
|
+
// Place polygons under labels, roads and buildings.
|
|
335
|
+
// 'aeroway-polygon'
|
|
336
|
+
}
|
|
337
|
+
this.map?.addLayer(layerConfig2)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
syncDataLayers() {
|
|
341
|
+
|
|
342
|
+
// remove sources and all Layers that are not part of the inputData anymore
|
|
343
|
+
const sources: any[] = this.map.getStyle().sources ?? []
|
|
344
|
+
const mySources: [string, any][] = Object.entries(sources).filter(([l]) => l.startsWith('input:'))
|
|
345
|
+
|
|
346
|
+
mySources.forEach(([label]) => {
|
|
347
|
+
if (!this.dataSources.has(label)){
|
|
348
|
+
// remove all layers using this source
|
|
349
|
+
this.map.getStyle().layers.filter((la: any) => la.id === label + ':' + la.type).forEach((la: any) => {
|
|
350
|
+
this.map.removeLayer(la.id)
|
|
351
|
+
})
|
|
352
|
+
this.map.removeSource(label)
|
|
353
|
+
}
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
// add new layers or update the data of existing layers
|
|
357
|
+
this.dataSets.forEach(ds => {
|
|
358
|
+
const fc = this.dataSources.get('input:' + ds.label)
|
|
359
|
+
const src = this.map.getSource('input:' + ds.label)
|
|
360
|
+
if (src) {
|
|
361
|
+
src.setData(fc || [])
|
|
362
|
+
return
|
|
363
|
+
}
|
|
364
|
+
// console.log('adding source', ds.label, ds.type)
|
|
365
|
+
this.map?.addSource('input:' + ds.label, {
|
|
366
|
+
type: 'geojson',
|
|
367
|
+
data: fc || []
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
switch(ds.type) {
|
|
371
|
+
case 'circle':
|
|
372
|
+
this.addCircleLayer(ds)
|
|
373
|
+
return
|
|
374
|
+
case 'symbol':
|
|
375
|
+
this.addSymbolLayer(ds)
|
|
376
|
+
return
|
|
377
|
+
case 'heatmap':
|
|
378
|
+
this.addHeatmapLayer(ds)
|
|
379
|
+
return
|
|
380
|
+
case 'line':
|
|
381
|
+
this.addLineLayer(ds)
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
if (this.inputData?.settings?.follow) this.fitBounds()
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
addBuildingLayer() {
|
|
388
|
+
// Insert the layer beneath any symbol layer.
|
|
389
|
+
const {layers} = this.map.getStyle()
|
|
390
|
+
|
|
391
|
+
let labelLayerId: number = 0
|
|
392
|
+
for (let i = 0; i < layers.length; i++) {
|
|
393
|
+
if (layers[i].type === 'symbol' && layers[i].layout['text-field']) {
|
|
394
|
+
labelLayerId = layers[i].id
|
|
395
|
+
break
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
this.map.addLayer({
|
|
400
|
+
'id': '3d-buildings',
|
|
401
|
+
'source': 'composite',
|
|
402
|
+
'source-layer': 'building',
|
|
403
|
+
'filter': ['==', 'extrude', 'true'],
|
|
404
|
+
'type': 'fill-extrusion',
|
|
405
|
+
'minzoom': 14,
|
|
406
|
+
'paint': {
|
|
407
|
+
'fill-extrusion-color': '#aaa',
|
|
408
|
+
// use an 'interpolate' expression to add a smooth transition effect to the
|
|
409
|
+
// buildings as the user zooms in
|
|
410
|
+
'fill-extrusion-height': [
|
|
411
|
+
"interpolate", ["linear"],
|
|
412
|
+
["zoom"],
|
|
413
|
+
14, 0,
|
|
414
|
+
14.05, ["get", "height"]
|
|
415
|
+
],
|
|
416
|
+
'fill-extrusion-base': [
|
|
417
|
+
"interpolate", ["linear"],
|
|
418
|
+
["zoom"],
|
|
419
|
+
14, 0,
|
|
420
|
+
14.05, ["get", "min_height"]
|
|
421
|
+
],
|
|
422
|
+
'fill-extrusion-opacity': .6
|
|
423
|
+
}
|
|
424
|
+
}, labelLayerId)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
createMap() {
|
|
428
|
+
if (this.map) return
|
|
429
|
+
this.mapStyle = this.inputData?.settings?.style
|
|
430
|
+
this.map = new mapboxgl.Map({
|
|
431
|
+
container: this.shadowRoot?.getElementById('map') as HTMLCanvasElement,
|
|
432
|
+
style: `mapbox://styles/mapbox/${this.mapStyle ?? 'light-v11'}` ,
|
|
433
|
+
center: [8.6841700, 50.1155200],
|
|
434
|
+
zoom: 1.8,
|
|
435
|
+
attributionControl: false
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
this.map.scrollZoom.disable();
|
|
439
|
+
|
|
440
|
+
this.map.addControl(new mapboxgl.NavigationControl(), 'top-right')
|
|
441
|
+
|
|
442
|
+
const scale = new mapboxgl.ScaleControl({
|
|
443
|
+
maxWidth: 80,
|
|
444
|
+
unit: 'metric'
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
this.map.addControl(scale, 'bottom-left')
|
|
448
|
+
|
|
449
|
+
console.log('MAPBOX VERSION', mapboxgl.version)
|
|
450
|
+
|
|
451
|
+
this.map.on('load', () => {
|
|
452
|
+
this.addBuildingLayer()
|
|
453
|
+
this.syncDataLayers()
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
static styles = css`
|
|
458
|
+
:host {
|
|
459
|
+
display: block;
|
|
460
|
+
color: var(--re-bar-text-color, #000);
|
|
461
|
+
font-family: sans-serif;
|
|
462
|
+
padding: 16px;
|
|
463
|
+
box-sizing: border-box;
|
|
464
|
+
margin: auto;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.paging:not([active]) { display: none !important; }
|
|
468
|
+
|
|
469
|
+
header {
|
|
470
|
+
display: flex;
|
|
471
|
+
margin: 0 0 16px 0;
|
|
472
|
+
gap: 24px;
|
|
473
|
+
justify-content: space-between;
|
|
474
|
+
}
|
|
475
|
+
h3 {
|
|
476
|
+
margin: 0;
|
|
477
|
+
max-width: 300px;
|
|
478
|
+
overflow: hidden;
|
|
479
|
+
text-overflow: ellipsis;
|
|
480
|
+
white-space: nowrap;
|
|
481
|
+
}
|
|
482
|
+
p {
|
|
483
|
+
margin: 10px 0 0 0;
|
|
484
|
+
max-width: 300px;
|
|
485
|
+
font-size: 14px;
|
|
486
|
+
overflow: hidden;
|
|
487
|
+
text-overflow: ellipsis;
|
|
488
|
+
white-space: nowrap;
|
|
489
|
+
line-height: 17px;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.wrapper {
|
|
493
|
+
display: flex;
|
|
494
|
+
flex-direction: column;
|
|
495
|
+
height: 100%;
|
|
496
|
+
width: 100%;
|
|
497
|
+
}
|
|
498
|
+
#map {
|
|
499
|
+
flex: 1;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.title {
|
|
503
|
+
white-space: nowrap;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.legend {
|
|
507
|
+
display: flex;
|
|
508
|
+
flex-wrap: wrap;
|
|
509
|
+
gap: 12px;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.label {
|
|
513
|
+
display: flex;
|
|
514
|
+
align-items: center;
|
|
515
|
+
font-size: 14px;
|
|
516
|
+
gap: 8px
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
a.mapboxgl-ctrl-logo {
|
|
520
|
+
display: none;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
`;
|
|
524
|
+
|
|
525
|
+
render() {
|
|
526
|
+
return html`
|
|
527
|
+
<link href="https://api.mapbox.com/mapbox-gl-js/v${mapboxgl.version}/mapbox-gl.css" rel="stylesheet">
|
|
528
|
+
<div class="wrapper">
|
|
529
|
+
<header>
|
|
530
|
+
<div class="title">
|
|
531
|
+
<h3 class="paging" ?active=${this.inputData?.settings?.title}>${this.inputData?.settings?.title}</h3>
|
|
532
|
+
<p class="paging" ?active=${this.inputData?.settings?.subTitle}>${this.inputData?.settings?.subTitle}</p>
|
|
533
|
+
</div>
|
|
534
|
+
<div class="legend paging" ?active=${this?.inputData?.settings?.showLegend}>
|
|
535
|
+
${repeat(this.dataSets, ds => ds.label, ds => {
|
|
536
|
+
return html`
|
|
537
|
+
<div class="label">
|
|
538
|
+
<div style="background: ${ds.color}; width: 24px; height: 12px;"></div>
|
|
539
|
+
<div>${ds.label}</div>
|
|
540
|
+
</div>
|
|
541
|
+
`})}
|
|
542
|
+
</div>
|
|
543
|
+
</header>
|
|
544
|
+
<div id="map"></div>
|
|
545
|
+
</div>
|
|
546
|
+
`;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
window.customElements.define('widget-mapbox-versionplaceholder', WidgetMapbox);
|