Skip to content

Commit

Permalink
Implement layer controls
Browse files Browse the repository at this point in the history
  • Loading branch information
henhuy committed Jun 26, 2024
1 parent a8f97f9 commit 4263140
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 1 deletion.
39 changes: 39 additions & 0 deletions slapp/explorer/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Form definitions for the explorer app."""
from __future__ import annotations

from typing import TYPE_CHECKING

from django.forms import BooleanField, Form, renderers
from django.utils.safestring import mark_safe

if TYPE_CHECKING:
from django_mapengine.legend import LegendLayer

from .widgets import SwitchWidget


class TemplateForm(Form): # noqa: D101
template_name = None

def __str__(self) -> str: # noqa: D105
if self.template_name:
renderer = renderers.get_default_renderer()
return mark_safe(renderer.render(self.template_name, {"form": self})) # noqa: S308
return super().__str__()


class StaticLayerForm(TemplateForm): # noqa: D101
template_name = "forms/layer.html"
switch = BooleanField(
label=False,
widget=SwitchWidget(
attrs={
"switch_class": "form-check form-switch",
"switch_input_class": "form-check-input",
},
),
)

def __init__(self, layer: LegendLayer, *args, **kwargs) -> None: # noqa: ANN002, D107
super().__init__(*args, **kwargs)
self.layer = layer
247 changes: 247 additions & 0 deletions slapp/explorer/map_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
"""Actual map setup is done here."""
import dataclasses

from django.utils.translation import gettext_lazy as _
from django_mapengine import legend


@dataclasses.dataclass
class SymbolLegendLayer(legend.LegendLayer):
"""Adds symbol field."""

symbol: str = "rectangle"


LEGEND = {
_("Renewables"): [
SymbolLegendLayer(
_("Wind turbine"),
_("Windenergieanlagen"),
layer_id="wind",
color="#6A89CC",
symbol="circle",
),
SymbolLegendLayer(
_("Roof-mounted PV"),
_("PV-Aufdachanlagen"),
layer_id="pvroof",
color="#FFD660",
symbol="circle",
),
SymbolLegendLayer(
_("Ground-mounted PV"),
_("PV-Freiflächenanlagen"),
layer_id="pvground",
color="#EFAD25",
symbol="circle",
),
SymbolLegendLayer(
_("Hydro"),
_("Wasserkraftanlagen"),
layer_id="hydro",
color="#A9BDE8",
symbol="circle",
),
SymbolLegendLayer(
_("Biomass"),
_("Biomasseanlagen"),
layer_id="biomass",
color="#52C41A",
symbol="circle",
),
SymbolLegendLayer(
_("Combustion"),
_("Verbrennungskraftwerke"),
layer_id="combustion",
color="#E6772E",
symbol="circle",
),
SymbolLegendLayer(
_("GSGK"),
_("Geo- oder Solarthermie-, Grubengas- und Klärschlamm-Anlagen"),
layer_id="gsgk",
color="#C27BA0",
symbol="circle",
),
SymbolLegendLayer(
_("Batteriespeicher"),
_("Batteriespeicher"),
layer_id="storage",
color="#8D2D5F",
symbol="circle",
),
],
_("Settlements Infrastructure"): [
legend.LegendLayer(
_("Settlement 0m"),
_(
"Eine Siedlung ist ein Gebiet, welches die menschliche Niederlassung in beliebiger Form der "
"gruppierten Behausung beschreibt. Sie beinhaltet überwiegend Wohngebiete.",
),
layer_id="settlement-0m",
),
legend.LegendLayer(
_("Industry"),
_(
"Industrie- und Gewerbegebiete werden ausgewiesen, um störende Einwirkungen von Betrieben wie Lärm, "
"Geruch oder Gefahren auf Wohnbebauung zu vermeiden.",
),
layer_id="industry",
),
legend.LegendLayer(
_("Road Railway 500m"),
_(
"Die Flächen längs von Autobahnen oder Schienenwegen werden durch Erstellen einer 500 m breiten "
"Pufferzone abzüglich einer 15 m breiten Pufferzone gebildet.",
),
layer_id="road_railway-500m_region",
),
legend.LegendLayer(
_("Road"),
_("Zu den Straßen gehören unter anderem Bundesautobahnen, Bundesfern-, Landes- und Kreisstraßen."),
layer_id="road_default",
),
legend.LegendLayer(
_("Railway"),
_(
"Der Bahnverkehr ist ein wichtiger Bestandteil der Verkehrsinfrastruktur. Berücksichtigt "
"werden Fernverkehrsbahnen, Regionalverkehrsbahnen und S-Bahnen.",
),
layer_id="railway",
),
legend.LegendLayer(
_("Aviation"),
_(
"Zur Infrastruktur des Luftverkehrs gehören neben Start- und Landebahnen die "
"Flughafengebäude und Hangars.",
),
layer_id="aviation",
),
legend.LegendLayer(
_("Air Traffic"),
_("Ein Drehfunkfeuer ist ein Funkfeuer für die Luftfahrtnavigation."),
layer_id="air_traffic",
),
legend.LegendLayer(
_("Military"),
_("Zu den militärisch genutzten Flächen gehören militärische Sperrgebiete und Liegenschaften."),
layer_id="military",
),
legend.LegendLayer(
_("Grid"),
_(
"Zum Übertragungsnetz zählen die elektrischen Leitungen sowie die dazugehörigen Einrichtungen "
"wie Schalt- und Umspannwerke der Höchst- und Hochspannungsebenen.",
),
layer_id="grid",
),
],
_("Nature Landscape"): [
legend.LegendLayer(
_("Nature Conservation Area"),
_(
"Naturschutzgebiete dienen dem Schutz der Natur und Landschaft. Sie tragen zur Erhaltung, Entwicklung "
"und Wiederherstellung der Lebensstätte für bestimmte wild lebende Tier- und Pflanzenarten bei. Aber "
"auch aus wissenschaftlichen, naturgeschichtlichen und ästhetischen Gründen werden Teile oder die "
"Gesamtheit der Natur in Schutz genommen.",
),
layer_id="nature_conservation_area",
),
legend.LegendLayer(
_("Fauna Flora Habitat"),
_(
"Die Fauna-Flora-Habitat-Richtlinie ist eine Naturschutz-Richtlinie der Europäischen Union (EU), die "
"seltene oder bedrohte Arten und Lebensräume schützt. Sie gehört zum Schutzgebietsnetz Natura 2000.",
),
layer_id="fauna_flora_habitat",
),
legend.LegendLayer(
_("Special Protection Area"),
_(
"Die Vogelschutzrichtlinie der Europäischen Union (EU) dient der Erhaltung der wild lebenden, "
"heimischen Vogelarten. Sie regelt den Schutz dieser Vögel, ihrer Eier und Lebensräume wie Brut-, "
"Rast- und Überwinterungsgebiete. Die Vogelschutzgebiete gehören zum Schutzgebietsnetz Natura 2000.",
),
layer_id="special_protection_area",
),
legend.LegendLayer(
_("Biosphere Reserve"),
_(
"Biosphärenreservate sind großräumige und für bestimmte Landschaftstypen charakteristische Gebiete "
"mit interdisziplinärem Ansatz. In diesen von der UNESCO initiierten Modellregionen soll nachhaltige "
"Entwicklung in ökologischer, ökonomischer und sozialer Hinsicht exemplarisch verwirklicht werden. "
"Die Biosphärenreservate sind in drei Zonen eingeteilt: Eine naturschutzorientierte Kernzone "
"(Schutzfunktion), eine am Landschaftsschutz orientierte Pflegezone (Forschungs- und Bildungsfunktion)"
" und eine sozioökonomisch orientierte Entwicklungszone (Entwicklungsfunktion).",
),
layer_id="biosphere_reserve",
),
legend.LegendLayer(
_("Landscape Protection Area"),
_(
"Landschaftsschutzgebiete sind oft großflächiger angelegt und zielen auf den Erhalt des "
"Landschaftscharakters, das allgemeine Erscheinungsbild der Landschaft und dessen Schönheit ab. "
"Sie haben einen geringeren Schutzstatus als etwa Naturschutzgebiete oder Nationalparke und "
"unterliegen daher weniger strengen Nutzungsbeschränkungen.",
),
layer_id="landscape_protection_area",
),
legend.LegendLayer(
_("Forest"),
_(
"Wald umfasst eine Vielzahl an mit Bäumen und anderer Vegetation bedeckten Fläche "
"mit unterschiedlicher forstwirtschaftlicher Nutzung und ökologischer Bedeutung. Wälder können in "
"Nadel-, Laub- und Mischwald sowie anhand der Waldfunktionen (z. B. Schutzwald, Erholungswald) "
"unterschieden werden.",
),
layer_id="forest",
),
legend.LegendLayer(
_("Drinking Water Protection Area"),
_(
"Wasserschutzgebiete stellen die öffentliche Wasserversorgung durch die Vermeidung "
"schädlicher Eintragungen in die Gewässer "
"(Grundwasser, oberirdische Gewässer, Küstengewässer) sicher.",
),
layer_id="drinking_water_protection_area",
),
legend.LegendLayer(
_("Water"),
_(
"Ein Gewässer ist in der Natur fließendes oder stehendes Wasser. "
"Dazu gehören der Wasserkörper, das Gewässerbett und der Grundwasserleiter.",
),
layer_id="water",
),
legend.LegendLayer(
_("Floodplain"),
_(
"Bei Überschwemmungsgebieten handelt es sich um die Flächen, "
"die statistisch gesehen mindestens einmal in hundert Jahren überflutet sein können.",
),
layer_id="floodplain",
),
legend.LegendLayer(
_("Soil Quality High"),
_(
"Acker- und Grünlandflächen mit hoher Bodenqualität (Soil Quality Rating (SQR) >= 40). Um die "
"Flächenkonkurrenz zwischen landwirtschaftlicher Nutzung und Energiegewinnung zu minimieren, wird bei "
"den links einstellbaren PV-Freiflächenpotenzialen als Grenzwert ein SQR von 40 angenommen, es werden "
"also lediglich Flächen mit sehr geringer und geringer Ertragsfähigkeit als potenzielle "
"Standorte berücksichtigt.",
),
layer_id="soil_quality_high",
),
legend.LegendLayer(
_("Soil Quality Low"),
_(
"Acker- und Grünlandflächen inner- und außerhalb benachteiligter Gebiete mit geringer Bodenqualität "
"(Soil Quality Rating (SQR) < 40). Um die Flächenkonkurrenz zwischen landwirtschaftlicher Nutzung und "
"Energiegewinnung zu minimieren, wird bei den links einstellbaren PV-Freiflächenpotenzialen als "
"Grenzwert ein SQR von 40 angenommen, es werden also lediglich Flächen mit sehr geringer und geringer "
"Ertragsfähigkeit als potenzielle Standorte berücksichtigt.",
),
layer_id="soil_quality_low",
),
],
}
8 changes: 7 additions & 1 deletion slapp/explorer/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from django.views.generic import TemplateView
from django_mapengine import views

from . import forms, map_config
from .models import Municipality

MAX_MUNICIPALITY_COUNT = 3
Expand All @@ -27,7 +28,12 @@ class MapGLView(TemplateView, views.MapEngineMixin):
"""Single view for the map."""

template_name = "pages/map.html"
extra_context = {}
extra_context = {
"area_switches": {
category: [forms.StaticLayerForm(layer) for layer in layers]
for category, layers in map_config.LEGEND.items()
},
}


def municipalities_details(ids: list[int]) -> list[Municipality]:
Expand Down
9 changes: 9 additions & 0 deletions slapp/explorer/widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Module holds widgets for digiplan."""

from django.forms.widgets import Widget


class SwitchWidget(Widget):
"""Widget to render switches."""

template_name = "widgets/switch.html"
4 changes: 4 additions & 0 deletions slapp/static/images/icons/i_info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions slapp/templates/forms/layer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{% load static i18n %}

<form class="layers__item static-layer {% if form.layer.clustered %}cluster-layer{% endif %}">
<div class="map-layer">
<div class="map-layer__legend">
<div class="map-layer__legend-color{% if form.layer.symbol == 'circle' %} map-layer__legend-color--rounded{% endif %}"
style="background-color: {{ form.layer.get_color }}"></div>
<div class="map-layer__legend-text">
<label class="form-check-label" for="{{ form.layer.get_layer_id }}">{{ form.layer.name }}</label>
</div>
</div>
<div class="map-layer__control">
<div class="map-layer__control-i">
{% include 'widgets/info_button.html' with description=form.layer.description %}
</div>
<div class="map-layer__control-toggle c-switch">
<div class="form-check form-switch">
<input class="form-check-input layer__switch"
type="checkbox"
id="{{ form.layer.get_layer_id }}" />
</div>
</div>
</div>
</div>
</form>
1 change: 1 addition & 0 deletions slapp/templates/pages/map.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ <h4 class="text-center">Karte</h4>
</p>
</div>
<div class="col-9">
{% include 'pages/partials/layer_box.html' %}
<div id="legend" class="legend"></div>
<div id="map"></div>
</div>
Expand Down
22 changes: 22 additions & 0 deletions slapp/templates/pages/partials/layer_box.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="map__layers-btn" id="js-map-layers-btn">
<svg width="16"
height="16"
version="1.1"
fill="currentColor"
viewBox="0 0 16.933 16.933"
xmlns="http://www.w3.org/2000/svg">
<path d="m8.4667 0.053743-0.23616 0.11731-8.1855 4.0933 8.4217 4.2111 8.4222-4.2111-8.4222-4.2106zm0 1.1813 6.057 3.0293-6.057 3.0277-6.0565-3.0277 6.0565-3.0293zm-8.4217 7.2404 8.4222 4.2111 8.4217-4.2111h-2.3652l-6.0565 3.0277-6.057-3.0277h-2.3652zm-5.1676e-4 4.2468 8.4222 4.2111 8.4217-4.2111h-2.3652l-6.0565 3.0277-6.057-3.0277h-2.3652z" />
</svg>
</div>
<div class="map__layers-box" id="js-map-layers-box">
<div class="map__layers-close">
<button type="button"
class="btn-close"
id="js-map-layers-box-close"
aria-label="Close"></button>
</div>
{% for category, layers in area_switches.items %}
<p class="map__layers-heading">{{ category }}</p>
{% for layer in layers %}{{ layer }}{% endfor %}
{% endfor %}
</div>
7 changes: 7 additions & 0 deletions slapp/templates/widgets/info_button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% load static %}

<img src="{% static 'images/icons/i_info.svg' %}"
alt="Info Icon"
class="i-icon"
data-bs-toggle="tooltip"
title="{{ description }}" />
Loading

0 comments on commit 4263140

Please sign in to comment.