Die Wetteranimation kann unter Verwendung der "Leaflet" JavaScript Bibliothek benutzt werden.
Erforderliche Komponenten zur Nutzung der Wetteranimation (laden Sie die benötigten Dateien als .zip herunter, ausser javascript_vars.js und javascript_vars_rtofs.js, siehe Erklärung weiter unten:
:
- Leaflet 1.3.1 oder neuer
- jQuery 3.3.1 oder neuer
- Die modifizierte Version von Leaflet-Velocity (hier das Leaflet-Velocity-Original zur Information):
leaflet-velocity.css
leaflet-velocity.js
IE_workarounds.js - Die modifizierte Version von Leaflet.TimeDimension (hier das Leaflet.TimeDimension original zur Information) (notwendig für den Zeitschieber):
iso8601.min.js
leaflet.timedimension.noLayers.src.js
leaflet.timedimension.control.min.css - Einige Variablenwerte werden direkt vom openportguide-Server geladen. Im Gegensatz zu allen obigen Dateien ändern sich diese Dateien ständig und müssen jedes Mal vom openportguide-Server geladen werden, wenn ein animierte Layer angezeigt werden soll! (Alle oben anderen genannten Dateien können heruntergeladen und auf dem eigenen Server plaziert oder in die eigene Software integriert werden, nicht jedoch in den folgenden zwei Dateien):
javascript_vars.js
javascript_vars_rtofs.js
Nützliche Komponenten zur Nutzung der Wetteranimation:
- Schöne Basiskarten als Hintergrund für die Wetteranimation: Esri-Leaflet 2.1.4 oder neuer
Optionen die das Aussehen der Wetteranimation beeinflussen:
Alle Optionen können mit dem Konfigurator getestet werden und der komplette Code zum Anzeigen der Seite ausgegeben werden, siehe https://weather.openportguide.org/map_leaflet.html. Der Konfigurator sollte mit Google Chrome benutzt werden!
Option | Typ | Standardwert | Beschreibung | |
displayValues | Boolean | true | Legt fest ob die Werte an der Mausposition angezeigt werden. | |
velocityType | Text | "Velocity" | Wird für die Beschreibung der angezeigten Werte an der Mausposition genutzt. | |
emptyString | Text | "Unavailable" | Wird angezeigt, wenn keine Werte für die Mausposition vorhanden sind. | |
angleConvention | Text | "meteoCW" | Die Option "angleConvention" bezieht sich auf die Konvention, die verwendet wird, um die Windrichtung als Winkel von der Nordrichtung in der Steuerung auszudrücken. Es kann eine beliebige Kombination aus "bearing" (Winkel, zu dem die Strömung geht) oder "meteo" (Winkel, aus dem die Strömung kommt) und "CW" (Winkelwert steigt im Uhrzeigersinn) oder "CCW" (Winkelwert steigt gegen den Uhrzeigersinn) an. Wenn keine Vorgabe gemacht wird, wird "meteoCW" verwendet. | |
speedUnit | Text | "m/s" | Gibt an in welcher Einheit die Geschwindigkeit an der Mausposition angezeigt wird. Möglich sind folgende Werte: "m/s" für Meter pro Sekunde "km/h" für Kilometer pro Stunde "kt" für Knoten "Bft" für Beaufort |
|
minVelocity | Zahl | 0 | Geschwindigkeit, bei der die Partikelintensität minimal ist (m / s) | |
maxVelocity | Zahl | 10 | Geschwindigkeit, bei der die Partikelintensität maximal ist (m / s) | |
velocityScale | Zahl | 0.005 | Skalierung für Windgeschwindigkeit (völlig willkürlich - dieser Wert sieht gut aus) | |
particleAge | Ganzzahl | 90 | Maximale Anzahl von Frames, die ein Partikel vor der Regeneration gezeichnet wird | |
lineWidth | Ganzzahl | 1 | Linienbreite eines gezeichneten Partikels | |
particleMultiplier | Zahl | 0.003333 | Partikelzahl skalar (völlig willkürlich - dieser Wert sieht gut aus) | |
frameRate | Ganzzahl | 15 | gewünschte Frames pro Sekunde | |
colorScale | Array | ["rgb(36,104,180)", | Farbskala (erster Farbwert entspricht "minVelocity", letzte Farbwert entspricht "maxVelocity", die Farbwerte sind zwischen "minVelocity" und "maxVelocity" gleich verteilt und die Anzahl der Farbwerte ist beliebig. | |
"rgb(60,157,194)", | ||||
"rgb(128,205,193 )", | ||||
"rgb(151,218,168 )", | ||||
"rgb(198,231,181)", | ||||
"rgb(238,247,217)", | ||||
"rgb(255,238,159)", | ||||
"rgb(252,217,125)", | ||||
"rgb(255,182,100)", | ||||
"rgb(252,150,75)", | ||||
"rgb(250,122,52)", | ||||
"rgb(245,64,32)", | ||||
"rgb(237,45,28)", | ||||
"rgb(220,24,32)", | ||||
"rgb(180,0,35)"] |
Beispielcode:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet - Particle animation</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Load Leaflet 1.3.1 -->
<link rel="stylesheet" href="/leaflet/leaflet.css" integrity="sha256-NUykZmi4kbsqfyw0XgSwmjUlpqW/u74zu5ibK9DuiSY=" crossorigin=""/>
<script src="/leaflet/leaflet.js" integrity="sha256-VxczYNPPl3vWEQjM566cf3Le5VD0hnABQ1iohWuvfqc=" crossorigin=""></script>
<!-- Load Esri Leaflet 2.1.4 -->
<script src="/esri-leaflet/esri-leaflet.js" integrity="sha256-5QgVwsPW6/SFxy0erdtA6j9XK682s/cOIrUiq8BuYGw=" crossorigin=""></script>
<!-- Load JQuery 3.3.1 -->
<script src="/jquery-3.3.1.min.js" integrity="sha256-oozPintQUive6gzYPN7KIhwY/B+d8+5rPTxI1ZkgaFU=" crossorigin=""></script>
<!--leaflet-velocity-->
<link rel="stylesheet" href="/leaflet-velocity_tkws/leaflet-velocity.css" />
<script src="/leaflet-velocity_tkws/leaflet-velocity.js"></script>
<script src="/leaflet-velocity_tkws/IE_workarounds.js"></script>
<!--for timeslider-->
<script type="text/javascript" src="/leafletTimeDimension/iso8601.min.js"></script>
<script type="text/javascript" src="/leafletTimeDimension/leaflet.timedimension.noLayers.src.js"></script>
<link rel="stylesheet" href="/leafletTimeDimension/leaflet.timedimension.control.min.css" />
<!--load variable values from server-->
<script type="text/javascript" src="/weather/javascript_vars.js"></script>
<script type="text/javascript" src="/weather/javascript_vars_rtofs.js"></script>
<style>
body { margin:0; padding:0; }
#map { position: absolute; top:0; bottom:0; right:0; left:0; z-index:1; }
</style>
</head>
<body>
<div id="map"></div>
<script>
var osmUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var OpenStreetMap = new L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib, opacity: 0.4}),
Topographic = new L.esri.basemapLayer('Topographic', {opacity: 0.4}),
Streets = new L.esri.basemapLayer('Streets', {opacity: 0.4}),
NationalGeographic = new L.esri.basemapLayer('NationalGeographic', {opacity: 0.4}),
Oceans = new L.esri.basemapLayer('Oceans', {opacity: 0.4}),
Gray = new L.esri.basemapLayer('Gray', {opacity: 0.4}),
DarkGray = new L.esri.basemapLayer('DarkGray'),
Imagery = new L.esri.basemapLayer('Imagery'),
ShadedRelief = new L.esri.basemapLayer('ShadedRelief', {opacity: 0.4});
var startTime = new Date(Date.UTC(GFS_server_year, GFS_server_month - 1, GFS_server_day, GFS_server_hour));
var actualTime = new Date(Date.UTC(GFS_server_year, GFS_server_month - 1, GFS_server_day, GFS_server_hour + 6)); //actual time is about 6 hours ahead to the first forecast timestep
var endTime = new Date(Date.UTC(GFS_server_year, GFS_server_month - 1, GFS_server_day, GFS_server_hour + ((GFS_timesteps-1)*GFS_interval)));
var dataTimeInterval = startTime.toISOString() + "/" + endTime.toISOString();
var actualInterval = GFS_interval*2 ; // show only every second available timestep (GFS_interval is "3" hours
var baseIndex = 1; // index of the wind10mArray containing the layer nearest to the actual time (2 if actualIndex==GFS_Index, 1 if actualIndex==GFS_Index*2)
var dataPeriod = "PT" + (actualInterval) + "H";
var wind10mBaseURL = 'weather/wind10m/';
var wind10mBaseName = 'wind10m_{h}h';
var wind10mName = '';
var wind10mArray = [];
var startTimeRTOFS = new Date(Date.UTC(RTOFS_server_year, RTOFS_server_month - 1, RTOFS_server_day, RTOFS_server_hour));
var actualTimeRTOFS = new Date(Date.UTC(RTOFS_server_year, RTOFS_server_month - 1, RTOFS_server_day, RTOFS_server_hour + 6));
var endTimeRTOFS = new Date(Date.UTC(RTOFS_server_year, RTOFS_server_month - 1, RTOFS_server_day, RTOFS_server_hour + ((RTOFS_timesteps-1)*RTOFS_interval)));
var dataTimeIntervalRTOFS = startTimeRTOFS.toISOString() + "/" + endTimeRTOFS.toISOString();
var actualIntervalRTOFS = RTOFS_interval*2 ; // show only every second available timestep
var baseIndexRTOFS = 1; // index of the seaSurfaceCurrent Array containing the layer nearest to the actual time (2 if actualIndex==RTOFS_Index, 1 if actualIndex==RTOFS_Index*2)
var dataPeriodRTOFS = "PT" + (actualIntervalRTOFS) + "H";
var seaSurfaceCurrentBaseURL = 'weather/sea_surface_current/';
var seaSurfaceCurrentBaseName = 'sea_surface_current_{h}h';
var seaSurfaceCurrentName = '';
var seaSurfaceCurrentArray = [];
var map = new L.map('map', {
center: [54.04, 9.07],
zoom: 4,
layers: [Imagery],
timeDimension: true,
timeDimensionOptions: {
timeInterval: dataTimeInterval,
period: dataPeriod,
currentTime: actualTime
},
timeDimensionControl: true,
timeDimensionControlOptions: {
loopButton: false,
limitSliders: false,
playButton: false,
speedSlider: false
}
});
var baseMaps = {
"OpenStreetMap": OpenStreetMap,
"Topographic": Topographic,
"Streets": Streets,
"NationalGeographic": NationalGeographic,
"<span style='color: gray'>Gray</span>": Gray,
"DarkGray": DarkGray,
"Imagery": Imagery,
"ShadedRelief": ShadedRelief,
"Oceans": Oceans,
};
var layerControl = new L.control.layers(baseMaps);
layerControl.addTo(map);
var wind10mLayerGroup = new L.layerGroup([], {});
wind10mArray.length = map.timeDimension._availableTimes.length;
var actualTimeIndex = map.timeDimension._currentTimeIndex;
// load data (u, v grids) from weather.openportguide.de
layerControl.addOverlay(wind10mLayerGroup, 'wind10m');
updateLayer(wind10mArray[actualTimeIndex]);
window.setInterval(function() { //check if time index changed
if (actualTimeIndex != map.timeDimension._currentTimeIndex) {
actualTimeIndex = map.timeDimension._currentTimeIndex;
updateLayer(wind10mArray[actualTimeIndex]);
}
},100);
function updateLayer(Layer){ //updates the actual layer
wind10mLayerGroup.clearLayers();
wind10mName = wind10mBaseName.replace(/{h}/g, (actualTimeIndex - baseIndex) * actualInterval);
$.getJSON(wind10mBaseURL + wind10mName + ".json", function (data) {
this[wind10mName] = L.velocityLayer({
displayValues: true,
displayOptions: {
velocityType: "Wind",
emptyString: "No wind data",
angleConvention: "bearingCW",
speedUnit: "Bft"
},
data: data,
minVelocity: 0,
maxVelocity: 30,
velocityScale: 0.002,
particleAge: 90,
lineWidth: 1,
particleMultiplier: 0.0033,
frameRate: 15,
colorScale: ["#2468b4", "#3c9dc2", "#80cdc1", "#97daa8", "#c6e7b5", "#eef7d9", "#ffee9f", "#fcd97d", "#ffb664", "#fc964b", "#fa7034", "#f54020", "#ed2d1c", "#dc1820", "#b40023"]
});
wind10mLayerGroup.addLayer(this[wind10mName]);
wind10mArray[actualTimeIndex] = wind10mLayerGroup.getLayer(wind10mLayerGroup.getLayerId(this[wind10mName]));
wind10mLayerGroup.addTo(map);
});
}
</script>
</body>
</html>
Tipps:
Wenn Basiskarten mit hellen Farben wie z.B. Openstreetmap als Hintergrund genutzt werden, ist die Wetteranimation schlecht zu sehen.
In diesem Fall kann einfach die Deckkraft des Basislayers reduziert werden und das Bild wird durch den schwarzen Hintergrund dunkler, z.B.:
var OpenStreetMap = new L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib, opacity: 0.4});
Es ist ein großer Unterschied welcher Browser verwendet wird, daher hier einige Anmerkung zur Kompatibilität mit den verschiedenen Browsern:
Browser | Empfehlung | Bemerkungen |
Chrome | gut sehr | Die Animation läuft auf PCs aller Leistungsklassen mit einem sehr niedrigen Ressourcenverbrauch. |
Opera | gut | Die Animation läuft auf PCs aller Leistungsklassen mit einem vernünftigen Ressourcenverbrauch. |
Firefox | eher nicht zu empfehlen | Die Animation läuft auf leistungsfähigen Rechnern flüssig, auch wenn die Maus über die Karte bewegt wird.Die CPU-Last ist allerdings bis zu 10 mal höher als bei der Anzeige mit Chrome. |
Edge | nicht zu empfehlen | Die Animation läuft auch auf leistungsfähigen PCs nicht flüssig, wenn die Maus auf der Karte bewegt wird. |
Internet Explorer | nicht zu empfehlen | Die Animation läuft auch auf leistungsfähigen PCs nicht flüssig, wenn die Maus auf der Karte bewegt wird. Außerdem ist die Animation wegen der Inkompatibilität mit einigen der neueren Komponenten von Java nur mit zusätzlichem Code (siehe oben) lauffähig. Da der Internet Explorer nicht weiterentwickelt wird, ist seine Verwendung nur als absolute Notlösung zu sehen. |