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:

:

Nützliche Komponenten zur Nutzung der Wetteranimation:

 

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.