Skip to content

Commit 8a5dd05

Browse files
Allow configuration of legend (#12)
* adjust loading only during data fetching, display popup correct name and type error. * add data folder into docker container * adjust legend option in input json files and add detail button for DB urls. * legend configuration into InputLayer * add not defined category to legends --------- Co-authored-by: Marius Heine <m.heine@geprog.com>
1 parent 4e54445 commit 8a5dd05

File tree

6 files changed

+74
-27
lines changed

6 files changed

+74
-27
lines changed

components/MyLeafletMap.vue

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@ import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility
1212
const props = defineProps<{
1313
fetchedData?: GeoJSON.FeatureCollection | null
1414
}>();
15+
1516
const emit = defineEmits<{
1617
(e: 'marker-click', feature: GeoJSON.Feature): void
1718
}>();
19+
20+
const NO_VALUE_COLOR = '#999999';
21+
22+
const { t } = useI18n();
23+
1824
let selectedMarker: L.Layer | null = null;
1925
const originalMarkerStyleMap = new Map<L.Layer, L.PathOptions>();
2026
let legendControl: L.Control | null = null;
@@ -57,16 +63,23 @@ function generateLabels(data: GeoJSON.FeatureCollection): Map<string, string> {
5763
);
5864
const labelKey: string | undefined = data.features[0]?.properties?.options?.label_option;
5965
const key = labelKey ?? 'default';
66+
const legendDetail = (data.features[0].properties?.options?.legend_details || []) as LegendDetails[];
6067
61-
const rawValues: (string | number)[] = data.features.map(f => findValueByKey(f, key) ?? 'default');
68+
const rawValues = data.features.map(f => findValueByKey(f, key));
6269
63-
const uniqueValues: string[] = Array.from(
64-
new Set(rawValues.map(v => String(v))),
70+
const uniqueValues = Array.from(
71+
new Set(rawValues.map(v => v === undefined ? undefined : String(v))),
6572
);
6673
6774
if (legendDisplayOption[0] === 'default') {
68-
uniqueValues.forEach((value, i) => {
69-
colorMap.set(value, generateColor(i, uniqueValues.length));
75+
uniqueValues.forEach((value) => {
76+
if (value === undefined) {
77+
return;
78+
}
79+
const match = legendDetail.find((item: LegendDetails) => item.label === value);
80+
if (match?.color) {
81+
colorMap.set(value, match.color);
82+
}
7083
});
7184
7285
legend.onAdd = function () {
@@ -76,36 +89,43 @@ function generateLabels(data: GeoJSON.FeatureCollection): Map<string, string> {
7689
'background: white; padding: 8px; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.2);',
7790
);
7891
79-
uniqueValues.forEach((value) => {
80-
const color = colorMap.get(value);
81-
div.innerHTML += `
82-
<div style="color:black; margin-bottom:4px;">
83-
<i style="background:${color}; width:12px; height:12px; display:inline-block; margin-right:4px;"></i> ${value}
84-
</div>`;
92+
legendDetail.forEach(({ label, color }) => {
93+
if (uniqueValues.includes(label)) {
94+
div.innerHTML += `
95+
<div style="color:black; margin-bottom:4px;">
96+
<i style="background:${color}; width:12px; height:12px; display:inline-block; margin-right:4px;"></i> ${label}
97+
</div>`;
98+
}
8599
});
100+
if (uniqueValues.includes(undefined)) {
101+
div.innerHTML += `
102+
<div style="color:black; margin-bottom:4px;">
103+
<i style="background:${NO_VALUE_COLOR}; width:12px; height:12px; display:inline-block; margin-right:4px;"></i> ${t('notDefined')}
104+
</div>`;
105+
}
86106
87107
return div;
88108
};
89109
}
90110
else if (legendDisplayOption[0] === 'colorVarient') {
91111
const numericValues: number[] = uniqueValues
112+
.filter(v => v !== undefined)
92113
.map(v => +v)
93114
.filter(v => !Number.isNaN(v));
94115
95-
if (numericValues.length === 0)
96-
return colorMap;
97-
98-
const min = Math.min(...numericValues);
99-
const max = Math.max(...numericValues);
116+
const bins: [number, number][] = [];
117+
if (numericValues.length > 0) {
118+
const min = Math.min(...numericValues);
119+
const max = Math.max(...numericValues);
100120
101-
const numBins = 5;
102-
const step = (max - min) / numBins;
121+
const numBins = 5;
122+
const step = (max - min) / numBins;
103123
104-
const bins: [number, number][] = [];
105-
for (let i = 0; i < numBins; i++) {
106-
const start = min + i * step;
107-
const end = i === numBins - 1 ? max : start + step;
108-
bins.push([start, end]);
124+
for (let i = 0; i < numBins; i++) {
125+
const start = min + i * step;
126+
const end = i === numBins - 1 ? max : start + step;
127+
bins.push([start, end]);
128+
}
109129
}
110130
111131
function getBinLabel(value: number): string {
@@ -137,6 +157,13 @@ function generateLabels(data: GeoJSON.FeatureCollection): Map<string, string> {
137157
</div>`;
138158
});
139159
160+
if (uniqueValues.includes(undefined)) {
161+
div.innerHTML += `
162+
<div style="color:black; margin-bottom:4px;">
163+
<i style="background:${NO_VALUE_COLOR}; width:12px; height:12px; display:inline-block; margin-right:4px;"></i> ${t('notDefined')}
164+
</div>`;
165+
}
166+
140167
return div;
141168
};
142169
@@ -188,7 +215,7 @@ function renderMarkers(data: GeoJSON.FeatureCollection | undefined) {
188215
key = feature.properties?.__binLabel;
189216
}
190217
191-
const color = colorMap.get(key) ?? '#999';
218+
const color = colorMap.get(key) ?? NO_VALUE_COLOR;
192219
193220
const geoJsonLayer = L.geoJSON(feature, {
194221
style: () => ({

composables/dataTypes.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,22 @@ export interface MapDisplayOptions {
1818
title: string
1919
}
2020

21+
export interface LegendDetails {
22+
label: string
23+
color: string
24+
}
25+
2126
export interface Options {
2227
label_option: string
23-
legend_option: string
28+
legend_option: 'default' | 'colorVariant'
2429
type: string
2530
value_group: string
2631
coordinate_field_x?: string
2732
coordinate_field_y?: string
2833
display_option: 'popup' | 'line chart'
2934
popup_name?: string
3035
popup_details?: { label: string, prop: string | string[] }[]
36+
legend_details?: LegendDetails[]
3137
}
3238

3339
export interface UrlInfo {

data/bathingWaterInputLayer.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@
107107
{
108108
"label_option": "EINSTUFUNG_ODER_VORABBEWERTUNG",
109109
"legend_option": "default",
110+
"legend_details": [
111+
{ "label": "ausgezeichnet (Überprüfung nur bei Änderung der Einstufung)", "color": "#10B981" },
112+
{ "label": "gut (Überprüfung mindestens alle vier Jahre)", "color": "#0D9488" },
113+
{ "label": "ausreichend (Überprüfung mindestens alle 3 J)", "color": "#3B82F6" },
114+
{ "label": "mangelhaft (Überprüfung mindestens alle 2 J)", "color": "#FF0000" },
115+
{ "label": "neu", "color": "#8B5CF6" }
116+
],
110117
"type": "series",
111118
"value_group": "",
112119
"display_option": "popup",

data/treesInputLayer.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
{
2121
"label_option": "typ",
2222
"legend_option": "default",
23+
"legend_details": [
24+
{ "label": "Naturdenkmal", "color": "#10B981" },
25+
{ "label": "Städtischer Baum", "color": "#3B82F6" },
26+
{ "label": "Privater Baum", "color": "#0D9488" }
27+
],
2328
"type": "geo",
2429
"value_group": "",
2530
"display_option": "popup",

i18n/locales/de.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
"organization": "Organisation",
1313
"datasetUrl": "Datensatz-URL",
1414
"name": "Name",
15-
"seriesDatasets": "Serien-Datensätze"
15+
"seriesDatasets": "Serien-Datensätze",
16+
"notDefined": "Nicht definiert"
1617
}

i18n/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
"organization": "Organization",
1313
"datasetUrl": "Dataset url",
1414
"name": "Name",
15-
"seriesDatasets": "Series Datasets"
15+
"seriesDatasets": "Series Datasets",
16+
"notDefined": "Not defined"
1617
}

0 commit comments

Comments
 (0)