Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate map layer controls #72

Draft
wants to merge 6 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ repos:

- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.2.0'
rev: 'v0.3.1'
hooks:
- id: ruff

Expand Down
2 changes: 1 addition & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
django-cors-headers==4.3.0 # https://github.com/adamchainz/django-cors-headers
# DRF-spectacular for api documentation
drf-spectacular==0.27.1 # https://github.com/tfranzel/drf-spectacular
git+https://github.com/rl-institut/django-mapengine.git@v0.18.0 # django-mapengine
django-mapengine==2.0.1 # django-mapengine
django-distill>=2.6,<4.0
geojson>=2.5.0,<4.0
django-geojson>=3.1.0,<4.0
Expand Down
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.
16 changes: 10 additions & 6 deletions slapp/static/css/project.css → slapp/static/scss/app.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
/* These styles are generated from project.scss. */
@charset "utf-8";

@import "base/variable_overrides";

@import "../vendors/bootstrap/scss/bootstrap";

@import 'base/variables';

@import 'components/map';
@import 'components/controls';

.alert-debug {
color: black;
Expand Down Expand Up @@ -35,8 +44,3 @@
border: 1px solid #ddd;
padding: 10px;
}

#map {
width: 100%;
height: 100%
}
Loading