-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #73 from rl-institut-private/add/chart-to-popup
Add/chart to popup
- Loading branch information
Showing
12 changed files
with
386 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,207 @@ | ||
"use strict"; | ||
|
||
function add_popup(layer_id, fields, template_id="default") { | ||
map.on("click", layer_id, function (e) { | ||
let coordinates; | ||
// Check if popup already exists: | ||
if ($('.mapboxgl-popup').length > 0) {return;} | ||
|
||
if ("lat" in e.features[0].properties) { | ||
// Get coordinates from lat/lon: | ||
coordinates = [e.features[0].properties.lat, e.features[0].properties.lon]; | ||
} else { | ||
// Get coordinates from geometry: | ||
coordinates = e.lngLat; | ||
async function fetchGetJson(url) { | ||
try { | ||
// Default options are marked with * | ||
const response = await fetch(url, { | ||
method: "GET", // *GET, POST, PUT, DELETE, etc. | ||
mode: "cors", // no-cors, *cors, same-origin | ||
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached | ||
credentials: "same-origin", // include, *same-origin, omit | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, redirect: "follow", // manual, *follow, error | ||
referrerPolicy: "no-referrer", // no-referrer, *client | ||
}); | ||
return await response.json(); // parses JSON response into native JavaScript objects | ||
} catch (err) { | ||
if (err instanceof Error) { | ||
throw new Error(err.message); | ||
} | ||
var template = $($("#" + template_id + "_popup").prop("content")).find("div"); | ||
var clone = template.clone(); | ||
var table = clone.find("table"); | ||
for (var label in fields) { | ||
const key = fields[label]; | ||
const value = e.features[0].properties[key]; | ||
let row = $("<tr>"); | ||
row.append($("<td>").text(label)); | ||
row.append($("<td>").text(value)); | ||
table.append(row); | ||
throw err; | ||
} | ||
} | ||
|
||
function createCoordinates(event) { | ||
if ("lat" in event.features[0].properties) { | ||
return [event.features[0].properties.lat, event.features[0].properties.lon]; | ||
} | ||
return event.lngLat; | ||
} | ||
|
||
function createListByName(name, series) { | ||
let list = []; | ||
for (const item in series) { | ||
list.push(series[item][name]); | ||
} | ||
return list; | ||
} | ||
|
||
function add_popup(layer_id, fields, template_id = "default") { | ||
map.on("click", layer_id, function (event) { | ||
/* | ||
Check if popup already exists | ||
*/ | ||
if ($('.mapboxgl-popup').length > 0) { | ||
return; | ||
} | ||
new maplibregl.Popup().setLngLat(coordinates).setHTML(clone.html()).addTo(map); | ||
|
||
/* | ||
Construct Coordinates From Event | ||
*/ | ||
const coordinates = createCoordinates(event); | ||
|
||
// TODO: construct dynamically via emitted id by event | ||
const url = "/static/tests/api/popup.json??lookup=population&municipality=12lang=en"; | ||
|
||
fetchGetJson(url).then(// TODO: for now we assume response has chart. Later determine dynamically. | ||
(response) => { | ||
/* | ||
Construct Popup From Event And Params | ||
*/ | ||
const template = document.getElementById("js-" + template_id + "_popup"); | ||
const clone = template.content.cloneNode(true); | ||
const html = clone.getElementById("js-" + "popup"); | ||
for (const field in fields) { | ||
if (field === "title") { | ||
const titleElement = html.querySelector("#js-popup__title"); | ||
const {title} = response; | ||
titleElement.innerHTML = title; | ||
} | ||
if (field === "municipality") { | ||
const municipalityElement = html.querySelector("#js-popup__municipality"); | ||
const {municipality} = response; | ||
municipalityElement.innerHTML = `(${municipality})`; | ||
} | ||
if (field === "key-values") { | ||
const lang = getLanguage(); | ||
const keyValuesElement = html.querySelector("#js-popup__key-values"); | ||
const { | ||
keyValues: { | ||
unit, | ||
year, | ||
municipalityValue, | ||
regionTitle, | ||
regionValue, | ||
} | ||
} = response; | ||
keyValuesElement.innerHTML = ` | ||
<span class="key-values__municipality"> | ||
<span class="key-values__unit">${unit}</span> | ||
<span class="key-values__year">${year}</span> | ||
<span class="key-values__region-value">${municipalityValue.toLocaleString(lang)}</span> | ||
</span> | ||
<span class="key-values__region"> | ||
<span class="key-values__municipality-title">${regionTitle}</span>: | ||
<span class="key-values__municipality-value">${regionValue.toLocaleString(lang)}</span> | ||
</span> | ||
`; | ||
} | ||
if (field === "description") { | ||
const descriptionElement = html.querySelector("#js-popup__description"); | ||
const {description} = response; | ||
descriptionElement.innerHTML = description; | ||
} | ||
if (field === "chart") { | ||
|
||
// Chart Title | ||
const {chart: {title}} = response; | ||
|
||
// Chart | ||
const chartElement = html.querySelector("#js-popup__chart"); | ||
const chart = echarts.init(chartElement, null, {renderer: 'svg'}); | ||
// TODO: use chartType in payload to construct chart dynamically. For now we assume bar chart type. | ||
// TODO: In this fetch we always expect one payload item. Make failsafe. | ||
const {chart: {data: {series}}} = response; | ||
const xAxisData = createListByName("key", series); | ||
const yAxisData = createListByName("value", series); | ||
const option = { | ||
title: { | ||
text: title, | ||
textStyle: { | ||
color: '#002E50', | ||
fontSize: 14, | ||
fontWeight: 400, | ||
lineHeight: 16 | ||
}, | ||
left: 'center' | ||
}, | ||
animation: false, | ||
tooltip: { | ||
trigger: 'axis', | ||
axisPointer: { | ||
type: 'shadow' | ||
} | ||
}, | ||
grid: { | ||
left: 16, | ||
right: 0, | ||
bottom: 32, | ||
top: 48, | ||
containLabel: true | ||
}, | ||
textStyle: { | ||
color: '#002E50' | ||
}, | ||
xAxis: [{ | ||
type: 'category', | ||
data: xAxisData, | ||
axisTick: { | ||
show: false | ||
}, | ||
axisLine: { | ||
show: true, | ||
lineStyle: { | ||
color: '#ECF2F6' | ||
} | ||
}, | ||
}], | ||
yAxis: [{ | ||
type: 'value', | ||
splitLine: { | ||
show: true, | ||
lineStyle: { | ||
color: '#ECF2F6' | ||
} | ||
} | ||
}], | ||
series: [{ | ||
name: 'Direct', | ||
type: 'line', | ||
symbol: 'circle', | ||
symbolSize: 6, | ||
data: yAxisData, | ||
lineStyle: { | ||
color: '#002E50' | ||
}, | ||
itemStyle: { | ||
color: '#002E50' | ||
} | ||
}] | ||
}; | ||
chart.setOption(option); | ||
requestAnimationFrame(() => { | ||
new maplibregl.Popup({ | ||
// https://maplibre.org/maplibre-gl-js-docs/api/markers/#popup-parameters | ||
maxWidth: "280px", | ||
}).setLngLat(coordinates).setHTML(html.innerHTML).addTo(map); | ||
}); | ||
} | ||
if (field === "sources") { | ||
const sourcesElement = html.querySelector("#js-popup__sources"); | ||
let links = []; | ||
for (const index in response.sources) { | ||
const url = response.sources[index].url; | ||
const name = response.sources[index].name; | ||
links.push(`<a href="${url}">${name}</a>`); | ||
} | ||
sourcesElement.innerHTML = `Quellen: ${links.join(", ")}`; | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
$(document).ready(function() { | ||
$(document).ready(function () { | ||
$('#js-intro-modal').modal('show'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,7 @@ | |
-moz-user-select: none; | ||
-ms-user-select: none; | ||
user-select: none; | ||
pointer-events: none; | ||
} | ||
|
||
// UL | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
.mapboxgl-popup-content, .maplibregl-popup-content { | ||
@extend .p-0; | ||
width: $popup-width; | ||
font-family: $font-family-sans-serif; | ||
|
||
.popup { | ||
&__header { | ||
@extend .bg-light; | ||
@extend .py-2; | ||
@include flex-row-justify-center; | ||
@include user-select-none; | ||
} | ||
|
||
&__title, | ||
&__municipality { | ||
@extend .fs-4; | ||
@extend .fw-light; | ||
@extend .mb-0; | ||
letter-spacing: $letter-spacing-large; | ||
} | ||
|
||
&__municipality { | ||
@extend .ps-1; | ||
} | ||
|
||
&__key-values, | ||
&__chart, | ||
&__description, | ||
&__sources { | ||
padding: $padding-normal; | ||
} | ||
|
||
&__key-values { | ||
@extend .d-flex; | ||
@extend .flex-row; | ||
@extend .justify-content-between; | ||
@extend .fs-7; | ||
@extend .border-bottom; | ||
@include user-select-none; | ||
|
||
.key-values { | ||
& > span { | ||
@extend .d-block; | ||
} | ||
|
||
&__municipality { | ||
@extend .fw-bold; | ||
} | ||
|
||
&__region { | ||
color: $gray-600; | ||
} | ||
|
||
&__region-value { | ||
@extend .bg-primary; | ||
@extend .text-white; | ||
margin-left: 4px; | ||
} | ||
|
||
&__municipality-value { | ||
@extend .bg-light; | ||
} | ||
|
||
&__region-value, | ||
&__municipality-value { | ||
padding: 4px 8px; | ||
@extend .rounded; | ||
} | ||
} | ||
} | ||
|
||
&__description { | ||
@extend .fw-light; | ||
@extend .fs-7; | ||
} | ||
|
||
&__sources { | ||
@extend .border-top; | ||
@extend .lh-sm; | ||
|
||
a { | ||
@extend .fw-bold; | ||
} | ||
} | ||
} | ||
|
||
.maplibregl-popup-close-button, | ||
.mapboxgl-popup-close-button { | ||
@extend .fs-3; | ||
@extend .fw-light; | ||
@extend .px-2; | ||
@extend .py-1; | ||
} | ||
} |
Oops, something went wrong.