1var default_lang_settings = { 2 loading: 'Wird geladen...', 3 months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], 4 weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], 5 shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], 6}; 7 8var simpleTransContainer = { 9 "de": { 10 partialData: "Daten anteilig" 11 }, 12 "en" : { 13 partialData: "Partial data" 14 } 15}; 16 17var simpleTrans = function (key) { 18 return simpleTransContainer[displayLanguage().toLowerCase()][key]; 19} 20 21function cssVar(name, fallback) { 22 const darkBody = document.body.classList.contains('dark'); 23 if (darkBody) { 24 // Wert aus body.dark holen 25 return getComputedStyle(document.body).getPropertyValue(name).trim() 26 || getComputedStyle(document.documentElement).getPropertyValue(name).trim() 27 || fallback || ''; 28 } 29 // Standardwert aus :root holen 30 var value = getComputedStyle(document.documentElement).getPropertyValue(name).trim(); 31 //console.log('cssVar',name,value); 32 return value || fallback || ''; 33} 34 35 36var getDynDateFormat = function(x) { 37 var date_format = ''; 38 if (typeof hccompact_units['date'] !== 'undefined') { 39 date_format = hccompact_units['date']; 40 if(typeof x !== 'undefined' && date_format.search('{day-nth}')){ 41 var day = Highcharts.dateFormat("%e", x); 42 date_format=date_format.replace('{day-nth}',day+nth(day)); 43 } 44 return date_format; 45 } 46 if(displayLanguage()=="EN"){ 47 var day = Highcharts.dateFormat("%e", x); 48 date_format="%A, %b the "+day+nth(day)+" at %H:%M"; 49 } 50 else { 51 date_format="%A, den %e. %B, %H:%M Uhr"; 52 } 53 return date_format; 54}; 55 56var getDynDayLongFormat = function(x) { 57 var date_format = ''; 58 if (typeof hccompact_units['date_day_long'] !== 'undefined') { 59 date_format = hccompact_units['date_day_long']; 60 if(typeof x !== 'undefined' && date_format.search('{day-nth}')){ 61 var day = Highcharts.dateFormat("%e", x); 62 date_format=date_format.replace('{day-nth}',day+nth(day)); 63 } 64 return date_format; 65 } 66 if(displayLanguage()=="EN"){ 67 return '<b>%A</b>, %e. %B'; 68 } 69 return '<b>%A</b>, %e. %B'; 70}; 71 72var getDynDayDateFormat = function(x, width) { 73 var date_format = ''; 74 if (typeof hccompact_units['date_day_head'] !== 'undefined') { 75 var sprungmarke = 400; 76 if(typeof x !== 'undefined' && date_format.search('{day-nth}')){ 77 sprungmarke = 520; 78 } 79 date_format = hccompact_units['date_day_head']; 80 if (typeof width !== 'undefined' && width <= sprungmarke && typeof hccompact_units['date_day_head_short'] !== 'undefined') { 81 date_format = hccompact_units['date_day_head_short']; 82 } 83 if(typeof x !== 'undefined' && date_format.search('{day-nth}')){ 84 var day = Highcharts.dateFormat("%e", x); 85 date_format=date_format.replace('{day-nth}',day+nth(day)); 86 } 87 return date_format; 88 } 89 if(displayLanguage()=="EN"){ 90 return '<b>%a</b>, %e.%b'; 91 } 92 return '<b>%a</b>, %e.%b'; 93 /* 94 date_format='<b>%a</b>, %b, '+day+nth(day); 95 date_format='<b>%a</b>'; 96 date_format='<b>%a</b>, %e. %b'; 97 date_format='<b>%a</b>'; 98 */ 99}; 100var getDynDayShortDateFormat = function(x, width) { 101 var date_format = ''; 102 if (typeof hccompact_units['date_day_head_short_date'] !== 'undefined') { 103 date_format = hccompact_units['date_day_head_short_date']; 104 var sprungmarke = 400; 105 if(typeof x !== 'undefined' && date_format.search('{day-nth}')){ 106 sprungmarke = 520; 107 } 108 if (typeof width !== 'undefined' && width <= sprungmarke && typeof hccompact_units['date_day_head_short'] !== 'undefined') { 109 date_format = hccompact_units['date_day_head_short']; 110 } 111 if(typeof x !== 'undefined' && date_format.search('{day-nth}')){ 112 var day = Highcharts.dateFormat("%e", x); 113 date_format=date_format.replace('{day-nth}',day+nth(day)); 114 } 115 return date_format; 116 } 117 if(displayLanguage()=="EN"){ 118 return '%e.%b'; 119 } 120 return '%e.%b'; 121 /* 122 date_format='<b>%a</b>, %b, '+day+nth(day); 123 date_format='<b>%a</b>'; 124 date_format='<b>%a</b>, %e. %b'; 125 date_format='<b>%a</b>'; 126 */ 127}; 128 129var getDynHourDateFormat = function() { 130 if (typeof hccompact_units['date_hour_head'] !== 'undefined') { 131 return hccompact_units['date_hour_head']; 132 } 133 if(displayLanguage()=="EN"){ 134 return '%H:%M'; 135 } 136 return '%H:%M'; 137}; 138var xlAlleNumbers=16; 139var xl925Numbers=3; 140var xl850Numbers=7; 141var xl700Numbers=4; 142var xlWbulbNumbers=3; 143 144var getWindSymbol = function(c) { 145 var img=''; 146 if (c>=120) { 147 img = 'sym_wind.svg'; 148 } 149 else if (c>=90) { 150 img = 'sym_wind.svg'; 151 } 152 else if (c>=70) { 153 img = 'sym_wind_red.svg'; 154 } 155 else if (c>=50) { 156 img = 'sym_wind_low.svg'; 157 } 158 return img; 159}; 160 161/** 162 * Haelt den Tooltip seitlich vom gehoverten Punkt frei. 163 * 164 * Der Tooltip haengt am oberen Rand der Zeichenflaeche und weicht dem Punkt 165 * horizontal aus: bevorzugt nach rechts, sonst nach links. Ist der Chart fuer 166 * beide Seiten zu schmal, wird die Seite mit mehr Platz genommen und der 167 * Tooltip an den Rand geschoben - dann bleibt wenigstens die Haelfte der 168 * Kurve frei. 169 * 170 * Freigehalten wird die Spanne zwischen Mauszeiger und gesnaptem Datenpunkt. 171 * Beide fallen nur bei dicht liegenden Punkten zusammen: bei Tagesdaten (z.B. 172 * 14-Tage-Trend) liegen sie bis zu einem halben Punktabstand auseinander, und 173 * ein Tooltip, der nur den Punkt beruecksichtigt, landet dann unter der Maus. 174 */ 175var TOOLTIP_POINT_GAP = 24; 176 177// Letzte bekannte Mausposition. Highcharts reicht das Maus-Event nicht an den 178// positioner durch, deshalb wird es hier passiv mitgeschrieben. 179var tooltipLastMouse = null; 180if (typeof document !== 'undefined' && document.addEventListener) { 181 document.addEventListener('mousemove', function (e) { 182 tooltipLastMouse = { x: e.clientX, y: e.clientY }; 183 }, true); 184} 185 186/** 187 * Scroll-Container der Zeichenflaeche. 188 * 189 * Bei `chart.scrollablePlotArea` (auf schmalen Screens immer aktiv) liegt das 190 * SVG in einem horizontal scrollbaren DIV, waehrend die Y-Achse in ein 191 * zusaetzliches, FESTES Overlay (`div.highcharts-fixed`) ausgelagert wird. 192 * Dieses Overlay liegt ueber dem gescrollten Inhalt - alles, was im 193 * gescrollten SVG links unter der Achsenspalte landet, verschwindet also 194 * dahinter. 195 * 196 * Highcharts hat den Container mehrfach umbenannt: 197 * < v11 chart.scrollingContainer 198 * >= v11 chart.scrollablePlotArea.scrollingContainer 199 * Da die Bibliothek vom CDN ohne feste Version geladen wird (siehe 200 * layouts/footer_javascript.php), werden beide Varianten geprueft. 201 */ 202var chartScrollingContainer = function (chart) { 203 if (!chart) { return null; } 204 if (chart.scrollingContainer) { return chart.scrollingContainer; } 205 if (chart.scrollablePlotArea && chart.scrollablePlotArea.scrollingContainer) { 206 return chart.scrollablePlotArea.scrollingContainer; 207 } 208 return null; 209}; 210 211var tooltipPositioner = function (labelWidth, labelHeight, point) { 212 const chart = this.chart; 213 const scroller = chartScrollingContainer(chart); 214 const offset = scroller ? scroller.scrollLeft : 0; 215 216 // Sichtbarer Ausschnitt: `chartWidth` ist die Breite des Sichtfensters, 217 // das SVG selbst ist um `scrollablePixelsX` breiter. 218 const scrollPx = chart.scrollablePixelsX || 0; 219 const viewWidth = chart.chartWidth; 220 221 // Punktposition im sichtbaren Ausschnitt (bei scrollbarer Zeichenflaeche 222 // ist das nicht die Position im SVG). 223 const pointX = point.plotX + chart.plotLeft - offset; 224 225 // Freizuhaltende Spanne: Punkt und - sofern bekannt - Mauszeiger. 226 let keepFrom = pointX; 227 let keepTo = pointX; 228 if (tooltipLastMouse) { 229 // Bezugsrahmen ist der Scroll-Container: dessen Rechteck entspricht 230 // dem Sichtfenster. Das Container-DIV des Charts waere um 231 // `scrollLeft` verschoben und wuerde die Maus falsch verorten. 232 const box = scroller || chart.container; 233 if (box) { 234 const rect = box.getBoundingClientRect(); 235 const mouseX = tooltipLastMouse.x - rect.left; 236 // Nur verwenden, wenn die Maus wirklich ueber diesem Chart steht. 237 if (mouseX >= 0 && mouseX <= viewWidth) {
238 keepFrom = Math.min(keepFrom, mouseX); 239 keepTo = Math.max(keepTo, mouseX); 240 } 241 } 242 } 243 244 // Bereich, in dem der Tooltip ungestoert liegen darf. Bei scrollbarer 245 // Zeichenflaeche verdeckt links die fixierte Achsenspalte und rechts die 246 // Abdeckmaske von Highcharts (beide im `div.highcharts-fixed`). 247 const safeLeft = scrollPx ? chart.plotLeft : 0; 248 const safeRight = scrollPx ? (chart.plotLeft + chart.plotWidth - scrollPx) : viewWidth; 249 250 const spaceRight = safeRight - keepTo - TOOLTIP_POINT_GAP; 251 const spaceLeft = keepFrom - safeLeft - TOOLTIP_POINT_GAP; 252 253 let x; 254 if (spaceRight >= labelWidth) { 255 x = keepTo + TOOLTIP_POINT_GAP; 256 } else if (spaceLeft >= labelWidth) { 257 x = keepFrom - labelWidth - TOOLTIP_POINT_GAP; 258 } else { 259 x = spaceRight >= spaceLeft ? safeRight - labelWidth : safeLeft; 260 } 261 262 // Nie in die fixierte Achsenspalte bzw. ueber den Chartrand hinaus. Passt 263 // der Tooltip nicht in den sicheren Bereich, gewinnt der linke Rand - 264 // rechts steht er dann hoechstens ueber dem schmalen Aussenrand. 265 x = Math.min(x, safeRight - labelWidth); 266 x = Math.max(safeLeft, x); 267 268 // Y: Der Tooltip haengt am oberen Rand der Zeichenflaeche. Herausragen 269 // kann er nicht: die Zeichenflaeche der XL-Charts ist praktisch immer 270 // horizontal scrollbar, und der Scroll-Container muss `overflow-y` dann 271 // zwingend auf auto/hidden halten - per CSS ist dagegen nichts zu machen. 272 // Deshalb wird er so weit nach oben geschoben, dass er hineinpasst. Damit 273 // er gar nicht erst zu hoch wird, setzt der Formatter die Modellliste ab 274 // vielen Modellen zweispaltig (siehe XL_TT_COLUMN_THRESHOLD). 275 let y = chart.plotTop; 276 if (scrollPx) { 277 y = Math.max(0, Math.min(y, chart.chartHeight - labelHeight)); 278 } 279 280 return { 281 x: x + offset, 282 y: y 283 }; 284}; 285 286 287var getMinWidth = function (days){ 288 var factor = 1; 289 var width = $(window).width(); 290 if(width <= 576) { 291 factor = 0.7; 292 } else if(width <= 768) { 293 factor = 0.8; 294 } else if(width <= 992) { 295 factor = 0.9; 296 } else if(width <= 1200) { 297 factor = 0.95; 298 } 299 300 if(typeof hccompact_xmax !== "undefined" && typeof hccompact_xmin !== "undefined") { 301 return ((hccompact_xmax - hccompact_xmin) / (60 * 60) / 1000 * 5) * factor; 302 } 303 304 if (typeof hcMinWidth !== "undefined") { 305 return hcMinWidth * factor; 306 } 307 308 return null; 309}; 310 311 312 313 314var tooltip14DaysTrend = { 315 crosshairs: true, 316 shared: true, 317 useHTML: true, 318 positioner: tooltipPositioner, 319 formatter: function() { 320 var s = []; 321 var counter=0; 322 var durchlauf=0; 323 var tmaxmin=''; 324 var windtext=''; 325 var counter=0; 326 var img = '', rain='',maxminv=''; 327 s.push('<div class="tt14d tt14d-overview">'); 328 var a=0; 329 $.each(this.points, function(i, p) { 330 a=this.series.data.indexOf( this.point ); 331 332 if (counter===0) { 333 //console.log(p); 334 s.push('<div class="tt14d-date">' + p.x + '<br><small>' + hc_data_14days_weekdays[a] + '</small></div>'); 335 s.push('<div class="tt14d-icons">'); 336 if (typeof hc_data_14days_ssym[a] !== 'undefined' && hc_data_14days_ssym[a]) { 337 s.push('<img src="/images/layout/icons/trend/cloudcoverage-'+hc_data_14days_ssym[a]+'.svg" alt="" class="tt14d-sun" /> '); 338 } 339 if (typeof hc_data_14days_rtype[a] !== 'undefined' && hc_data_14days_rtype[a] !== null && typeof hc_data_14days_rint[a] !== 'undefined' && hc_data_14days_rint[a]>0) { 340 s.push('<img src="/images/layout/icons/trend/precipitation-'+hc_data_14days_rtype[a]+hc_data_14days_rint[a]+'.svg" alt="" class="tt14d-rain" /> '); 341 } 342 if (typeof hc_data_14days_tsym[a] !== 'undefined' && hc_data_14days_tsym[a]>0) { 343 s.push('<img src="/images/layout/icons/trend/thunderstorm-'+hc_data_14days_tsym[a]+'.svg" alt="" class="tt14d-thun
343derstorm" /> '); 344 } 345 if (typeof hc_data_14days_gusts[a] !== 'undefined' 346 && typeof hc_data_14days_gusts_raw[a] !== 'undefined') { 347 var b =hc_data_14days_gusts[a]; 348 img = getWindSymbol(hc_data_14days_gusts_raw[a]); 349 if (img.length>0) { 350 if (displayFCUnitV() == 'kmh') { 351 b = Math.round(Math.ceil(b/5)*5); 352 } 353 else { 354 b = Math.round(b); 355 } 356 var einheit = $('#w-14days-data').attr('data-gunit'); 357 windtext = $('#w-14days-data').attr('data-gusts')+' '+b+(einheit === 'Bft' ? ' ':'')+einheit+'.'; 358 s.push('<img src="/images/symbole/'+img+'" alt="" class="tt14d-thunderstorm" /> '); 359 } 360 } 361 s.push('</div>'); 362 } 363 counter++; 364 }); 365 366 s.push('<div class="tt14d-overview-data">'); 367 counter=0; 368 var max_string='', min_string=''; 369 $.each(this.points, function(i, p) { 370 if (durchlauf === 0 || durchlauf === 1) { 371 var a=this.series.data.indexOf( this.point ); 372 $.each(hc_data_14days_maxmin, function(j,q) { 373 if (j === 0 || j === 1) { 374 if (typeof q.data !== 'undefined' && typeof q.data[a] !== 'undefined' && q.data[a] !== null) { 375 if (j === 0) { 376 max_string='<strong>'+Highcharts.numberFormat(q.data[a],0)+hccompact_units['temp']+'</strong>'; 377 } 378 else { 379 min_string='<strong>'+Highcharts.numberFormat(q.data[a],0)+hccompact_units['temp']+'</strong>'; 380 } 381 } 382 } 383 }); 384 } 385 var min_max=-999, min_min=1000; 386 if (p.point.low < min_min) { min_min=p.point.low; } 387 if (p.point.high < min_min) { min_min=p.point.high; } 388 if (p.point.low > min_max) { min_max=p.point.low; } 389 if (p.point.high > min_max) { min_max=p.point.high; } 390 if (min_max !== -999 && min_min !== 1000) { 391 if (i === 0) { 392 s.push('<div class="tt14d-row clearhigh">'+$('#w-14days-data').attr('data-max')+': '+max_string+'<br /><em>('+$('#w-14days-data').attr('data-bandbreite')+' '+$('#w-14days-data').attr('data-from')+' '+Highcharts.numberFormat(min_min,0) +hccompact_units['temp']+' '+$('#w-14days-data').attr('data-to')+' ' +Highcharts.numberFormat(min_max,0) +hccompact_units['temp']+ ')</em></div>'); 393 } 394 else if (i === 1) { 395 s.push('<div class="tt14d-row">'+$('#w-14days-data').attr('data-min')+': '+min_string+'<br /><em>('+$('#w-14days-data').attr('data-bandbreite')+' '+$('#w-14days-data').attr('data-from')+' '+Highcharts.numberFormat(min_min,0) +hccompact_units['temp']+' '+$('#w-14days-data').attr('data-to')+' ' +Highcharts.numberFormat(min_max,0) +hccompact_units['temp']+ ')</em></div>'); 396 } 397 } 398 counter++; 399 }); 400 s.push('</div>'); 401 s.push('<div class="tt14d-prob">'); 402 if (typeof hc_data_14days_word[a] !== 'undefined' && hc_data_14days_word[a].length>0) { 403 s.push(hc_data_14days_word[a]); 404 } 405 if (windtext.length>0) { 406 s.push(windtext); 407 } 408 s.push('</div>'); 409 s.push('</div>'); 410 return '<div class="highcharts-tooltip highcharts-tooltip-14">' + s.join(' ') + '</div>'; 411 } 412}; 413 414var tooltip14DaysTrendSun = { 415 crosshairs: true, 416 shared: true, 417 useHTML: true, 418 positioner: tooltipPositioner, 419 420 formatter: function() { 421 var s = []; 422 s.push('<div class="tt14d tt14d-sun">'); 423 var counter = 0; 424 var a=0; 425 $.each(this.points, function(i, p) { 426 a=this.series.data.indexOf( this.point ); 427 }); 428 429 if (typeof hc_data_14days_ssym[a] !== 'undefined' && hc_data_14days_ssym[a]) { 430 s.push('<div class="tt14d-sun-detail"><img src="/images/layout/icons/trend/cloudcoverage-'+hc_data_14days_ssym[a]+'.svg" alt="" /></div>'); 431 } 432 s.push('<div class="tt14d-date">'+this.x + '<br><small>' + hc_data_14days_weekdays[a] + '</small></div>'); 433 $.each(hc_data_14days_sun, function(j,q) { 434 if (j === 0) { 435 s.push('<div class="tt14d-sun-estimated">'); 436 if (typeof q.data !== 'undefined' && typeof q.data[a] !== 'undefined' && q.data[a] !== null) { 437 s.push($('#w-14days-data').attr('data-sunshineduration')+': <strong>'+Highcharts.numberFormat(q.data[a],1)+' '+$('#w-14days-data').attr('data-hours')+'</strong> '); 438 } 439 if(typeof hc_data_14days_sun_rel[a] !== 'undefined' && hc_data_14days_sun_rel[a] !== 'null') { 440 s.push('<div class="tt14d-astro">('+Highcharts.numberFormat(hc_data_14days_sun_rel[a],0)+'% '+$('#w-14days-data').attr('data-maxsunshine')+')</div>'); 441 } 442 s.push('</div>'); 443 } 444 }); 445 counter=0; 446 $.each(this.points, function(i, p) { 447 if (counter===0) { 448 s.push('<div class="clearfix"></div>'); 449 } 450 var min_max=-999, min_min=1000; 451 if (p.point.low < min_min) { min_min=p.point.low; } 452 if (p.point.high < min_min) { min_min=p.point.high; } 453 if (p.point.low > min_max) { min_max=p.point.low; } 454 if (p.point.high > min_max) { min_max=p.point.high; } 455 if (min_max !== -999 && min_min !== 1000) { 456 s.push('<div class="tt14d-sun-range">'+$('#w-14days-data').attr('data-epsrange')+' '+Highcharts.numberFormat(min_min,
4561) +' '+$('#w-14days-data').attr('data-to')+' ' +Highcharts.numberFormat(min_max,1) + ' '+$('#w-14days-data').attr('data-hours')+'</div>'); 457 } 458 counter++; 459 }); 460 s.push('</div>'); 461 return '<div class="highcharts-tooltip highcharts-tooltip-14">' + s.join(' ') + '</div>'; 462 } 463}; 464 465var tooltip14DaysTrendRain = { 466 crosshairs: true, 467 shared: true, 468 useHTML: true, 469 positioner: tooltipPositioner, 470 471 formatter: function() { 472 var s = []; 473 s.push('<div class="tt14d tt14d-rain">'); 474 var counter = 0; 475 var a=0; 476 $.each(this.points, function(i, p) { 477 a=this.series.data.indexOf( this.point ); 478 }); 479 480 if (typeof hc_data_14days_rtype[a] !== 'undefined' && hc_data_14days_rtype[a] !== null && typeof hc_data_14days_rint[a] !== 'undefined' && hc_data_14days_rint[a] !== 'null') { 481 s.push('<div class="tt14d-rain-detail">'); 482 if (typeof hc_data_14days_tsym[a] !== 'undefined' && hc_data_14days_tsym[a] !== 'null' && hc_data_14days_tsym[a]>0) { 483 s.push('<img src="/images/layout/icons/trend/thunderstorm-1.svg" alt="" />'); 484 } 485 s.push('<img src="/images/layout/icons/trend/precipitation-'+hc_data_14days_rtype[a]+hc_data_14days_rint[a]+'.svg" alt="" />'); 486 s.push('</div>'); 487 } 488 s.push('<div class="tt14d-date">'+this.x +'<br><small>' + hc_data_14days_weekdays[a] + '</small></div>'); 489 $.each(hc_data_14days_rain, function(j,q) { 490 if (j === 0) { 491 s.push('<div class="tt14d-rain-estimated">'); 492 if (typeof q.data !== 'undefined' && typeof q.data[a] !== 'undefined' && q.data[a] !== null) { 493 s.push($('#w-14days-data').attr('data-ptotal')+': <strong>'+Highcharts.numberFormat(q.data[a],1)+' '+hccompact_units['rain']+'</strong> '); 494 } 495 if(typeof hc_data_14days_prob[a] !== 'undefined' && hc_data_14days_prob[a] !== 'null') { 496 s.push('<div class="tt14d-rainprob">('+Highcharts.numberFormat(hc_data_14days_prob[a],0)+'% '+$('#w-14days-data').attr('data-pprob')+')</div>'); 497 } 498 s.push('</div>'); 499 } 500 }); 501 counter=0; 502 s.push('<div class="tt14d-rain-range">'); 503 $.each(this.points, function(i, p) { 504 if (counter===0) { 505 s.push('<div class="clearfix"></div>'); 506 } 507 var min_max=-999, min_min=1000; 508 if (p.point.low < min_min) { min_min=p.point.low; } 509 if (p.point.high < min_min) { min_min=p.point.high; } 510 if (p.point.low > min_max) { min_max=p.point.low; } 511 if (p.point.high > min_max) { min_max=p.point.high; } 512 if (min_max !== -999 && min_min !== 1000) { 513 s.push($('#w-14days-data').attr('data-epsrange')+' '+Highcharts.numberFormat(min_min,1) +' '+hccompact_units['rain']+' '+$('#w-14days-data').attr('data-to')+' ' +Highcharts.numberFormat(min_max,1) + ' '+hccompact_units['rain']+'.'); 514 } 515 counter++; 516 }); 517 518 s.push('</div>'); 519 s.push('</div>'); 520 return '<div class="highcharts-tooltip highcharts-tooltip-14">' + s.join(' ') + '</div>'; 521 } 522}; 523 524var tooltip14DaysTrendGusts = { 525 crosshairs: true, 526 shared: true, 527 useHTML: true, 528 positioner: tooltipPositioner, 529 530 formatter: function() { 531 var s = []; 532 s.push('<div class="tt14d tt14d-gusts">'); 533 var counter = 0; 534 var a=0; 535 $.each(this.points, function(i, p) { 536 a=this.series.data.indexOf( this.point ); 537 }); 538 539 if (typeof hc_data_14days_gusts_raw[a] !== 'undefined') { 540 img = getWindSymbol(hc_data_14days_gusts_raw[a]); 541 if (img.length>0) { 542 s.push('<div class="tt14d-gusts-detail"><img src="/images/symbole/'+img+'" alt="" class="tt14d-thunderstorm" /></div>'); 543 } 544 } 545 s.push('<div class="tt14d-date">'+this.x +'<br><small>' + hc_data_14days_weekdays[a] + '</small></div>'); 546 $.each(hc_data_14days_wind, function(j,q) { 547 if (j === 0) { 548 s.push('<div class="tt14d-gusts-estimated">'); 549 if (typeof q.data !== 'undefined' && typeof q.data[a] !== 'undefined' && q.data[a] !== null) {
550 s.push($('#w-14days-data').attr('data-estgusts')+': <strong>'+$('#w-14days-data').attr('data-upto')+' '+Highcharts.numberFormat(q.data[a],0)+' '+hccompact_units['wind']+'</strong> '); 551 } 552 s.push('<div class="tt14d-gusts-note">'+$('#w-14days-data').attr('data-gustnote')+'</div>'); 553 s.push('</div>'); 554 } 555 }); 556 counter=0; 557 $.each(this.points, function(i, p) { 558 if (counter===0) { 559 s.push('<div class="clearfix"></div>'); 560 } 561 var min_max=-999, min_min=1000; 562 if (p.point.low < min_min) { min_min=p.point.low; } 563 if (p.point.high < min_min) { min_min=p.point.high; } 564 if (p.point.low > min_max) { min_max=p.point.low; } 565 if (p.point.high > min_max) { min_max=p.point.high; } 566 if (min_max !== -999 && min_min !== 1000) { 567 s.push('<div class="tt14d-gusts-range">'+$('#w-14days-data').attr('data-epsrange')+' '+Highcharts.numberFormat(min_min,0) +' '+hccompact_units['wind']+' '+$('#w-14days-data').attr('data-to')+' ' +Highcharts.numberFormat(min_max,0) + ' '+hccompact_units['wind']+'</div>'); 568 } 569 counter++; 570 }); 571 s.push('</div>'); 572 return '<div class="highcharts-tooltip highcharts-tooltip-14">' + s.join(' ') + '</div>'; 573 } 574}; 575 576/* --------------------------------------------------------------------------- 577 * Hoehenbegrenzung der XL-Diagramme auf mobilen Viewports. 578 * 579 * Die Regeln unten arbeiten mit festen Pixelhoehen, die sich an der *Chart- 580 * breite* orientieren. Auf Telefonen fuehrt das dazu, dass ein Diagramm fast 581 * die gesamte Bildschirmhoehe einnimmt, ohne zusaetzliche Information zu 582 * liefern. Deshalb wird die Hoehe hier zusaetzlich an der Viewporthoehe 583 * gedeckelt: im Hochformat auf 40%, im Querformat auf 60%. 584 * Auf Desktopbreiten bleibt alles unveraendert. 585 * ------------------------------------------------------------------------ */ 586var XL_MOBILE_MAX_WIDTH = 767; // schmaler Viewport: Telefon im Hochformat 587var XL_MOBILE_MAX_HEIGHT = 500; // niedriger Viewport: Telefon im Querformat 588var XL_HEIGHT_PORTRAIT = 0.4; 589var XL_HEIGHT_LANDSCAPE = 0.6; 590var XL_MIN_CHART_HEIGHT = 220; // Untergrenze, damit die Achsen lesbar bleiben 591 592/* Liefert die erlaubte Maximalhoehe oder 0, wenn nicht begrenzt werden soll. 593 * 594 * Die Breite allein reicht zur Erkennung nicht aus: aktuelle Telefone sind im 595 * Querformat breiter als 767px (z.B. 844x390). Deshalb gilt ein Viewport auch 596 * dann als mobil, wenn er sehr niedrig ist. */ 597var xlMaxChartHeight = function () { 598 if (typeof window === 'undefined') { 599 return 0; 600 } 601 var vw = window.innerWidth || 0, 602 vh = window.innerHeight || 0; 603 if (!vw || !vh) { 604 return 0; 605 } 606 if (vw > XL_MOBILE_MAX_WIDTH && vh > XL_MOBILE_MAX_HEIGHT) { 607 return 0; // Desktop - unveraendert lassen. 608 } 609 var share = vh >= vw ? XL_HEIGHT_PORTRAIT : XL_HEIGHT_LANDSCAPE; 610 return Math.max(Math.round(vh * share), XL_MIN_CHART_HEIGHT); 611}; 612 613/* Deckelt eine Hoehe, vergroessert sie aber nie. */ 614var xlCapHeight = function (h) { 615 var max = xlMaxChartHeight(); 616 return max ? Math.min(h, max) : h; 617}; 618 619/* Zuletzt angewandte Layout-Lage. Bewusst *nicht* der Pixelwert: iOS aendert 620 * window.innerHeight beim Ein- und Ausblenden der Adressleiste waehrend des 621 * Scrollens. Ein Vergleich der Pixelhoehe wuerde dabei staendig alle Diagramme 622 * neu zeichnen. Nur ein echter Wechsel Hoch-/Querformat bzw. mobil/Desktop 623 * loest ein Neuzeichnen aus. */ 624var xlHeightCapState = null; 625var xlHeightCapTimer = null; 626 627var xlLayoutKey = function () { 628 if (typeof window === 'undefined') { 629 return 'd'; 630 } 631 var vw = window.innerWidth || 0, 632 vh = window.innerHeight || 0; 633 if (!vw || !vh || (vw > XL_MOBILE_MAX_WIDTH && vh > XL_MOBILE_MAX_HEIGHT)) { 634 return 'd'; 635 } 636 return vh >= vw ? 'm-portrait' : 'm-landscape'; 637}; 638 639var xlChartOptions = function (max_modelle) { 640 var height_xs,height_sm, height_md, height_lg; 641 height_xs=600; 642 height_sm=500; 643 height_md=470; 644 height_lg=450; 645 if (parseInt(max_modelle) <=4 ) { 646 height_xs=380; 647 height_sm=340; 648 height_md=360; 649 height_lg=350; 650 } 651 else if (parseInt(max_modelle) <=8 ) { 652 height_xs=420; 653 height_sm=370; 654 height_md=360; 655 height_lg=350; 656 } 657 else if (parseInt(max_modelle) >12 ) { 658 height_xs=610; 659 height_sm=610; 660 height_md=500; 661 height_lg=480; 662 } 663 // Lage merken, damit der Resize-Handler erkennt, ob sich etwas geaendert hat. 664 xlHeightCapState = xlLayoutKey(); 665 return { 666 // Kein Highcharts-Option, sondern eine Notiz fuer xlRefreshChartHeights(): 667 // damit laesst sich die Regelmenge nach einem Orientierungswechsel mit 668 // derselben Modellzahl neu aufbauen. 669 xlModels: max_modelle, 670 rules: [ 671 { 672 chartOptions: { 673 chart: {height: xlCapHeight(height_xs)}, 674 xAxis: {minorTickInterval: null}, 675 legend: {alignColumns: false} 676 }, 677 condition: {maxWidth: 337} 678 }, 679 { 680 chartOptions: { 681 chart: {height: xlCapHeight(height_sm)}, 682 xAxis: {minorTickInterval: null}, 683 legend: {alignColumns: false} 684 }, 685 condition: {minWidth: 338,maxWidth: 360} 686 }, 687 { 688 chartOptions: { 689 chart: {height: xlCapHeight(height_sm)}, 690 xAxis: {minorTickInterval: null}, 691 legend: {alignColumns: true} 692 }, 693 condition: {minWidth: 360,maxWidth: 488} 694 }, 695 696 { 697 chartOptions: { 698 chart: {height: xlCapHeight(height_md)}, 699 xAxis: {minorTickInterval: 6*36e5}, 700 legend: {alignColumns: true} 701 }, 702 condition: {minWidth: 489,maxWidth: 639} 703 }, 704 705 { 706 chartOptions: { 707 chart: {height: xlCapHeight(height_lg)} 708 }, 709 condition: {minWidth: 640} 710 } 711 712 ] 713 }; 714}; 715 716/* Die Hoehen oben werden beim Aufbau des Diagramms berechnet. Dreht der Nutzer 717 * das Geraet, aendert sich die Viewporthoehe - Highcharts kennt dann aber nur 718 * noch die fertigen Pixelwerte. Deshalb werden die Regeln neu erzeugt, sobald 719 * sich die erlaubte Maximalhoehe tatsaechlich aendert. */ 720var xlRefreshChartHeights = function () { 721 var next = xlLayoutKey(); 722 if (next === xlHeightCapState) { 723 return; // Gleiche Lage - kein teures Neuzeichnen noetig. 724 } 725 if (typeof Highcharts === 'undefined' || !Highcharts.charts) { 726 return; 727 }
728 Highcharts.charts.forEach(function (chart) { 729 if (!chart) { 730 return; // Zerstoerte Diagramme bleiben als undefined im Array. 731 } 732 // Je nach Highcharts-Version liegt die Notiz in userOptions oder in 733 // den gemergten options - beide Wege pruefen. 734 var models; 735 if (chart.userOptions && chart.userOptions.responsive) { 736 models = chart.userOptions.responsive.xlModels; 737 } 738 if (typeof models === 'undefined' && chart.options && chart.options.responsive) { 739 models = chart.options.responsive.xlModels; 740 } 741 if (typeof models === 'undefined') { 742 return; // Kein XL-Diagramm. 743 } 744 chart.update({responsive: xlChartOptions(models)}, true, false, false); 745 }); 746 xlHeightCapState = next; 747}; 748 749if (typeof window !== 'undefined' && window.addEventListener) { 750 ['resize', 'orientationchange'].forEach(function (evt) { 751 window.addEventListener(evt, function () { 752 clearTimeout(xlHeightCapTimer); 753 xlHeightCapTimer = setTimeout(xlRefreshChartHeights, 200); 754 }); 755 }); 756} 757 758var xlLegendWithFlag = { 759 enabled: false, 760}; 761 762var xlXAxisStandard = { 763 opposite:true, 764 type: 'datetime', 765 tickInterval: 24*36e5, 766 // Tagesgrenze: EINE dezente vertikale Linie - keine dominante dunkle Trennung. 767 gridLineWidth: 1, 768 lineWidth: 0, 769 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 770 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 771 majorGridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 772 gridZIndex: 1, 773 // Stundenraster entfaellt bewusst: es war das dominanteste Grid-Element. 774 minorTickInterval: null, 775 minorGridLineWidth: 0, 776 dateTimeLabelFormats: { 777 hour: getDynHourDateFormat(), 778 day: getDynDayDateFormat() 779 }, 780 labels: { 781 useHTML: true, 782 align: 'center', 783 formatter: function () { 784 var date_format = getDynDayShortDateFormat(this.value, this.chart.plotWidth); 785 return Highcharts.dateFormat(date_format, this.value); 786 }, 787 style: { 788 color: cssVar('--hc-xl-label', '#79838D'), 789 fontSize: '12px' 790 } 791 }, 792 tickLength: 0, 793 crosshair: false 794}; 795 796var xlYAxisStandard = function (lab, zeroline, allowD, minorTI, emphStep) { 797 var plotL = null; 798 if (typeof allowD === 'undefined') { allowD=false; } 799 if (typeof minorTI === 'undefined') { minorTI=1; } 800 if (typeof zeroline !== 'undefined') { 801 plotL = [{ 802 value: zeroline, 803 width: 1, 804 color: cssVar('--hc-xl-zeroline', '#C3CAD1'), 805 zIndex: 2 806 }]; 807 } 808 if (emphStep) { xlEnsureGridEmphasis(); } 809 return { 810 title: { 811 text: false 812 }, 813 labels: { 814 format: lab, 815 style: { 816 color: cssVar('--hc-xl-label', '#79838D'), 817 fontSize: '12px' 818 } 819 }, 820 plotLines: plotL, 821 allowDecimals: allowD, 822 // Betonte Gitterlinien alle `emphStep` Einheiten (siehe 823 // xlApplyGridEmphasis) - ohne Wert bleibt das Raster gleichmaessig. 824 xlEmphasizeStep: emphStep || null, 825 // Nur noch Hauptlinien - Zwischenlinien waren reines Rauschen. 826 minorTickInterval: null, 827 minorGridLineWidth: 0, 828 gridLineWidth: 1, 829 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 830 majorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 831 lineWidth: 0, 832 tickPixelInterval: 42, 833 // Damit die Kurven nicht am Panelrand kleben. 834 minPadding: 0.08, 835 maxPadding: 0.08 836 }; 837}; 838/** 839 * Temperaturachse: wie die Standardachse, zusaetzlich werden die 10er-Linien 840 * (-10, 0, 10, 20 ...) kraeftiger gezeichnet. Betont wird immer der 841 * angezeigte Wert, in °F also 0/10/20 °F usw. 842 */ 843var XL_TEMP_GRID_STEP = 10; 844var xlYAxisTemp = function (lab, zeroline) { 845 return xlYAxisStandard(lab, zeroline, false, 1, XL_TEMP_GRID_STEP); 846}; 847 848var xlYAxisStandardFormatter = function (lab, zeroline, allowD, minorTI) { 849 var plotL = null; 850 if (typeof allowD === 'undefined') { allowD=false; } 851 if (typeof minorTI === 'undefined') { minorTI=1; } 852 if (typeof zeroline !== 'undefined') { 853 plotL = [{ 854 value: zeroline, 855 width: 1, 856 color: cssVar('--hc-xl-zeroline', '#C3CAD1'), 857 zIndex: 2 858 }]; 859 } 860 return { 861 title: { 862 text: false 863 }, 864 labels: { 865 formatter: lab, 866 style: { 867 color: cssVar('--hc-xl-label', '#79838D'), 868 fontSize: '12px' 869 } 870 }, 871 plotLines: plotL, 872 allowDecimals: allowD, 873 minorTickInterval: null, 874 minorGridLineWidth: 0, 875 gridLineWidth: 1, 876 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 877 majorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 878 lineWidth: 0, 879 tickPixelInterval: 42, 880 minPadding: 0.08, 881 maxPadding: 0.08 882 }; 883}; 884 885/* --------------------------------------------------------------------------- 886 * Betonte Gitterlinien (10er-Schritte) 887 * --------------------------------------------------------------------------- 888 * In den Temperatur-Charts sollen die "runden" Linien (-10, 0, 10, 20 ...) 889 * kraeftiger sein als das uebrige Raster - sie dienen als Orientierungsanker. 890 * 891 * Highcharts kann die Strichstaerke nicht je Tick konfigurieren, deshalb 892 * werden die bereits gezeichneten Gitterlinien im `render`-Event nachtraeglich 893 * ueberschrieben. Das ist bewusst KEIN Satz zusaetzlicher plotLines: 894 * plotLines lassen sich nicht automatisch an die jeweils sichtbare Skala 895 * anpassen und wuerden bei jedem Redraw neu erzeugt werden muessen. 896 * 897 * Aktiviert wird das ueber die Achsenoption `xlEmphasizeStep` (siehe 898 * `xlYAxisStandard`). Die Betonung bezieht sich immer auf die ANGEZEIGTEN 899 * Werte, funktioniert also in °C, °F und K gleichermassen. 900 * ------------------------------------------------------------------------- */ 901var XL_GRID_EMPHASIS_WIDTH = 2; 902var xlGridEmphasisBound = false;
903 904var xlApplyGridEmphasis = function (axis) { 905 var step = axis && axis.options && axis.options.xlEmphasizeStep; 906 if (!step || !axis.ticks) { return; } 907 908 // Fallback bewusst modusabhaengig: solange `--hc-xl-grid-strong` noch 909 // nicht im kompilierten CSS steht, passt die Farbe trotzdem zum Theme. 910 var strongColor = cssVar('--hc-xl-grid-strong', xlIsDark() ? '#363B41' : '#DCE2E8'); 911 var normalColor = cssVar('--hc-xl-grid', '#EEF1F4'); 912 913 Object.keys(axis.ticks).forEach(function (key) { 914 var tick = axis.ticks[key]; 915 if (!tick || !tick.gridLine) { return; } 916 917 var value = parseFloat(key); 918 // Rundung gegen Fliesskomma-Reste (z.B. 10.000000000000002) 919 var strong = isFinite(value) && Math.abs(Math.round(value / step) * step - value) < 1e-6; 920 921 tick.gridLine.attr({ 922 'stroke-width': strong ? XL_GRID_EMPHASIS_WIDTH : 1, 923 stroke: strong ? strongColor : normalColor 924 }); 925 }); 926}; 927 928/** 929 * Registriert den globalen `render`-Hook genau einmal. Achsen ohne 930 * `xlEmphasizeStep` werden dabei nicht angefasst. 931 */ 932var xlEnsureGridEmphasis = function () { 933 if (xlGridEmphasisBound || typeof Highcharts === 'undefined') { return; } 934 xlGridEmphasisBound = true; 935 Highcharts.addEvent(Highcharts.Chart, 'render', function () { 936 (this.yAxis || []).forEach(xlApplyGridEmphasis); 937 }); 938}; 939 940var xlPlotOptions = function(ContainerId) { 941 return { 942 series: { 943 events: { 944 legendItemClick: function() { 945 chartContainerId = $('#'+ContainerId).children().attr('id'); 946 $( '#'+chartContainerId+'.toggle-flags' ).tooltip('destroy'); 947 $( '#'+chartContainerId+'.toggle-flags' ).tooltip({ 948 content: function() { 949 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 950 } 951 }); 952 }, 953 }, 954 }, 955 column: { 956 borderColor: cssVar('--hc-bar-stroke-color'), 957 } 958 }; 959}; 960 961/* ============================================================================ 962 * XL-Multimodell: visuelle Hierarchie (Median / Unsicherheitsband / Modelle) 963 * ============================================================================ 964 * HAUPTINFORMATION -> Median 965 * KONTEXT -> Unsicherheitsband (10.-90. Perzentil) 966 * DETAILINFORMATION -> die einzelnen Modelllaeufe 967 * 968 * Die Aggregate werden AUSSCHLIESSLICH aus den bereits vorhandenen 969 * Modellserien berechnet - keine zusaetzlichen Requests, keine Aenderung an 970 * den Originaldaten. Die Aggregatserien tragen bewusst KEIN `param`, damit 971 * die Modellauswahl-Legende (xlSelection) sie niemals anfasst; erkannt 972 * werden sie ueber `xlRole`. 973 * ------------------------------------------------------------------------- */ 974 975/** Ab dieser Anzahl sichtbarer Modelle sind Median/Band statistisch sinnvoll. */ 976var XL_MIN_MODELS_FOR_STATS = 3; 977 978/** 979 * Unsicherheitsband (10.-90. Perzentil) global ein-/ausschalten. 980 * TEMPORAER auf false - auf false bleibt die gesamte Band-Logik erhalten, 981 * es wird lediglich keine Flaeche erzeugt. Zum Reaktivieren: true. 982 */ 983var XL_SHOW_BAND = false; 984 985/** 986 * Zeitschritt-Punkte auf den Modelllinien. 987 * ------------------------------------------------------------------------ 988 * Die Modelle liefern unterschiedlich feine Zeitschritte (1h/3h/6h). Ein 989 * kleiner Punkt je Stuetzstelle macht das direkt im Chart sichtbar. 990 * 991 * 'auto' Highcharts blendet die Punkte selbst aus, sobald sie zu dicht 992 * stehen (< XL_STEP_MARKER_RADIUS * enabledThreshold Pixel). 993 * Folge: grobe Modelle zeigen Punkte, 1h-Modelle bleiben glatt - 994 * und beim Zoomen tauchen sie dort ebenfalls auf. 995 * 'always' Punkte immer zeichnen (kann bei 1h-Schritten dicht wirken). 996 * 'off' Bisheriges Verhalten ohne Punkte. 997 */ 998var XL_STEP_MARKER_MODE = 'off'; 999var XL_STEP_MARKER_RADIUS = 2.2; 1000/** Mindestabstand zweier Punkte in Vielfachen des Radius (nur bei 'auto'). */ 1001var XL_STEP_MARKER_THRESHOLD = 2.5; 1002 1003var xlColor = function (name, fallback) { 1004 var v = cssVar(name); 1005 return (v && v.length) ? v : fallback; 1006}; 1007 1008/** 1009 * Darkmode-Erkennung fuer die Chartfarben. 1010 * 1011 * Gleiche Quelle wie `cssVar` (body.dark), damit Serienfarben und 1012 * CSS-Variablen nie auseinanderlaufen. Der Wert wird bewusst bei jedem 1013 * Aufruf frisch gelesen statt gecacht - beim Umschalten laedt die Seite 1014 * zwar neu (siehe applyMode in function.js), aber so bleibt die Funktion 1015 * auch ohne Reload korrekt. 1016 */ 1017var xlIsDark = function () { 1018 return !!(document.body && document.body.classList.contains('dark')); 1019}; 1020 1021/** 1022 * Farbe mit Alpha versehen. 1023 * Highcharts ignoriert `fillOpacity`, sobald ein explizites `fillColor` 1024 * gesetzt ist - die Transparenz muss deshalb in der Farbe selbst stecken. 1025 */ 1026var xlAlpha = function (color, alpha) { 1027 if (typeof Highcharts !== 'undefined' && Highcharts.color) { 1028 var rgba = Highcharts.color(color).setOpacity(alpha).get('rgba'); 1029 if (rgba && rgba.indexOf('rgba') === 0) { return rgba; } 1030 } 1031 var m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(String(color).trim()); 1032 if (m) { 1033 return 'rgba(' + parseInt(m[1], 16) + ',' + parseInt(m[2], 16) + ',' + 1034 parseInt(m[3], 16) + ',' + alpha + ')'; 1035 } 1036 return color; 1037}; 1038 1039/** Beschriftungen der Aggregatebenen (Server liefert sie via xlLegendI18n). */ 1040var xlStatsFallback = { 1041 median: 'Median', 1042 band: '10â90 % Perzentil', 1043 bandhint: 'Unsicherheitsbereich', 1044 models: 'Einzelne Modelle', 1045 range: 'Spannweite', 1046 count: 'Modelle' 1047}; 1048 1049var xlStatsT = function (key) { 1050 var i18n = (typeof xlLegendI18n !== 'undefined' && xlLegendI18n) ? xlLegendI18n : {}; 1051 var stats = i18n.stats || {}; 1052 return stats[key] || xlStatsFallback[key] || key; 1053}; 1054 1055/** Quantil mit linearer Interpolation auf einem aufsteigend sortierten Array. */ 1056var xlQuantile = function (sorted, q) { 1057 var n = sorted.length; 1058 if (!n) { return null; } 1059 if (n === 1) { return sorted[0]; } 1060 var pos = (n - 1) * q; 1061 var lo = Math.floor(pos); 1062 var hi = Math.ceil(pos); 1063 if (lo === hi) { return sorted[lo]; } 1064 return sorted[lo] + (sorted[hi] - sorted[lo]) * (pos - lo); 1065}; 1066 1067/** Rohpunkte einer Serie/eines Serien-Optionsobjekts ([[x,y], ...]). */ 1068var xlRawPoints = function (s) { 1069 var o = (s && (s.userOptions || s.options || s)) || {}; 1070 return Array.isArray(o.data) ? o.data : []; 1071}; 1072 1073var xlSeriesRole = function (s) { 1074 var o = (s && (s.userOptions || s.options || s)) || {}; 1075 return o.xlRole || null; 1076}; 1077 1078/** 1079 * Median + Perzentilband ueber eine Liste von Modellserien. 1080 * Nur Zeitpunkte mit mindestens XL_MIN_MODELS_FOR_STATS Werten werden 1081 * beruecksichtigt - dadurch laufen die Aggregate am Rand nicht ins Leere und 1082 * es entstehen keine Linien ueber den letzten belastbaren Datenpunkt hinaus. 1083 */ 1084var xlComputeAggregates = function (modelSeries, monotone) { 1085 var buckets = {}; 1086 var haveAny = false;
1087 1088 (modelSeries || []).forEach(function (s) { 1089 xlRawPoints(s).forEach(function (p) { 1090 if (!p) { return; } 1091 var x = Array.isArray(p) ? p[0] : p.x; 1092 var y = Array.isArray(p) ? p[1] : p.y; 1093 if (x === null || x === undefined) { return; } 1094 if (y === null || y === undefined || typeof y !== 'number' || !isFinite(y)) { return; } 1095 if (!buckets[x]) { buckets[x] = []; } 1096 buckets[x].push(y); 1097 haveAny = true; 1098 }); 1099 }); 1100 1101 if (!haveAny) { return { median: [], band: [], count: 0 }; } 1102 1103 var xs = Object.keys(buckets).map(Number).sort(function (a, b) { return a - b; }); 1104 var median = []; 1105 var band = []; 1106 var maxCount = 0; 1107 1108 xs.forEach(function (x) { 1109 var vals = buckets[x]; 1110 if (vals.length > maxCount) { maxCount = vals.length; } 1111 if (vals.length < XL_MIN_MODELS_FOR_STATS) { return; } 1112 vals.sort(function (a, b) { return a - b; }); 1113 median.push([x, xlQuantile(vals, 0.5)]); 1114 band.push([x, xlQuantile(vals, 0.1), xlQuantile(vals, 0.9)]); 1115 }); 1116 1117 // Bei kumulativen Groessen (Niederschlagssumme) kann der punktweise Median 1118 // zurueckspringen, sobald ein Modell endet und sich die beitragende 1119 // Modellmenge aendert. Das ist ein Artefakt der Aggregation, nicht der 1120 // Daten - die abgeleitete Linie wird deshalb monoton gehalten. 1121 if (monotone) { 1122 var runMed = -Infinity; 1123 median.forEach(function (p) { 1124 if (p[1] < runMed) { p[1] = runMed; } else { runMed = p[1]; } 1125 }); 1126 var runLo = -Infinity, runHi = -Infinity; 1127 band.forEach(function (p) { 1128 if (p[1] < runLo) { p[1] = runLo; } else { runLo = p[1]; } 1129 if (p[2] < runHi) { p[2] = runHi; } else { runHi = p[2]; } 1130 }); 1131 } 1132 1133 return { median: median, band: band, count: maxCount }; 1134}; 1135 1136/** 1137 * Baut die Serienliste eines XL-Charts um: Modelle optisch zuruecknehmen und 1138 * Band + Median als zusaetzliche Ebenen davorlegen. 1139 * 1140 * Die uebergebenen Objekte werden NICHT mutiert - die Originalserien aus dem 1141 * PHP-Template bleiben unveraendert erhalten. 1142 * 1143 * opts: 1144 * smooth Spline statt Polyline (NICHT fuer kumulative Groessen!) 1145 * stats Median/Band erzeugen (default true) 1146 * band Unsicherheitsband erzeugen (default = stats) 1147 * column Saeulendarstellung (Niederschlag) 1148 * monotone Aggregate monoton steigend halten (kumulative Groessen) 1149 * medianColor Farbe der zentralen Linie/Saeule 1150 * bandColor Farbe der Unsicherheitsflaeche (default: --hc-xl-band) 1151 */ 1152/** 1153 * Markerdefinition fuer eine Modelllinie: kleiner Punkt je Zeitschritt. 1154 * Bei 'auto' bleibt `enabled` bewusst UNGESETZT - nur dann wertet Highcharts 1155 * `enabledThreshold` aus und blendet zu dicht stehende Punkte selbst aus. 1156 */ 1157var xlStepMarker = function (base, color) { 1158 var m = $.extend({}, base, { 1159 symbol: 'circle', 1160 radius: XL_STEP_MARKER_RADIUS, 1161 lineWidth: 0, 1162 fillColor: color, 1163 states: { hover: { enabled: true, radius: XL_STEP_MARKER_RADIUS + 1.8, lineWidth: 0 } } 1164 }); 1165 1166 if (XL_STEP_MARKER_MODE === 'always') { 1167 m.enabled = true; 1168 } else if (XL_STEP_MARKER_MODE === 'auto') { 1169 delete m.enabled; 1170 m.enabledThreshold = XL_STEP_MARKER_THRESHOLD; 1171 } else { 1172 m.enabled = false; 1173 } 1174 1175 return m; 1176}; 1177 1178var xlSeries = function (raw, opts) { 1179 if (!Array.isArray(raw)) { return raw; } 1180 opts = opts || {}; 1181 1182 var wantStats = opts.stats !== false; 1183 var wantBand = XL_SHOW_BAND && 1184 ((opts.band !== undefined) ? opts.band : (wantStats && !opts.column)); 1185 var medianColor = opts.medianColor || xlColor('--hc-xl-median', '#1a3852'); 1186 var bandColor = opts.bandColor || xlColor('--hc-xl-band', '#007dfe'); 1187 var lineType = opts.column ? 'column' : (opts.smooth ? 'spline' : 'line'); 1188 1189 var models = raw.map(function (s) { 1190 // Bewusst FLACHE Kopie: `data` wird nie mutiert und muss deshalb nicht 1191 // geklont werden (bei ~15 Serien x ~200 Punkten waere das teuer). 1192 var copy = $.extend({}, s); 1193 copy.type = copy.type || lineType; 1194 // Darkmode: aufgehellte Variante derselben Modellfarbe. Die Rampen 1195 // sind serverseitig in `model_color_dark` hinterlegt, damit die 1196 // Abstufung innerhalb einer Gruppe erhalten bleibt. 1197 if (xlIsDark() && copy.colorDark) { copy.color = copy.colorDark; } 1198 if (opts.column) { 1199 copy.borderWidth = 0; 1200 copy.pointPadding = 0.02; 1201 copy.groupPadding = 0.12; 1202 // Balken in voller Farbe: anders als bei den Linien-Charts gibt es 1203 // hier keine Medianebene, die sich davor schieben muesste. 1204 // Ohne das rendert Highcharts fuer jeden 0-Wert einen sichtbaren 1205 // 1px-Strich - bei Niederschlag waere das ein Meer aus Mini-Balken. 1206 copy.minPointLength = 0; 1207 } else { 1208 // Deutlich schwaecher als die Medianlinie (3px, volle Deckung), 1209 // aber kraeftig genug, um einzelne Modelle nachverfolgen zu koennen. 1210 copy.lineWidth = 2; 1211 copy.opacity = 0.65; 1212 } 1213 // Saeulen (Niederschlag) zeigen ihre Zeitschritte schon durch die 1214 // Balkenbreite - dort bleiben die Marker aus.
1215 copy.marker = opts.column 1216 ? $.extend({}, s.marker, { enabled: false, symbol: 'circle' }) 1217 : xlStepMarker(s.marker, copy.color); 1218 copy.states = $.extend(true, {}, s.states, { 1219 hover: { lineWidthPlus: 1, halo: false }, 1220 inactive: { opacity: 0.12 } 1221 }); 1222 copy.zIndex = (typeof copy.zIndex === 'number') ? copy.zIndex : 3; 1223 return copy; 1224 }); 1225 1226 if (!wantStats) { return models; } 1227 1228 // Initialer Aufbau: nur die serverseitig aktiven Modelle zaehlen. 1229 var active = models.filter(function (s) { return s.visible !== false; }); 1230 var agg = xlComputeAggregates(active, opts.monotone); 1231 var out = []; 1232 1233 if (wantBand && agg.band.length) { 1234 out.push({ 1235 xlRole: 'band', 1236 xlMonotone: !!opts.monotone, 1237 type: 'arearange', 1238 name: xlStatsT('band'), 1239 data: agg.band, 1240 color: xlAlpha(bandColor, 0.3), 1241 // Alpha steckt bewusst in der Farbe selbst - `fillOpacity` wird 1242 // von Highcharts ignoriert, sobald `fillColor` gesetzt ist. 1243 fillColor: xlAlpha(bandColor, 0.3), 1244 lineWidth: 0, 1245 zIndex: 20, 1246 marker: { enabled: false }, 1247 enableMouseTracking: false, 1248 states: { inactive: { opacity: 1 }, hover: { enabled: false } }, 1249 showInLegend: false 1250 }); 1251 } 1252 1253 if (agg.median.length) { 1254 out.push({ 1255 xlRole: 'median', 1256 xlMonotone: !!opts.monotone, 1257 type: opts.column ? 'column' : (opts.smooth ? 'spline' : 'line'), 1258 name: xlStatsT('median'), 1259 data: agg.median, 1260 color: medianColor, 1261 lineWidth: opts.column ? undefined : 3, 1262 zIndex: 60, 1263 grouping: opts.column ? false : undefined, 1264 pointPadding: opts.column ? 0.36 : undefined, 1265 borderWidth: opts.column ? 0 : undefined, 1266 marker: { enabled: false, symbol: 'circle', states: { hover: { enabled: true, radius: 4 } } }, 1267 states: { inactive: { opacity: 1 }, hover: { lineWidthPlus: 0, halo: false } }, 1268 showInLegend: false 1269 }); 1270 } 1271 1272 return out.concat(models); 1273}; 1274 1275/** 1276 * Ensemble-Charts auf die XL-Linienoptik bringen. 1277 * ------------------------------------------------------------------------ 1278 * Uebernimmt aus `xlSeries` genau die Linienaesthetik - NICHT die Aggregate: 1279 * Ensembles bringen Main/Mean/Range/Perzentile bereits serverseitig mit. 1280 * 1281 * - Marker konsequent aus (bei 50 Membern sonst ein Punktteppich) 1282 * - Hover verbreitert um 1px, ohne Halo 1283 * - nicht gehoverte Member werden abgedunkelt (wie in XL) 1284 * - Member leicht transparent, damit die Buendelung lesbar bleibt 1285 * - Leitlinien (Main/Mean) in voller Deckung und kraeftiger 1286 * 1287 * Daten, Farben, Reihenfolge, zIndex und Serien-Namen bleiben unangetastet - 1288 * der Tooltip erkennt die Leitserien weiterhin ueber `name`. 1289 */ 1290var XL_ENS_LEAD_SERIES = ['Main', 'Mean']; 1291 1292var xlEnsembleSeries = function (raw) { 1293 if (!Array.isArray(raw)) { return raw; } 1294 1295 return raw.map(function (s) { 1296 // Flache Kopie: `data` wird nie mutiert. 1297 var copy = $.extend({}, s); 1298 1299 // Flaechen (Range/Perzentile) sind Kontext, keine Linien - die 1300 // bekommen nur das Dimmen abgewoehnt, damit sie beim Hover stehen 1301 // bleiben. 1302 if (copy.type === 'arearange' || copy.type === 'areasplinerange') { 1303 copy.states = $.extend(true, {}, s.states, { 1304 inactive: { opacity: 1 }, 1305 hover: { enabled: false } 1306 }); 1307 return copy; 1308 } 1309 1310 var lead = XL_ENS_LEAD_SERIES.indexOf(copy.name) !== -1; 1311 1312 copy.marker = $.extend({}, s.marker, { enabled: false }); 1313 // Bewusst KEIN Wechsel auf 'spline': die Ensemble-Member sollen genau 1314 // die gelieferten Stuetzstellen zeigen, nicht eine interpolierte Kurve. 1315 copy.lineWidth = lead ? 3 : 1.5; 1316 copy.opacity = lead ? 1 : 0.6; 1317 copy.states = $.extend(true, {}, s.states, { 1318 hover: { lineWidthPlus: 1, halo: false }, 1319 inactive: { opacity: lead ? 1 : 0.12 } 1320 }); 1321 1322 return copy; 1323 }); 1324}; 1325 1326/** 1327 * Zieht Median/Band eines bestehenden Charts auf die aktuell SICHTBAREN 1328 * Modelle nach (nach einem Klick in der Modellauswahl). 1329 * Gibt true zurueck, wenn sich tatsaechlich etwas geaendert hat. 1330 */ 1331var xlRefreshAggregates = function (chart) { 1332 if (!chart || !chart.series) { return false; } 1333 1334 var aggregates = chart.series.filter(function (s) { return xlSeriesRole(s); }); 1335 if (!aggregates.length) { return false; } 1336 1337 var visibleModels = chart.series.filter(function (s) { 1338 return xlSeriesParam(s) && s.visible; 1339 }); 1340 1341 // Neuberechnung nur, wenn sich die Menge der sichtbaren Modelle geaen
1341dert 1342 // hat - sonst wuerde jeder Tabwechsel ein volles Redraw ausloesen. 1343 var key = visibleModels.map(xlSeriesParam).sort().join('|'); 1344 if (chart.xlAggKey === key) { return false; } 1345 chart.xlAggKey = key; 1346 1347 var enough = visibleModels.length >= XL_MIN_MODELS_FOR_STATS; 1348 var monotone = aggregates.some(function (s) { return s.options.xlMonotone; }); 1349 var agg = enough ? xlComputeAggregates(visibleModels, monotone) : { median: [], band: [], count: 0 }; 1350 1351 aggregates.forEach(function (s) { 1352 var role = xlSeriesRole(s); 1353 var next = (role === 'band') ? agg.band : agg.median; 1354 // redraw=false - der Aufrufer redrawt gesammelt. 1355 s.setData(next, false, false, false); 1356 if (s.visible !== (next.length > 0)) { 1357 s.setVisible(next.length > 0, false); 1358 } 1359 }); 1360 1361 return true; 1362}; 1363 1364/** 1365 * Gemeinsamer XL-Tooltip: zuerst die zentrale Medianinformation, darunter die 1366 * Modellwerte. Dadurch traegt der Tooltip die Detailinformation, die in der 1367 * Grafik bewusst zurueckgenommen ist. 1368 * 1369 * opts.rangeHours Zeitraum-Kopf ("Von ... bis ...") statt einzelnem Zeitpunkt 1370 */ 1371/** 1372 * Ab wie vielen Modellen die Tooltip-Liste zweispaltig wird. Bei rund 24 1373 * sichtbaren Modellen waere eine einspaltige Liste hoeher als der Chart. 1374 */ 1375var XL_TT_COLUMN_THRESHOLD = 10; 1376 1377/** Rand, den der Tooltip im sichtbaren Ausschnitt frei laesst (Rahmen/Padding). */ 1378var XL_TT_WIDTH_RESERVE = 24; 1379 1380/** Unterhalb dieser sichtbaren Breite wird die Modelltabelle kleiner gesetzt. */ 1381var XL_TT_NARROW_WIDTH = 360; 1382 1383/** Untergrenze, damit der Tooltip nie absurd schmal berechnet wird. */ 1384var XL_TT_MIN_WIDTH = 200; 1385 1386/** 1387 * Zweispaltige Tooltips gibt es nur auf schmalen Geraeten. Auf dem Desktop 1388 * ist genug Hoehe vorhanden, dort bleibt die Liste immer einspaltig. 1389 */ 1390var xlTooltipColumns = function (count) { 1391 if (count <= XL_TT_COLUMN_THRESHOLD) { return 1; } 1392 if (typeof window === 'undefined') { return 1; } 1393 return (window.innerWidth || 0) <= XL_MOBILE_MAX_WIDTH ? 2 : 1; 1394}; 1395 1396/** 1397 * Bricht eine per <br> aufgebaute Modellliste auf schmalen Geraeten in zwei 1398 * Spalten, sobald sie zu viele Zeilen hat. Die Tooltips werden bei 24 1399 * sichtbaren Modellen sonst hoeher als der Chart. Auf dem Desktop ist genug 1400 * Hoehe vorhanden, dort bleibt die Liste unveraendert einspaltig. 1401 * 1402 * Inhalt, Reihenfolge und Werte bleiben unveraendert - es wird ausschliesslich 1403 * umgebrochen. Gefuellt wird spaltenweise, damit die Liste weiter von oben 1404 * nach unten gelesen werden kann. Die Breite wird auf den sichtbaren 1405 * Ausschnitt begrenzt, damit nichts hinter der Achsenmaske verschwindet. 1406 * 1407 * @param html Der vom Formatter gebaute Inhalt (Kopfzeile, dann <br>-Liste) 1408 * @param ctx Der Formatter-Kontext (`this`), fuer die Chartbreite 1409 * @param reserve Zusaetzlich freizuhaltende Breite, z.B. fuer das Wettersymbol 1410 */ 1411var ttCols = function (html, ctx, reserve) { 1412 var parts = String(html).split(/<br\s*\/?>/i); 1413 if (xlTooltipColumns(parts.length - 1) < 2) { return html; } 1414 1415 var head = parts.shift(); 1416 var n = parts.length; 1417 var perCol = Math.ceil(n / 2); 1418 1419 var availW = 0; 1420 var chart = (ctx && ctx.points && ctx.points.length) ? ctx.points[0].series.chart : null; 1421 if (chart) { 1422 availW = Math.max(XL_TT_MIN_WIDTH, 1423 chart.chartWidth - chart.plotLeft - XL_TT_WIDTH_RESERVE - (reserve || 0)); 1424 } 1425 1426 // `width: max-content` verhindert, dass der Browser den Tooltip auf die 1427 // schmalste moegliche Breite zusammenzieht und jede Zeile umbricht. 1428 var style = availW ? ';width:max-content;max-width:' + Math.round(availW) + 'px' : ''; 1429 // Die Spaltendarstellung wird zusaetzlich inline gesetzt, damit sie auch 1430 // ohne frisch ausgeliefertes CSS greift. 1431 var out = head + '<div class="tt-cols" style="display:flex;gap:14px;white-space:normal' + style + '">'; 1432 for (var c = 0; c < 2; c++) { 1433 out += '<div class="tt-col" style="flex:1 1 0;min-width:0">'; 1434 for (var i = c * perCol; i < Math.min(n, (c + 1) * perCol); i++) { 1435 out += '<div class="tt-row" style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis">' + 1436 parts[i] + '</div>'; 1437 } 1438 out += '</div>'; 1439 } 1440 return out + '</div>'; 1441}; 1442 1443var xlTooltip = function (unit, digits, opts) { 1444 opts = opts || {}; 1445 if (typeof digits !== 'number') { digits = 1; } 1446 1447 return { 1448 xlDigits: digits, 1449 crosshairs: { 1450 width: 1, 1451 color: xlColor('--hc-xl-crosshair', 'rgba(120,130,140,.35)'), 1452 zIndex: 2 1453 }, 1454 shared: true, 1455 valueSuffix: ' ' + unit,
1456 shape: 'square', 1457 useHTML: true, 1458 // Der Tooltip bleibt IM Chart (`outside: false`). Ein Versuch mit 1459 // `outside: true` positionierte in dieser Highcharts-Version 1460 // unzuverlaessig - der Tooltip landete weit ausserhalb des Charts. 1461 // Das Hoehenproblem wird stattdessen an der Wurzel geloest: ab 1462 // XL_TT_COLUMN_THRESHOLD Modellen wird die Liste zweispaltig, der 1463 // Tooltip also nur noch halb so hoch. 1464 outside: false, 1465 backgroundColor: xlColor('--hc-xl-tooltip-bg', 'rgba(255,255,255,.97)'), 1466 borderColor: xlColor('--hc-xl-tooltip-border', '#d8dee4'), 1467 borderRadius: 6, 1468 borderWidth: 1, 1469 shadow: false, 1470 style: { 1471 zIndex: 10000, 1472 pointerEvents: 'auto', 1473 color: cssVar('--color-text') 1474 }, 1475 positioner: tooltipPositioner, 1476 formatter: function () { 1477 var fmt = function (v) { 1478 return Highcharts.numberFormat(v, digits); 1479 }; 1480 1481 var head; 1482 if (opts.rangeHours) { 1483 var ms = opts.rangeHours * 3600 * 1000; 1484 head = hccompact_units['from'] + ' ' + 1485 Highcharts.dateFormat(getDynDateFormat(this.x - ms), this.x - ms) + '<br />' + 1486 hccompact_units['until'] + ' ' + 1487 Highcharts.dateFormat(getDynDateFormat(this.x), this.x); 1488 } else { 1489 head = Highcharts.dateFormat(getDynDateFormat(this.x), this.x); 1490 } 1491 1492 var chart = (this.points && this.points.length) ? this.points[0].series.chart : null; 1493 1494 // Sichtbare Breite ab der Achse: der Tooltip steht linksbuendig an 1495 // `plotLeft`, `chartWidth` ist die Breite des Sichtfensters (bei 1496 // scrollbarer Zeichenflaeche ist das SVG breiter). Mehr Platz hat 1497 // er nicht, sonst verschwinden die rechten Spalten hinter der 1498 // Maske der fixierten Achse. 1499 var availW = 0; 1500 if (chart) { 1501 availW = Math.max(XL_TT_MIN_WIDTH, 1502 chart.chartWidth - chart.plotLeft - XL_TT_WIDTH_RESERVE); 1503 } 1504 1505 // `width: max-content` ist hier entscheidend: ohne feste Breite 1506 // wuerde der Browser den Tooltip auf die schmalste moegliche 1507 // Breite zusammenziehen und jede Zeile umbrechen. So bleibt er so 1508 // breit wie noetig - und hoechstens so breit wie erlaubt. 1509 var s = '<div class="xl-tt"' + 1510 (availW ? ' style="width:max-content;max-width:' + Math.round(availW) + 'px"' : '') + 1511 '><div class="xl-tt-head">' + head + '</div>'; 1512 1513 var median = null; 1514 var band = null; 1515 var models = []; 1516 this.points.forEach(function (p) { 1517 var role = xlSeriesRole(p.series); 1518 if (role === 'median') { median = p; } 1519 else if (role === 'band') { band = p; } 1520 else { models.push(p); } 1521 }); 1522 1523 if (median) { 1524 s += '<div class="xl-tt-median">' + 1525 '<span class="xl-tt-median-label">' + xlStatsT('median') + '</span>' + 1526 '<span class="xl-tt-median-value">' + fmt(median.y) + ' ' + unit + '</span>' + 1527 '</div>'; 1528 } 1529 if (band && band.point && band.point.low !== undefined) { 1530 s += '<div class="xl-tt-band">' + xlStatsT('band') + ': ' + 1531 fmt(band.point.low) + 'â' + fmt(band.point.high) + ' ' + unit + '</div>'; 1532 } 1533 1534 if (models.length) { 1535 models.sort(ordertooltip); 1536 1537 // Auf schmalen Geraeten ab vielen Modellen zweispaltig: sonst 1538 // wird der Tooltip hoeher als der Chart und wird unten 1539 // abgeschnitten (die Zeichenflaeche der XL-Charts ist 1540 // horizontal scrollbar, ihr Container kann `overflow-y` nicht 1541 // freigeben). Auf dem Desktop bleibt es einspaltig. 1542 // Gefuellt wird SPALTENWEISE, damit die Sortierung nach 1543 // Werten von oben nach unten lesbar bleibt. 1544 var cols = xlTooltipColumns(models.length);
1545 var rows = Math.ceil(models.length / cols); 1546 1547 // Mehrspaltig ist der Platz knapp: die Einheit steht bereits 1548 // am Medianwert, in den Zellen wird sie weggelassen. Auf 1549 // schmalen Geraeten zusaetzlich eine Stufe kleinere Schrift. 1550 var cellUnit = cols > 1 ? '' : ' ' + unit; 1551 // Die Breitenbegrenzung ist entscheidend dafuer, dass nichts 1552 // hinter der Achsenmaske verschwindet - deshalb zusaetzlich 1553 // inline, damit sie auch ohne frisch kompiliertes CSS greift. 1554 var tblStyle = ''; 1555 var nameStyle = ''; 1556 if (cols > 1) { 1557 tblStyle = 'table-layout:fixed;width:100%;'; 1558 if (availW > 0 && availW < XL_TT_NARROW_WIDTH) { 1559 tblStyle += 'font-size:10px;'; 1560 } 1561 nameStyle = ' style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap"'; 1562 } 1563 tblStyle = tblStyle ? ' style="' + tblStyle + '"' : ''; 1564 1565 s += '<table class="xl-tt-table' + (cols > 1 ? ' xl-tt-multicol' : '') + 1566 '"' + tblStyle + ' border="0" cellspacing="1">'; 1567 for (var r = 0; r < rows; r++) { 1568 s += '<tr>'; 1569 for (var c = 0; c < cols; c++) { 1570 var p = models[r + c * rows]; 1571 if (!p) { 1572 s += '<td class="xl-tt-name"></td><td class="xl-tt-val"></td>'; 1573 continue; 1574 } 1575 s += '<td class="xl-tt-name"' + nameStyle + '><span class="hc-legend-color" style="color:' + 1576 p.series.color + '">â</span> ' + p.series.name + '</td>' + 1577 '<td class="xl-tt-val"><b>' + fmt(p.y) + '</b>' + cellUnit + '</td>'; 1578 } 1579 s += '</tr>'; 1580 } 1581 s += '</table>'; 1582 } 1583 1584 return s + '</div>'; 1585 } 1586 }; 1587}; 1588 1589/** 1590 * Y-Achse fuer Niederschlag/Niederschlagssumme. 1591 * 1592 * Der bisherige feste softMax von 10 mm liess typische Ereignisse im unteren 1593 * Zehntel der Flaeche verschwinden. Stattdessen ein kleiner, sinnvoller 1594 * Mindestbereich: geringe Mengen fuellen den Plot, groessere Mengen skalieren 1595 * automatisch hoch. `tickAmount` sorgt fuer gerundete Schritte (0/2/4/6/8 mm). 1596 */ 1597var xlRainYAxis = function () { 1598 var mm = hccompact_units['rain'] == 'mm'; 1599 return { 1600 title: { text: false }, 1601 floor: 0, 1602 min: 0, 1603 softMax: mm ? 2 : 0.2, 1604 allowDecimals: true, 1605 labels: { 1606 format: '{value} ' + hccompact_units['rain'], 1607 style: { 1608 color: cssVar('--hc-xl-label', '#79838D'), 1609 fontSize: '12px' 1610 } 1611 }, 1612 minorTickInterval: null, 1613 minorGridLineWidth: 0, 1614 gridLineWidth: 1, 1615 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 1616 majorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 1617 lineWidth: 0, 1618 tickAmount: 5, 1619 maxPadding: 0.08 1620 }; 1621}; 1622 1623var getVHStationUnitSoftMax = function() { 1624 if ($('#btn-vhs-unit-ms').hasClass('btn-active')) { 1625 return 20; 1626 } 1627 else if ($('#btn-vhs-unit-kmh').hasClass('btn-active')) { 1628 return 80; 1629 } 1630 else if ($('#btn-vhs-unit-kn').hasClass('btn-active')) { 1631 return 40; 1632 } 1633 else if ($('#btn-vhs-unit-kjm2').hasClass('btn-active')) { 1634 if($('#btn-vhs-mode-minutes').hasClass('btn-active')) { 1635 return 600; 1636 } else { 1637 return 1000; 1638 } 1639 1640 } 1641 return 100; 1642} 1643var getVHStationUnit = function() { 1644 if ($('#btn-vhs-unit-ms').hasClass('btn-active')) { 1645 return 'm/s'; 1646 } 1647 else if ($('#btn-vhs-unit-kmh').hasClass('btn-active')) { 1648 return 'km/h'; 1649 } 1650 else if ($('#btn-vhs-unit-kn').hasClass('btn-active')) { 1651 return 'kn'; 1652 } 1653 else if ($('#btn-vhs-unit-kjm2').hasClass('btn-active')) { 1654 return 'kJ/m²'; 1655 } 1656 else if ($('#btn-vhs-unit-hpa').hasClass('btn-active')) { 1657 return 'hPa'; 1658 } 1659 else if ($('#btn-vhs-unit-jcm2').hasClass('btn-active')) { 1660 return 'J/cm²'; 1661 } 1662 else if ($('#btn-vhs-unit-percent').hasClass('btn-active')) { 1663 return '%'; 1664 } 1665 return ''; 1666} 1667 1668var getVHStationDateFormat = function(value, is_tooltip) { 1669 var date_format; 1670 date_format='%e. %b'; 1671 if(is_tooltip) date_format = '%A, der %e. %B'; 1672 1673 if ($('#btn-vhs-mode-hour').hasClass('btn-active')) { 1674 var hour = Highcharts.dateFormat("%H", value); 1675 if(hour%24!=0) { date_format='%H:%M'; } 1676 if(is_tooltip) date_format="%A, der %e.%B, %H:%M Uhr"; 1677 } 1678 else if ($('#btn-vhs-mode-minutes').hasClass('btn-active')) { 1679 var hour = Highcharts.dateFormat("%H", value); 1680 if(hour%24!=0) { date_format='%H:%M'; } 1681 if(is_tooltip) date_format="%A, der %e.%B, %H:%M Uhr"; 1682 } 1683 else if ($('#btn-vhs-mode-week').hasClass('btn-active')) { 1684 //date_format='%w'; 1685 } 1686 else if ($('#btn-vhs-mode-month').hasClass('btn-active')) { 1687 date_format='%b'; 1688 if(is_tooltip) date_format = '%B %Y'; 1689 } 1690 else if ($('#btn-vhs-mode-year').hasClass('btn-active')) { 1691 date_format='%Y'; 1692 } 1693 return date_format; 1694} 1695 1696function ordertooltip( a, b ) { 1697 if ( a.y < b.y ){ 1698 return 1; 1699 } 1700 if ( a.y >
1700 b.y ){ 1701 return -1; 1702 } 1703 return 0; 1704} 1705 1706(function(){ 1707 const SCROLLER_SELECTOR = '.highcharts-scrolling, .highcharts-scrolling-parent, [data-highcharts-chart] .highcharts-scrolling';; 1708 1709 const lastLeft = new WeakMap(); // merkt pro Scroller die letzte scrollLeft-Position 1710 let hint, host, dismissed = false; 1711 1712 function isHorizOverflow(el){ 1713 return el && el.scrollWidth - el.clientWidth > 2; 1714 } 1715 function isVisible(el){ 1716 if (!el) return false; 1717 const cs = getComputedStyle(el); 1718 if (cs.visibility === 'hidden' || cs.display === 'none') return false; 1719 const r = el.getBoundingClientRect(); 1720 return r.width > 0 && r.height > 0; 1721 } 1722 function getActiveScroller(){ 1723 const root = (host && host.isConnected ? host : document); 1724 let list = Array.from(root.querySelectorAll(SCROLLER_SELECTOR)); 1725 1726 if (!list.length && root !== document) { 1727 list = Array.from(document.querySelectorAll(SCROLLER_SELECTOR)); 1728 } 1729 1730 return list.find(el => isVisible(el) && isHorizOverflow(el)) || list[0] || null; 1731 } 1732 1733 1734 function dismissHint(){ 1735 if (!hint || dismissed) return; 1736 dismissed = true; 1737 hint.classList.add('dismiss'); 1738 hint.addEventListener('animationend', () => hint.remove(), { once:true }); 1739 } 1740 1741 function onScrollerScroll(e){ 1742 const el = e.currentTarget || e.target; 1743 const prev = lastLeft.get(el) ?? el.scrollLeft; 1744 const moved = Math.abs(el.scrollLeft - prev) > 0; 1745 lastLeft.set(el, el.scrollLeft); 1746 if (moved && el.scrollLeft > 0) dismissHint(); 1747 } 1748 1749 function attachToScroller(el){ 1750 if (!el || el.__hcHintBound) return; 1751 el.__hcHintBound = true; 1752 lastLeft.set(el, el.scrollLeft); 1753 el.addEventListener('scroll', onScrollerScroll, { passive:true }); 1754 } 1755 1756 function attachGlobalScrollListeners(){ 1757 1758 document.querySelectorAll(SCROLLER_SELECTOR).forEach(attachToScroller); 1759 document.addEventListener('scroll', (e)=>{ 1760 const t = e.target; 1761 if (!(t instanceof Element)) return; 1762 if (t.matches && t.matches(SCROLLER_SELECTOR)) onScrollerScroll(e); 1763 }, { passive:true, capture:true }); 1764 1765 const mo = new MutationObserver(()=> { 1766 document.querySelectorAll(SCROLLER_SELECTOR).forEach(attachToScroller); 1767 }); 1768 mo.observe(document.body, { subtree:true, childList:true, attributes:true, attributeFilter:['class','style'] }); 1769 } 1770 1771 1772 1773 window.addGlobalChartScrollHint = function(hostContainer){ 1774 host = hostContainer || document.body; 1775 if (!hint) { 1776 const firstScroller = getActiveScroller(); 1777 if (!firstScroller || !isHorizOverflow(firstScroller)) return; 1778 1779 hint = document.createElement('button'); 1780 hint.type = 'button'; 1781 hint.className = 'scroll-hint'; 1782 hint.textContent = (displayLanguage()=="EN")?'More Data â':'Mehr Daten â'; 1783 (host).style.position = getComputedStyle(host).position === 'static' ? 'relative' : getComputedStyle(host).position; 1784 host.appendChild(hint); 1785 1786 hint.addEventListener('click', () => { 1787 const sc = getActiveScroller(); 1788 if (sc) sc.scrollBy({ left: Math.round(sc.clientWidth * 0.33), behavior: 'smooth' }); 1789 dismissHint(); 1790 }, { passive:true }); 1791 1792 attachGlobalScrollListeners(); 1793 } 1794 }; 1795})(); 1796 1797var plotGraph = function() { 1798 Highcharts.seriesTypes.line.prototype.drawLegendSymbol = Highcharts.seriesTypes.column.prototype.drawLegendSymbol; 1799 Highcharts.AST.allowedAttributes.push('title'); 1800 Highcharts.AST.allowedAttributes.push('data-longname'); 1801 Highcharts.AST.allowedAttributes.push('data-flagfile'); 1802 Highcharts.AST.allowedAttributes.push('data-run'); 1803 Highcharts.AST.allowedAttributes.push('border'); 1804 Highcharts.AST.allowedAttributes.push('cellspacing'); 1805 var timezone_id_local = typeof timezone_id !== 'undefined' ? timezone_id : null; 1806 Highcharts.setOptions({ 1807 global: { 1808 /** 1809 * Use moment-timezone.js to return the timezone offset for individual 1810 * timestamps, used in the X axis labels and the tooltip header. 1811 */ 1812 // getTimezoneOffset: function (timestamp) { 1813 // return -moment.tz(timezone_id).utcOffset(); 1814 // } 1815 timezone: timezone_id_local || $('#real-user-timezone').attr('data-value') || 'UTC' 1816 1817 }, 1818 lang: typeof hc_user_settings_lang !== 'undefined' ? hc_user_settings_lang : { 1819 loading: 'Wird geladen...', 1820 months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
1821 weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], 1822 shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], 1823 } 1824 }); 1825 var zeroline = 0; 1826 if (typeof hccompact_units != 'undefined') { 1827 if (hccompact_units['temp'] == '°F') { 1828 zeroline = 32; 1829 } 1830 else if(hccompact_units['temp']=="K") { 1831 zeroline = 273.15; 1832 } 1833 } 1834 if (typeof hc_data_temp != 'undefined') { 1835 $('#temp_graph').highcharts({ 1836 title: 'false', 1837 1838 chart: { 1839 scrollablePlotArea: {minWidth: getMinWidth()}, 1840 className: (typeof hc_data_temp_chartclass != 'undefined')?hc_data_temp_chartclass:'', 1841 events: { 1842 load: function() { 1843 temp_graphContainerId = this.container.id; 1844 $( '#'+temp_graphContainerId+'.toggle-flags' ).tooltip({ 1845 content: function() { 1846 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 1847 } 1848 }); 1849 //drawHourlyLabels(this,'xl'); 1850 drawNightShadows(this,1,'xl'); 1851 fixLabels(this,'xl'); 1852 }, 1853 redraw: function(){ 1854 //drawHourlyLabels(this,'xl'); 1855 drawNightShadows(this,1,'xl'); 1856 fixLabels(this,'xl'); 1857 }, 1858 1859 } 1860 }, 1861 legend: xlLegendWithFlag, 1862 responsive: xlChartOptions(xlAlleNumbers), 1863 1864 xAxis: xlXAxisStandard, 1865 yAxis: xlYAxisTemp("{value} "+hccompact_units['temp'], zeroline), 1866 tooltip: xlTooltip(hccompact_units['temp'], 1), 1867 credits: { enabled: false }, 1868 exporting: { enabled: false }, 1869 plotOptions: xlPlotOptions('temp_graph'), 1870 series: xlSeries(hc_data_temp, {smooth: true}), 1871 reflow: true 1872 }); 1873 } 1874 if (typeof hc_data_temp850 != 'undefined') { 1875 $('#temp850_graph').highcharts({ 1876 title: 'false', 1877 chart: { 1878 scrollablePlotArea: {minWidth: getMinWidth()}, 1879 className: (typeof hc_data_temp850_chartclass != 'undefined')?hc_data_temp850_chartclass:'', 1880 events: { 1881 load: function() { 1882 temp850_graphContainerId = this.container.id; 1883 $( '#'+temp850_graphContainerId+'.toggle-flags' ).tooltip({ 1884 content: function() { 1885 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 1886 } 1887 }); 1888 //drawHourlyLabels(this,'xl'); 1889 drawNightShadows(this,3,'xl'); 1890 fixLabels(this,'xl'); 1891 }, 1892 redraw: function(){ 1893 //drawHourlyLabels(this,'xl'); 1894 drawNightShadows(this,3,'xl'); 1895 fixLabels(this,'xl'); 1896 } 1897 } 1898 }, 1899 legend: xlLegendWithFlag, 1900 responsive: xlChartOptions(xl850Numbers), 1901 xAxis: xlXAxisStandard, 1902 yAxis: xlYAxisTemp("{value} "+hccompact_units['temp'],zeroline), 1903 tooltip: xlTooltip(hccompact_units['temp'], 1), 1904 credits: { enabled: false }, 1905 exporting: { enabled: false }, 1906 plotOptions: xlPlotOptions('temp850_graph'), 1907 series: xlSeries(hc_data_temp850, {smooth: true}), 1908 reflow: true 1909 }); 1910 } 1911 1912 if (typeof hc_data_temp925 != 'undefined') { 1913 $('#temp925_graph').highcharts({ 1914 title: 'false', 1915 chart: { 1916 scrollablePlotArea: {minWidth: getMinWidth()}, 1917 className: (typeof hc_data_temp925_chartclass != 'undefined')?hc_data_temp925_chartclass:'', 1918 events: { 1919 load: function() { 1920 temp925_graphContainerId = this.container.id; 1921 $( '#'+temp925_graphContainerId+'.toggle-flags' ).tooltip({ 1922 content: function() { 1923 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 1924 } 1925 }); 1926 //drawHourlyLabels(this,'xl'); 1927 drawNightShadows(this,4,'xl'); 1928 fixLabels(this,'xl'); 1929 }, 1930 redraw: function(){ 1931 //drawHourlyLabels(this,'xl'); 1932 drawNightShadows(this,4,'xl'); 1933 fixLabels(this,'xl'); 1934 } 1935 } 1936 }, 1937 legend: xlLegendWithFlag, 1938 responsive: xlChartOptions(xl925Numbers), 1939 xAxis: xlXAxisStandard, 1940 yAxis: xlYAxisTemp("{value} "+hccompact_units['temp'],zeroline), 1941 tooltip: xlTooltip(hccompact_units['temp'], 1), 1942 credits: { enabled: false }, 1943 exporting: { enabled: false }, 1944 plotOptions: xlPlotOptions('temp925_graph'), 1945 series: xlSeries(hc_data_temp925, {smooth: true}), 1946 reflow: true 1947 }); 1948 } 1949 1950 if (typeof hc_data_temp700 != 'undefined') { 1951 $('#temp700_graph').highcharts({ 1952 title: 'false', 1953 chart: { 1954 scrollablePlotArea: {minWidth: getMinWidth()}, 1955 className: (typeof hc_data_temp700_chartclass != 'undefined')?hc_data_temp700_chartclass:'', 1956 events: { 1957 load: function() { 1958 temp700ContainerId = this.container.id; 1959 $( '#'+temp700ContainerId+'.toggle-flags' ).tooltip({ 1960 content: function() { 1961 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 1962 } 1963 }); 1964 //drawHourlyLabels(this,'xl'); 1965 drawNightShadows(this,5,'xl'); 1966 fixLabels(this,'xl'); 1967 }, 1968 redraw: function(){ 1969 //drawHourlyLabels(this,'xl'); 1970 drawNightShadows(this,5,'xl'); 1971 fixLabels(this,'xl'); 1972 } 1973 } 1974 }, 1975 legend: xlLegendWithFlag, 1976 responsive: xlChartOptions(xl700Numbers), 1977 xAxis: xlXAxisStandard, 1978 yAxis: xlYAxisTemp("{value} "+hccompact_units['temp'],zeroline), 1979 tooltip: xlTooltip(hccompact_units['temp'], 1), 1980 credits: { enabled: false }, 1981 exporting: { enabled: false }, 1982 plotOptions: xlPlotOptions('temp700_graph'), 1983 series: xlSeries(hc_data_temp700, {smooth: true}), 1984 reflow: true 1985 }); 1986 } 1987 1988 if (typeof hc_data_dewpoint != 'undefined') { 1989 $('#dewpoint_graph').highcharts({ 1990 title: 'false', 1991 chart: { 1992 scrollablePlotArea: {minWidth: getMinWidth()}, 1993 className: (typeof hc_data_dewpoint_chartclass != 'undefined')?hc_data_dewpoint_chartclass:'', 1994 events: { 1995 load: function() {
1996 dewpointContainerId = this.container.id; 1997 $( '#'+dewpointContainerId+'.toggle-flags' ).tooltip({ 1998 content: function() { 1999 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2000 } 2001 }); 2002 //drawHourlyLabels(this,'xl'); 2003 drawNightShadows(this,6,'xl'); 2004 fixLabels(this,'xl'); 2005 }, 2006 redraw: function(){ 2007 //drawHourlyLabels(this,'xl'); 2008 drawNightShadows(this,6,'xl'); 2009 fixLabels(this,'xl'); 2010 } 2011 } 2012 }, 2013 legend: xlLegendWithFlag, 2014 responsive: xlChartOptions(xlAlleNumbers), 2015 xAxis: xlXAxisStandard, 2016 yAxis: xlYAxisTemp("{value}"+hccompact_units['temp'],zeroline), 2017 tooltip: xlTooltip(hccompact_units['temp'], 1), 2018 credits: { enabled: false }, 2019 exporting: { enabled: false }, 2020 plotOptions: xlPlotOptions('dewpoint_graph'), 2021 series: xlSeries(hc_data_dewpoint, {smooth: true}), 2022 reflow: true 2023 }); 2024 } 2025 2026 if (typeof hc_data_wbulb != 'undefined') { 2027 $('#wbulb_graph').highcharts({ 2028 title: 'false', 2029 chart: { 2030 scrollablePlotArea: {minWidth: getMinWidth()}, 2031 className: (typeof hc_data_wbulb_chartclass != 'undefined')?hc_data_wbulb_chartclass:'', 2032 events: { 2033 load: function() { 2034 wbulbContainerId = this.container.id; 2035 $( '#'+wbulbContainerId+'.toggle-flags' ).tooltip({ 2036 content: function() { 2037 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2038 } 2039 }); 2040 //drawHourlyLabels(this,'xl'); 2041 drawNightShadows(this,7,'xl'); 2042 fixLabels(this,'xl'); 2043 }, 2044 redraw: function(){ 2045 //drawHourlyLabels(this,'xl'); 2046 drawNightShadows(this,7,'xl'); 2047 fixLabels(this,'xl'); 2048 } 2049 } 2050 }, 2051 legend: xlLegendWithFlag, 2052 responsive: xlChartOptions(xlWbulbNumbers), 2053 xAxis: xlXAxisStandard, 2054 yAxis: xlYAxisTemp("{value} "+hccompact_units['temp'],zeroline), 2055 tooltip: xlTooltip(hccompact_units['temp'], 1), 2056 credits: { enabled: false }, 2057 exporting: { enabled: false }, 2058 plotOptions: xlPlotOptions('wbulb_graph'), 2059 series: xlSeries(hc_data_wbulb, {smooth: true}), 2060 reflow: true 2061 }); 2062 } 2063 2064 if (typeof hc_data_pressure != 'undefined') { 2065 console.log("pressure"); 2066 $('#pressure_graph').highcharts({ 2067 title: 'false', 2068 chart: { 2069 scrollablePlotArea: {minWidth: getMinWidth()}, 2070 className: (typeof hc_data_pressure_chartclass != 'undefined')?hc_data_pressure_chartclass:'', 2071 events: { 2072 load: function() { 2073 pressureContainerId = this.container.id; 2074 $( '#'+pressureContainerId+'.toggle-flags' ).tooltip({ 2075 content: function() { 2076 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2077 } 2078 }); 2079 //drawHourlyLabels(this,'xl'); 2080 drawNightShadows(this,31,'xl'); 2081 fixLabels(this,'xl'); 2082 }, 2083 redraw: function(){ 2084 //drawHourlyLabels(this,'xl'); 2085 drawNightShadows(this,31,'xl'); 2086 fixLabels(this,'xl'); 2087 } 2088 } 2089 }, 2090 legend: xlLegendWithFlag, 2091 responsive: xlChartOptions(xlAlleNumbers), 2092 xAxis: xlXAxisStandard, 2093 yAxis: xlYAxisStandardFormatter(function() { 2094 return Highcharts.numberFormat(this.value,hccompact_units['pressure'] === '
2094inHg' ? 1 : 0)+(hccompact_units['pressure'] === 'mbar' ? "":" ")+hccompact_units['pressure']; 2095 },0, hccompact_units['pressure'] === 'inHg', hccompact_units['pressure'] === 'inHg' ? 0.1:1), 2096 tooltip: xlTooltip(hccompact_units['pressure'], 1), 2097 credits: { enabled: false }, 2098 exporting: { enabled: false }, 2099 plotOptions: xlPlotOptions('pressure_graph'), 2100 series: xlSeries(hc_data_pressure, {smooth: true}), 2101 reflow: true 2102 }); 2103 } 2104 2105 if (typeof hc_data_wind != 'undefined') { 2106 $('#wind_graph').highcharts({ 2107 title: 'false', 2108 chart: { 2109 scrollablePlotArea: {minWidth: getMinWidth()}, 2110 className: (typeof hc_data_wind_chartclass != 'undefined')?hc_data_wind_chartclass:'', 2111 events: { 2112 load: function() { 2113 windContainerId = this.container.id; 2114 $( '#'+windContainerId+'.toggle-flags' ).tooltip({ 2115 content: function() { 2116 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2117 } 2118 }); 2119 //drawHourlyLabels(this,'xl'); 2120 drawNightShadows(this,9,'xl'); 2121 fixLabels(this,'xl'); 2122 }, 2123 redraw: function(){ 2124 //drawHourlyLabels(this,'xl'); 2125 drawNightShadows(this,9,'xl'); 2126 fixLabels(this,'xl'); 2127 } 2128 } 2129 }, 2130 legend: xlLegendWithFlag, 2131 responsive: xlChartOptions(xlAlleNumbers), 2132 xAxis: xlXAxisStandard, 2133 yAxis: { 2134 title: { 2135 text: false 2136 }, 2137 floor: 0, 2138 labels: { 2139 format: "{value} "+hccompact_units['wind'], 2140 style: { 2141 color: cssVar('--color-text') 2142 } 2143 }, 2144 min: 0, 2145 max: hccompact_units['wind']=="Bft" ? 12 : hccompact_units['wind']=="m/s" ? 30 : hccompact_units['wind']=="kn" ? 60 : hccompact_units['wind']=="mph" ? 60 : 100, 2146 allowDecimals: false, 2147 minorTickInterval: 5, 2148 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 2149 minorGridLineColor: cssVar('--hc-gridLineColorf2f2f2'), 2150 2151 endOnTick: false, 2152 tickAmount: 5 2153 }, 2154 tooltip: xlTooltip(hccompact_units['wind'], hccompact_units['wind'] == 'm/s' ? 1 : 0), 2155 credits: { enabled: false }, 2156 exporting: { enabled: false }, 2157 plotOptions: xlPlotOptions('wind_graph'), 2158 series: xlSeries(hc_data_wind, {smooth: false}), 2159 reflow: true 2160 }); 2161 } 2162 2163 if (typeof wind_graph_open != 'undefined') { 2164 $('#wind_graph_open').highcharts({ 2165 title: 'false', 2166 chart: { 2167 scrollablePlotArea: {minWidth: getMinWidth()}, 2168 className: (typeof wind_graph_open_chartclass != 'undefined')?wind_graph_open_chartclass:'', 2169 events: { 2170 load: function() { 2171 windopenContainerId = this.container.id; 2172 $( '#'+windopenContainerId+'.toggle-flags' ).tooltip({ 2173 content: function() { 2174 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2175 } 2176 }); 2177 //drawHourlyLabels(this,'xl'); 2178 drawNightShadows(this,10,'xl'); 2179 fixLabels(this,'xl'); 2180 }, 2181 redraw: function(){ 2182 //drawHourlyLabels(this,'xl'); 2183 drawNightShadows(this,10,'xl'); 2184 fixLabels(this,'xl'); 2185 } 2186 } 2187 }, 2188 legend: xlLegendWithFlag, 2189 responsive: xlChartOptions(xlAlleNumbers), 2190 xAxis: xlXAxisStandard, 2191 yAxis: { 2192 title: { 2193 text: false 2194 }, 2195 floor: 0, 2196 labels: { 2197 format: "{value} "+hccompact_units['wind'] 2198 }, 2199 min:0, 2200 allowDecimals: false, 2201 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 2202 }, 2203 tooltip: xlTooltip(hccompact_units['wind'], hccompact_units['wind'] == 'm/s' ? 1 : 0), 2204 credits: { enabled: false }, 2205 exporting: { enabled: false }, 2206 plotOptions: xlPlotOptions('wind_graph_open'), 2207 series: xlSeries(hc_data_wind_open, {smooth: false}), 2208 reflow: true 2209 }); 2210 } 2211 2212 if (typeof hc_data_gusts != 'undefined') { 2213 $('#gusts_graph').highcharts({ 2214 title: 'false', 2215 chart: { 2216 scrollablePlotArea: {minWidth: getMinWidth()}, 2217 className: (typeof hc_data_gusts_chartclass != 'undefined')?hc_data_gusts_chartclass:'', 2218 events: { 2219 load: function() { 2220 gustsContainerId = this.container.id; 2221 $( '#'+gustsContainerId+'.toggle-flags' ).tooltip({ 2222 content: function() { 2223 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2224 } 2225 }); 2226 //drawHourlyLabels(this,'xl'); 2227 drawNightShadows(this,11,'xl'); 2228 fixLabels(this,'xl'); 2229 }, 2230 redraw: function(){ 2231 //drawHourlyLabels(this,'xl'); 2232 drawNightShadows(this,11,'xl'); 2233 fixLabels(this,'xl'); 2234 } 2235 } 2236 }, 2237 legend: xlLegendWithFlag, 2238 responsive: xlChartOptions(xlAlleNumbers), 2239 xAxis: xlXAxisStandard, 2240 yAxis: { 2241 title: { 2242 text: false 2243 }, 2244 allowDecimals: false, 2245 floor: 0, 2246 labels: { 2247 format: "{value} "+hccompact_units['wind'], 2248 style: { 2249 color: cssVar('--color-text') 2250 } 2251 }, 2252 min:0, 2253 softMax: hccompact_units['wind']=="Bft" ? 12 : hccompact_units['wind']=="m/s" ? 30 : hccompact_units['wind']=="kn" ? 60 : hccompact_units['wind']=="mph" ? 60 : 100, 2254 minorTickInterval: 5, 2255 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 2256 minorGridLineColor: cssVar('--hc-gridLineColorf2f2f2'), 2257 tickAmount: 5 2258 }, 2259 tooltip: xlTooltip(hccompact_units['wind'], hccompact_units['wind'] == 'm/s' ? 1 : 0), 2260 credits: { enabled: false }, 2261 exporting: { enabled: false }, 2262 plotOptions: xlPlotOptions('gusts_graph'), 2263 series: xlSeries(hc_data_gusts, {smooth: false}), 2264 reflow: true 2265 }); 2266 } 2267 2268 if (typeof hc_data_gusts_open != 'undefined') { 2269 $('#gusts_graph_open').highcharts({ 2270 title: 'false', 2271 chart: { 2272 scrollablePlotArea: {minWidth: getMinWidth()}, 2273 className: (typeof hc_data_gusts_open_chartclass != 'undefined')?hc_data_gusts_open_chartclass:'', 2274 events: { 2275 load: function() { 2276 gustsopenContainerId = this.container.id; 2277 $( '#'+gustsopenContainerId+'.toggle-flags' ).tooltip({ 2278 content: function() { 2279 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2280 } 2281 }); 2282 //drawHourlyLabels(this,'xl'); 2283 drawNightShadows(this,13,'xl'); 2284 fixLabels(this,'xl'); 2285 }, 2286 redraw: function(){ 2287 //drawHourlyLabels(this,'xl'); 2288 drawNightShadows(this,13,'xl'); 2289 fixLabels(this,'xl'); 2290 } 2291 } 2292 }, 2293 legend: xlLegendWithFlag, 2294 responsive: xlChartOptions(xlAlleNumbers), 2295 xAxis: xlXAxisStandard, 2296 yAxis: { 2297 title: { 2298 text: false 2299 }, 2300 floor: 0, 2301 labels: { 2302 format: "{value} "+hccompact_units['wind'], 2303 style: { 2304 color: cssVar('--color-text') 2305 } 2306 }, 2307 min:0, 2308 allowDecimals: false, 2309 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 2310 minorGridLineColor: cssVar('--hc-gridLineColorf2f2f2'), 2311 }, 2312 tooltip: xlTooltip(hccompact_units['wind'], hccompact_units['wind'] == 'm/s' ? 1 : 0), 2313 credits: { enabled: false }, 2314 exporting: { enabled: false }, 2315 plotOptions: xlPlotOptions('gusts_graph_open'), 2316 series: xlSeries(hc_data_gusts_open, {smooth: false}), 2317 reflow: true 2318 }); 2319 } 2320 2321 if (typeof hc_data_rain != 'undefined') { 2322 $('#rain_graph').highcharts({ 2323 2324 chart: { 2325 scrollablePlotArea: {minWidth: getMinWidth()}, 2326 type: 'column', 2327 className: (typeof hc_data_rain_chartclass != 'undefined')?hc_data_rain_chartclass:'', 2328 events: { 2329 load: function() { 2330 rainContainerId = this.container.id; 2331 $( '#'+rainContainerId+'.toggle-flags' ).tooltip({ 2332 content: function() { 2333 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2334 } 2335 }); 2336 drawHourlyLabels(this,'xl2'); 2337 drawIntervals(this,8,undefined,'xl'); 2338 fixLabels(this,'temp'); 2339 }, 2340 redraw: function(){ 2341 drawHourlyLabels(this,'xl2'); 2342 drawIntervals(this,8,undefined,'xl'); 2343 fixLabels(this,'temp'); 2344 } 2345 } 2346 }, 2347 title: 'false', 2348 legend: xlLegendWithFlag, 2349 responsive: xlChartOptions(xlAlleNumbers), 2350 xAxis: { 2351 opposite:true, 2352 type: 'datetime', 2353 tickInterval: 24*36e5, 2354 gridLineWidth: 0, 2355 gridLineColor: cssVar('--hc-gridLineColor777777'), 2356 gridZIndex:2, 2357 tickLength: 0, 2358 dateTimeLabelFormats: { 2359 hour: getDynHourDateFormat(), 2360 day: getDynDayDateFormat() 2361 }, 2362 labels: { 2363 useHTML: true, 2364 align: 'center', 2365 style: { 2366 color: cssVar('--color-text') 2367 }, 2368 formatter: function () { 2369 var date_format = getDynDayShortDateFormat(this.value, this.chart.plotWidth); 2370 return Highcharts.dateFormat(date_format, this.value); 2371 } 2372 } 2373 2374 }, 2375 yAxis: xlRainYAxis(), 2376 tooltip: xlTooltip(hccompact_units['rain'], hccompact_units['rain'] == 'in' ? 2 : 1, {rangeHours: 6}), 2377 credits: { enabled: false }, 2378 exporting: { enabled: false }, 2379 plotOptions: xlPlotOptions('rain_graph'), 2380 series: xlSeries(hc_data_rain, {column: true, stats: false /*, medianColor: xlColor('--hc-xl-median-rain', '#1B6FB5') */}), 2381 reflow: true 2382 }); 2383 } 2384 2385 if (typeof hc_data_rain_day != 'undefined') { 2386 $('#rain_graph_day').highcharts({ 2387 2388 chart: { 2389 scrollablePlotArea: {minWidth: getMinWidth()}, 2390 type: 'column', 2391 className: (typeof hc_data_rain_chartclass != 'undefined')?hc_data_rain_chartclass:'', 2392 events: { 2393 load: function() { 2394 raindayContainerId = this.container.id; 2395 $( '#'+raindayContainerId+'.toggle-flags' ).tooltip({ 2396 content: function() { 2397 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2398 } 2399 }); 2400 2401 //drawHourlyLabels(this,'xl3'); 2402 drawIntervals(this,8,48,'xl'); 2403 //fixLabels(this,'temp'); 2404 }, 2405 redraw: function() { 2406 2407 //drawHourlyLabels(this,'xl3'); 2408 drawIntervals(this,8,48,'xl'); 2409 //fixLabels(this,'temp'); 2410 } 2411 2412 } 2413 }, 2414 title: 'false', 2415 legend: xlLegendWithFlag, 2416 responsive: xlChartOptions(xlAlleNumbers), 2417 xAxis: { 2418 opposite:true, 2419 type: 'datetime', 2420 tickLength: 0, 2421 lineColor: cssVar('--hc-gridLineColorCCCCCC'), 2422 minorGridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 2423 dateTimeLabelFormats: { 2424 hour: getDynHourDateFormat(), 2425 day: getDynDayDateFormat() 2426 }, 2427 labels: { 2428 useHTML: true, 2429 align: 'center', 2430 style: { 2431 color: cssVar('--color-text') 2432 }, 2433 formatter: function () { 2434 var date_format = getDynDayShortDateFormat(this.value, this.chart.plotWidth); 2435 return Highcharts.dateFormat(date_format, this.value); 2436 } 2437 }, 2438 2439 2440 }, 2441 yAxis: xlRainYAxis(), 2442 tooltip: xlTooltip(hccompact_units['rain'], hccompact_units['rain'] == 'in' ? 2 : 1), 2443 credits: { enabled: false }, 2444 exporting: { enabled: false }, 2445 plotOptions: xlPlotOptions('rain_graph_day'), 2446 series: xlSeries(hc_data_rain_day, {column: true, stats: false /*, medianColor: xlColor('--hc-xl-median-rain', '#1B6FB5') */}), 2447 reflow: true 2448 }); 2449 } 2450 2451 if (typeof hc_data_sunshine_day != 'undefined') { 2452 $('#sunshine_graph_day').highcharts({ 2453 2454 chart: { 2455 scrollablePlotArea: {min
2455Width: getMinWidth()}, 2456 type: 'column', 2457 className: (typeof chartclass != 'undefined')?chartclass:'', 2458 events: { 2459 load: function() { 2460 sunshinedayContainerId = this.container.id; 2461 $( '#'+sunshinedayContainerId+'.toggle-flags' ).tooltip({ 2462 content: function() { 2463 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2464 } 2465 }); 2466 //drawHourlyLabels(this,'xl'); 2467 drawNightShadows(this,15,'xl'); 2468 fixLabels(this,'xl'); 2469 }, 2470 redraw: function(){ 2471 //drawHourlyLabels(this,'xl'); 2472 drawNightShadows(this,15,'xl'); 2473 fixLabels(this,'xl'); 2474 } 2475 } 2476 }, 2477 title: 'false', 2478 legend: xlLegendWithFlag, 2479 responsive: xlChartOptions(xlAlleNumbers), 2480 xAxis: xlXAxisStandard, 2481 yAxis: { 2482 title: { 2483 text: false 2484 }, 2485 floor: 0, 2486 labels: { 2487 format: "{value} "+hccompact_units['sun'], 2488 style: { 2489 color: cssVar('--color-text') 2490 } 2491 }, 2492 min:0, 2493 softMax: 12, 2494 allowDecimals: false, 2495 minorTickInterval: 1, 2496 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 2497 2498 }, 2499 tooltip: { 2500 crosshairs: true, 2501 shared: true, 2502 valueSuffix: ' '+hccompact_units['sun'], 2503 shape: 'square', 2504 useHTML: true, 2505 dateTimeLabelFormats: { 2506 minute:"%A, den %e.%B", 2507 hour:"%A, den %e.%B", 2508 }, 2509 zIndex: 50, 2510 outside: false, 2511 style: { 2512 zIndex: 10000, 2513 pointerEvents: 'auto' 2514 }, 2515 positioner: tooltipPositioner, 2516 formatter: function () { 2517 var date_format = getDynDateFormat(this.x); 2518 var s = '<span style="font-size:10px; font-weight: bold; line-height: 20px;">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 2519 this.points.sort( ordertooltip ); 2520 s += '<table width="100%" border="0" cellspacing="1">'; 2521 $.each(this.points, function () { 2522 s += '<tr><td style="font-size: 11px; line-height: 16px;" width="70%"><span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ':</td><td width="30%" style="text-align: right; font-size: 11px; line-height: 16px;"><b>'+(Math.round(this.y * 100) / 100).toFixed(1) + '</b> '+hccompact_units['sun']+'</td></tr>'; 2523 }); 2524 s += '</table>'; 2525 2526 2527 return s; 2528 } 2529 }, 2530 credits: { enabled: false }, 2531 exporting: { enabled: false }, 2532 plotOptions: xlPlotOptions('sunshine_graph_day'), 2533 series: xlSeries(hc_data_sunshine_day, {column: true, stats: false}), 2534 reflow: true 2535 }); 2536 } 2537 2538 if (typeof hc_data_rain2 != 'undefined') { 2539 $('#rain2_graph').highcharts({ 2540 chart: { 2541 scrollablePlotArea: {minWidth: getMinWidth()}, 2542 className: (typeof chartclass != 'undefined')?chartclass:'', 2543 events: { 2544 load: function() { 2545 rain2ContainerId = this.container.id; 2546 $( '#'+rain2ContainerId+'.toggle-flags' ).tooltip({ 2547 content: function() { 2548 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2549 } 2550 }); 2551 //drawHourlyLabels(this,'xl'); 2552 drawNightShadows(this,17,'xl'); 2553 fixLabels(this,'xl'); 2554 }, 2555 redraw: function(){ 2556 //drawHourlyLabels(this,'xl'); 2557 drawNightShadows(this,17,'xl'); 2558 fixLabels(this,'xl'); 2559 } 2560 } 2561 }, 2562 title: 'false', 2563 legend: xlLegendWithFlag, 2564 responsive: xlChartOptions(xlAlleNumbers), 2565 xAxis: { 2566 opposite:true, 2567 type: 'datetime', 2568 tickInterval: 24*36e5, 2569 gridLineWidth: 1, 2570 gridLineColor: cssVar('--hc-gridLineColor777777'), 2571 gridZIndex:2, 2572 minorTickInterval: 3*36e5, 2573 minorGridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 2574 minorGridWidth: 1, 2575 tickLength: 0, 2576 dateTimeLabelFormats: { 2577 hour: getDynHourDateFormat(), 2578 day: getDynDayDateFormat() 2579 }, 2580 labels: { 2581 useHTML: true, 2582 align: 'center', 2583 formatter: function () { 2584 var date_format = getDynDayShortDateFormat(this.value, this.chart.plotWidth); 2585 return Highcharts.dateFormat(date_format, this.value); 2586 }, 2587 style: { 2588 color: cssVar('--color-text') 2589 } 2590 } 2591 2592 }, 2593 yAxis: xlRainYAxis(), 2594 tooltip: xlTooltip(hccompact_units['rain'], hccompact_units['rain'] == 'in' ? 2 : 1), 2595 credits: { enabled: false }, 2596 exporting: { enabled: false }, 2597 plotOptions: xlPlotOptions('rain2_graph'), 2598 series: xlSeries(hc_data_rain2, {column: true, stats: false /*, medianColor: xlColor('--hc-xl-median-rain', '#1B6FB5') */}), 2599 reflow: true 2600 }); 2601 } 2602 2603 if (typeof hc_data_accrain != 'undefined') { 2604 $('#accrain_graph').highcharts({ 2605 chart: { 2606 scrollablePlotArea: {minWidth: getMinWidth()}, 2607 className: (typeof hc_data_accrain_chartclass != 'undefined')?hc_data_accrain_chartclass:'', 2608 events: { 2609 load: function() { 2610 accrainContainerId = this.container.id; 2611 $( '#'+accrainContainerId+'.toggle-flags' ).tooltip({ 2612 content: function() { 2613 return "<img src='"+$(this).data('flagfile')+"' /><br /><span style='display: inline-block; color:#555; font-size: 13px; font-weight: bold; margin-top: 7px;'>"+$(this).data('longname')+"</span><br /><span style='color: #555; font-size:11px;'>"+$(this).data('run')+"</span>"; 2614 } 2615 }); 2616 //drawHourlyLabels(this,'xl'); 2617 drawNightShadows(this,18,'xl'); 2618 fixLabels(this,'xl'); 2619 }, 2620 redraw: function(){ 2621 //drawHourlyLabels(this,'xl'); 2622 drawNightShadows(this,18,'xl'); 2623 fixLabels(this,'xl'); 2624 } 2625 } 2626 }, 2627 title: 'false', 2628 legend: xlLegendWithFlag, 2629 responsive: xlChartOptions(xlAlleNumbers), 2630 xAxis: xlXAxisStandard, 2631 yAxis: xlRainYAxis(), 2632 tooltip: xlTooltip(hccompact_units['rain'], hccompact_units['rain'] == 'in' ? 2 : 1), 2633 credits: { enabled: false }, 2634 exporting: { enabled: false }, 2635 plotOptions: xlPlotOptions('accrain_graph'), 2636 series: xlSeries(hc_data_accrain, {smooth: false, monotone: true}), 2637 reflow: true 2638 }); 2639 } 2640 addGlobalChartScrollHint(document.querySelector('.tab-content')); 2641 buildXlLegends(); 2642}; 2643 2644/** 2645 * ============================================================================ 2646 * XL-Multimodell-Legende (Modellauswahl unter dem Meteogramm) 2647 * ============================================================================ 2648 * Gruppen: Regional / Global / KI / Multimodell / MOS. 2649 * 2650 * Designprinzip: EIN Zustand, EINE Wahrheit. 2651 * `xlSelection` ist eine flache Map `param -> bool` über ALLE bekannten 2652 * Modelle. Der Gruppen-Zustand wird nie gespeichert, sondern bei jedem
2653 * Render frisch daraus abgeleitet (all / none / mixed). Dadurch ist 2654 * "Nur diese Gruppe" lediglich ein Massen-Set auf dieselbe Map und 2655 * beliebig mit einzelnen Modell-Toggles kombinierbar. 2656 * 2657 * Alle Aktionen sind absolut (idempotent) - ein doppelt ausgelöstes Event 2658 * kann den Zustand daher nicht mehr "umklappen". 2659 */ 2660var XL_SEL_KEY = 'xlModelSelection.v2'; 2661var XL_TAB_KEY = 'xlModelTab.v1'; 2662 2663var xlSelection = null; // { GFS: true, ICON_D2: false, ... } 2664var xlDefaults = {}; // Server-Default (aus series.visible beim ersten Sehen) 2665var xlBound = false; // Event-Delegation nur EINMAL binden 2666var xlActiveTab = null; // aktiver Reiter der Modellauswahl 2667var xlGroupOrder = ['regional', 'global', 'mos', 'multimodel', 'ai']; 2668 2669/** 2670 * Reiter der Modellauswahl. 2671 * 2672 * WICHTIG: Die Reiter sind ein reiner ANSICHTSFILTER fuer die Chip-Liste. 2673 * Sie veraendern die Sichtbarkeit im Chart nicht - der Zustand bleibt beim 2674 * Reiterwechsel unangetastet, damit Modelle weiterhin frei ueber Gruppen 2675 * hinweg kombiniert werden koennen. 2676 * 2677 * Jede Modellgruppe bekommt einen eigenen Reiter. "Weitere" bleibt als 2678 * Auffangbecken fuer Gruppen, die hier (noch) nicht bekannt sind. 2679 */ 2680var xlTabOrder = ['all', 'regional', 'global', 'mos', 'multimodel', 'ai', 'other']; 2681 2682/** Gruppe -> Reiter. Unbekannte Gruppen landen automatisch unter "Weitere". */ 2683var xlTabOf = function (g) { 2684 if (g === 'regional') { return 'regional'; } 2685 if (g === 'global') { return 'global'; } 2686 if (g === 'mos') { return 'mos'; } 2687 if (g === 'multimodel') { return 'multimodel'; } 2688 if (g === 'ai') { return 'ai'; } 2689 return 'other'; 2690}; 2691 2692/** Fallback-Labels, falls der Server (xlLegendI18n) nichts geliefert hat. */ 2693var xlLegendFallback = { 2694 title: 'Modellauswahl', 2695 all: 'Alle anzeigen', 2696 only: 'Nur diese Gruppe', 2697 show: 'Alle einblenden', 2698 hide: 'Alle ausblenden', 2699 visible: '{visible} von {total} Modellen sichtbar', 2700 tabs: { 2701 all: 'Alle', 2702 regional: 'Regional', 2703 global: 'Global', 2704 mos: 'MOS', 2705 multimodel: 'Multi', 2706 ai: 'KI', 2707 other: 'Weitere' 2708 }, 2709 groups: { 2710 regional: { title: 'Regionale Modelle', color: '#2F8B78', colorDark: '#3FB29A' }, 2711 global: { title: 'Globale Modelle', color: '#C8641E', colorDark: '#F58132' }, 2712 mos: { title: 'MOS', color: '#0080D3', colorDark: '#0080D3' }, 2713 multimodel: { title: 'Multimodell', color: '#D54587', colorDark: '#D54587' }, 2714 ai: { title: 'KI-Modelle', color: '#A062C2', colorDark: '#A062C2' } 2715 } 2716}; 2717 2718var xlT = function (key) { 2719 var i18n = (typeof xlLegendI18n !== 'undefined' && xlLegendI18n) ? xlLegendI18n : {}; 2720 return i18n[key] || xlLegendFallback[key] || key; 2721}; 2722 2723var xlGroupMeta = function (g) { 2724 var i18n = (typeof xlLegendI18n !== 'undefined' && xlLegendI18n) ? xlLegendI18n : {}; 2725 var fromServer = (i18n.groups || {})[g]; 2726 var fallback = xlLegendFallback.groups[g] || { title: g, color: '#808080' }; 2727 var meta = (fromServer && fromServer.title) ? fromServer : fallback; 2728 // Im Darkmode die aufgehellte Variante als wirksame Farbe liefern, damit 2729 // die Aufrufer (Gruppenpunkt in der Legende) nichts davon wissen muessen. 2730 // `colorDark` kann beim Server fehlen (aelterer Cache-Stand) - dann greift 2731 // der lokale Fallback, sonst bliebe der Punkt im Darkmode zu dunkel. 2732 if (xlIsDark()) { 2733 var dark = (fromServer && fromServer.colorDark) || fallback.colorDark; 2734 if (dark) { meta = { title: meta.title, color: dark, colorDark: dark }; } 2735 } 2736 return meta; 2737}; 2738 2739var xlTabLabel = function (tabId) { 2740 var i18n = (typeof xlLegendI18n !== 'undefined' && xlLegendI18n) ? xlLegendI18n : {}; 2741 var fromServer = (i18n.tabs || {})[tabId]; 2742 return fromServer || xlLegendFallback.tabs[tabId] || tabId; 2743}; 2744 2745/** Aktiver Reiter ('' = alle zugeklappt). Ueberlebt Seitenwechsel. */ 2746var xlLoadTab = function () { 2747 if (xlActiveTab === null) { 2748 var stored = null; 2749 try { stored = localStorage.getItem(XL_TAB_KEY); } catch (e) {} 2750 // Default ist bewusst zugeklappt - die Modell-Liste ist lang und 2751 // soll die Seite nicht von vornherein aufblaehen. 2752 xlActiveTab = (stored && xlTabOrder.indexOf(stored) !== -1) ? stored : ''; 2753 } 2754 return xlActiveTab; 2755}; 2756 2757var xlSetTab = function (tabId) { 2758 // Erneuter Klick auf den offenen Reiter klappt ihn wieder zu. 2759 xlActiveTab = (tabId === xlActiveTab || xlTabOrder.indexOf(tabId) === -1) ? '' : tabId; 2760 try { localStorage.setItem(XL_TAB_KEY, xlActiveTab); } catch (e) {} 2761}; 2762 2763/** Serien-Metadaten robust auslesen (userOptions überlebt Updates, options nicht immer). */ 2764var xlSeriesParam = function (s) { 2765 var o = (s && (s.userOptions || s.options)) || {}; 2766 return o.param || null; 2767}; 2768var xlSeriesGroup = function (s) { 2769 var o = (s && (s.userOptions || s.options)) || {}; 2770 return o.group || 'global'; 2771}; 2772 2773/**
2774 * Nur die XL-Multimodell-Charts. `Highcharts.charts` ist global und enthält 2775 * auch Kompakt-/14-Tage-/Ensemble-Graphen - die dürfen wir NIE anfassen. 2776 * Erkennungsmerkmal: mindestens eine Serie trägt ein `param`. 2777 */ 2778var xlCharts = function () { 2779 if (typeof Highcharts === 'undefined' || !Highcharts.charts) { return []; } 2780 return Highcharts.charts.filter(function (c) { 2781 return c && c.series && c.series.length && c.series.some(xlSeriesParam); 2782 }); 2783}; 2784 2785/** Alle bekannten Params einer Gruppe (über alle XL-Charts hinweg). */ 2786var xlParamsOfGroup = function (g) { 2787 var out = {}; 2788 xlCharts().forEach(function (c) { 2789 c.series.forEach(function (s) { 2790 var p = xlSeriesParam(s); 2791 if (p && xlSeriesGroup(s) === g) { out[p] = true; } 2792 }); 2793 }); 2794 return Object.keys(out); 2795}; 2796 2797/** Gruppen -> Serien (erste Fundstelle je param) für das Rendern der Legende. */ 2798var xlCollectGroups = function () { 2799 var groups = {}; 2800 var seen = {}; 2801 xlCharts().forEach(function (c) { 2802 c.series.forEach(function (s) { 2803 var p = xlSeriesParam(s); 2804 if (!p || seen[p]) { return; } 2805 seen[p] = true; 2806 var g = xlSeriesGroup(s); 2807 if (!groups[g]) { groups[g] = []; } 2808 groups[g].push(s); 2809 }); 2810 }); 2811 return groups; 2812}; 2813 2814/** 2815 * Zustand laden. Defaults werden fortlaufend aus den Serien nachgezogen, 2816 * damit auch Modelle korrekt behandelt werden, die erst in einem später 2817 * nachgeladenen Tab/Chart auftauchen. 2818 */ 2819var xlLoadSelection = function () { 2820 var fresh = []; 2821 xlCharts().forEach(function (c) { 2822 c.series.forEach(function (s) { 2823 var p = xlSeriesParam(s); 2824 if (p && xlDefaults[p] === undefined) {
2825 // Wird immer VOR dem ersten xlApplySelection() aufgerufen, 2826 // s.visible entspricht hier also noch dem Server-Default. 2827 xlDefaults[p] = s.visible !== false; 2828 fresh.push(p); 2829 } 2830 }); 2831 }); 2832 2833 var stored = {}; 2834 try { stored = JSON.parse(localStorage.getItem(XL_SEL_KEY) || '{}'); } catch (e) { stored = {}; } 2835 2836 if (!xlSelection) { 2837 xlSelection = {}; 2838 Object.keys(xlDefaults).forEach(function (p) { 2839 xlSelection[p] = (typeof stored[p] === 'boolean') ? stored[p] : xlDefaults[p]; 2840 }); 2841 } else { 2842 // Neu aufgetauchte Modelle ergänzen, bestehende Auswahl nicht anfassen. 2843 fresh.forEach(function (p) { 2844 if (xlSelection[p] === undefined) { 2845 xlSelection[p] = (typeof stored[p] === 'boolean') ? stored[p] : xlDefaults[p]; 2846 } 2847 }); 2848 } 2849 return xlSelection; 2850}; 2851 2852/** 2853 * Zentraler Schreibpfad: Patch anwenden -> Guard -> persistieren -> 2854 * Charts spiegeln (inkl. redraw) -> Legenden neu rendern. 2855 * `patch` ist eine Map `param -> bool`; null bedeutet "nur spiegeln". 2856 */ 2857var xlApplySelection = function (patch) { 2858 var sel = xlLoadSelection(); 2859 2860 if (patch) { 2861 Object.keys(patch).forEach(function (p) { 2862 if (sel[p] !== undefined) { sel[p] = !!patch[p]; } 2863 }); 2864 } 2865 2866 // Guard: niemals alles ausblenden -> auf Server-Default zurückfallen. 2867 var anyVisible = Object.keys(sel).some(function (p) { return sel[p]; }); 2868 if (!anyVisible) { 2869 Object.keys(sel).forEach(function (p) { sel[p] = !!xlDefaults[p]; }); 2870 if (!Object.keys(sel).some(function (p) { return sel[p]; })) { 2871 Object.keys(sel).forEach(function (p) { sel[p] = true; }); 2872 } 2873 } 2874 2875 try { localStorage.setItem(XL_SEL_KEY, JSON.stringify(sel)); } catch (e) {} 2876 2877 xlCharts().forEach(function (c) { 2878 var dirty = false; 2879 c.series.forEach(function (s) { 2880 var p = xlSeriesParam(s); 2881 if (!p || sel[p] === undefined) { return; } // fremde Serien: nie anfassen 2882 if (s.visible !== sel[p]) { 2883 s.setVisible(sel[p], false); 2884 dirty = true; 2885 } 2886 }); 2887 // Median/Band beziehen sich immer auf die AKTUELL sichtbaren Modelle. 2888 if (xlRefreshAggregates(c)) { dirty = true; } 2889 // Ohne redraw bleiben die Y-Achsen auf den ausgeblendeten Extremwerten stehen. 2890 if (dirty) { c.redraw(); } 2891 }); 2892 2893 xlRenderLegends(); 2894 xlRenderStats(); 2895}; 2896 2897/** 2898 * Params je Gruppe in EINEM Durchlauf - vermeidet das mehrfache Iterieren 2899 * über alle Charts/Serien beim Rendern. 2900 */ 2901var xlParamsByGroup = function () { 2902 var out = {}; 2903 var seen = {}; 2904 xlCharts().forEach(function (c) { 2905 c.series.forEach(function (s) { 2906 var p = xlSeriesParam(s); 2907 if (!p || seen[p]) { return; } 2908 seen[p] = true; 2909 var g = xlSeriesGroup(s); 2910 if (!out[g]) { out[g] = []; } 2911 out[g].push(p); 2912 }); 2913 }); 2914 return out; 2915}; 2916 2917/** Abgeleiteter Gruppen-Zustand: 'all' | 'none' | 'mixed'. */ 2918var xlStateOf = function (params, sel) { 2919 var known = (params || []).filter(function (p) { return sel[p] !== undefined; }); 2920 if (!known.length) { return 'none'; } 2921 var on = known.filter(function (p) { return sel[p]; }).length; 2922 if (on === 0) { return 'none'; } 2923 if (on === known.length) { return 'all'; } 2924 return 'mixed'; 2925}; 2926 2927var xlGroupState = function (g) { 2928 return xlStateOf(xlParamsOfGroup(g), xlLoadSelection()); 2929}; 2930 2931/* --------------------------------------------------------------------------- 2932 * Aktionen - liefern jeweils einen absoluten Patch (idempotent). 2933 * ------------------------------------------------------------------------- */ 2934var xlActions = { 2935 all: function () { 2936 var p = {}; 2937 Object.keys(xlLoadSelection()).forEach(function (k) { p[k] = true; }); 2938 return p; 2939 }, 2940 only: function (g) { 2941 var p = {}; 2942 var inGroup = {}; 2943 xlParamsOfGroup(g).forEach(function (k) { inGroup[k] = true; });
2944 Object.keys(xlLoadSelection()).forEach(function (k) { p[k] = !!inGroup[k]; }); 2945 return p; 2946 }, 2947 groupSet: function (g, on) { 2948 var p = {}; 2949 xlParamsOfGroup(g).forEach(function (k) { p[k] = !!on; }); 2950 return p; 2951 }, 2952 toggle: function (param) { 2953 var p = {}; 2954 p[param] = !xlLoadSelection()[param]; 2955 return p; 2956 } 2957}; 2958 2959/* --------------------------------------------------------------------------- 2960 * Rendern - baut/aktualisiert ausschliesslich DOM, bindet KEINE Listener. 2961 * ------------------------------------------------------------------------- */ 2962var xlEsc = function (str) { 2963 return String(str == null ? '' : str) 2964 .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') 2965 .replace(/"/g, '"').replace(/'/g, '''); 2966}; 2967 2968/* --------------------------------------------------------------------------- 2969 * Hover-Hervorhebung: Chip in der Modellauswahl -> zugehoerige Linie betonen. 2970 * ------------------------------------------------------------------------- */ 2971 2972/** Aktuell hervorgehobener Param (null = kein Hover). */ 2973var xlHoverParam = null; 2974/** Restdeckkraft der NICHT gehoverten Modelle (relativ zur Grunddeckkraft). */ 2975var XL_HOVER_DIM = 0.22; 2976/** Zusaetzliche Linienstaerke der gehoverten Serie. */ 2977var XL_HOVER_LINE_PLUS = 1.5; 2978/** Faktor, um den der gehoverte Balken (Niederschlag) breiter wird. */ 2979var XL_HOVER_BAR_SCALE = 2.2; 2980 2981/** 2982 * Saeulenserien haben keine Linienstaerke, die man betonen koennte - dort 2983 * wird stattdessen der Balken verbreitert (mittig, damit er ueber dem 2984 * gleichen Zeitpunkt stehen bleibt). 2985 * 2986 * Die Ausgangsmasse kommen aus `shapeArgs`, das Highcharts bei jedem Redraw 2987 * neu berechnet - dadurch kann kein veralteter Cachewert die Balken nach 2988 * einem Resize verzerren. 2989 */ 2990var xlColumnEmphasis = function (s, on) { 2991 if (!s || !s.points) { return; } 2992 2993 // Der verbreiterte Balken ueberlappt die Nachbarn. Damit er nicht unter 2994 // spaeter gezeichneten Serien verschwindet, wandert die Gruppe im DOM 2995 // nach vorn - die Ausgangsposition wird gemerkt und exakt 2996 // wiederhergestellt, damit die Zeichenreihenfolge unveraendert bleibt. 2997 var el = s.group && s.group.element; 2998 if (el && el.parentNode) { 2999 if (on) { 3000 if (!s.xlDomAnchor) { 3001 s.xlDomAnchor = { parent: el.parentNode, next: el.nextSibling }; 3002 el.parentNode.appendChild(el); 3003 } 3004 } else if (s.xlDomAnchor) { 3005 var a = s.xlDomAnchor; 3006 s.xlDomAnchor = null; 3007 if (a.parent === el.parentNode) { 3008 var next = (a.next && a.next.parentNode === a.parent) ? a.next : null; 3009 a.parent.insertBefore(el, next); 3010 } 3011 } 3012 } 3013 3014 s.points.forEach(function (pt) { 3015 var g = pt && pt.graphic; 3016 var sa = pt && pt.shapeArgs; 3017 if (!g || !sa || !sa.width) { return; } 3018 if (!on) { 3019 g.attr({ width: sa.width, x: sa.x }); 3020 return; 3021 } 3022 // Sehr schmale Balken (lange Zeitraeume) wuerden rein multiplikativ 3023 // kaum sichtbar wachsen - daher zusaetzlich ein absoluter Zuschlag. 3024 var w = Math.max(sa.width * XL_HOVER_BAR_SCALE, sa.width + 3); 3025 g.attr({ width: w, x: sa.x - (w - sa.width) / 2 }); 3026 }); 3027}; 3028 3029/** 3030 * Hebt EIN Modell in allen XL-Charts hervor; `null` stellt den Normalzustand 3031 * wieder her. 3032 * 3033 * Bewusst ueber die SVG-Attribute statt ueber `series.update()`: 3034 * Letzteres wuerde die Serie neu aufbauen und einen Redraw ausloesen - bei 3035 * ~15 Serien x 4 Charts waere das bei jeder Mausbewegung viel zu teuer. 3036 * Das Unsicherheitsband bleibt als Kontext stehen, die Medianlinie wird 3037 * mitgedimmt, damit sie das hervorgehobene Modell nicht ueberstrahlt. 3038 */ 3039var xlHighlight = function (param) { 3040 if (xlHoverParam === param) { return; } 3041 xlHoverParam = param; 3042 3043 xlCharts().forEach(function (c) { 3044 (c.series || []).forEach(function (s) { 3045 var p = xlSeriesParam(s); 3046 var o = (s.userOptions || s.options) || {}; 3047 3048 // Die Medianlinie ist die kraeftigste Linie im Chart und wuerde 3049 // das hervorgehobene Modell sonst ueberstrahlen - sie wird 3050 // mitgedimmt. Das Band bleibt als Kontext stehen. 3051 if (!p && o.xlRole === 'median' && s.visible && s.group) { 3052 s.group.attr({ opacity: (param === null) ? 1 : XL_HOVER_DIM }); 3053 if (s.markerGroup) { s.markerGroup.attr({ opacity: (param === null) ? 1 : XL_HOVER_DIM }); } 3054 return; 3055 } 3056 3057 if (!p || !s.visible || !s.group) { return; } 3058 3059 var baseOpacity = (typeof o.opacity === 'number') ? o.opacity : 1; 3060 var baseWidth = (typeof o.lineWidth === 'number') ? o.lineWidth : 2; 3061 var isHovered = (param !== null && p === param); 3062 3063 var opacity = baseOpacity; 3064 if (param !== null) { 3065 opacity = isHovered ? 1 : (baseOpacity * XL_HOVER_DIM); 3066 } 3067 3068 s.group.attr({ opacity: opacity }); 3069 if (s.markerGroup) { s.markerGroup.attr({ opacity: opacity }); } 3070 // Saeulenserien (Niederschlag) haben keinen `graph`. 3071 if (s.graph) { 3072 s.graph.attr({ 'stroke-width': isHovered ? (baseWidth + XL_HOVER_LINE_PLUS) : baseWidth }); 3073 } else if (s.type === 'column') { 3074 xlColumnEmphasis(s, isHovered); 3075 } 3076 }); 3077 }); 3078}; 3079
3080var xlRenderLegends = function () { 3081 var legends = document.querySelectorAll('.xl-legend'); 3082 if (!legends.length) { return; } 3083 3084 // Das Neuschreiben der Chips laesst kein `mouseout` mehr feuern - der 3085 // Hover-Zustand muss deshalb hier zurueckgesetzt werden. 3086 xlHighlight(null); 3087 3088 var sel = xlLoadSelection(); 3089 var groups = xlCollectGroups(); 3090 var paramsByGroup = xlParamsByGroup(); 3091 if (!Object.keys(sel).length) { return; } 3092 3093 // Gruppenzustände einmal vorberechnen (statt pro Gruppe erneut alle 3094 // Charts zu durchlaufen). 3095 var states = {}; 3096 Object.keys(paramsByGroup).forEach(function (g) { 3097 states[g] = xlStateOf(paramsByGroup[g], sel); 3098 }); 3099 var visibleGroups = Object.keys(states).filter(function (g) { 3100 return states[g] !== 'none'; 3101 }); 3102 3103 var allOn = Object.keys(sel).every(function (p) { return sel[p]; }); 3104 var totalCount = Object.keys(sel).length; 3105 var visibleCount = Object.keys(sel).filter(function (p) { return sel[p]; }).length; 3106 3107 // Bekannte Gruppen in fester Reihenfolge, unbekannte hinten anhängen. 3108 var order = xlGroupOrder.slice(); 3109 Object.keys(groups).forEach(function (g) { 3110 if (order.indexOf(g) === -1) { order.push(g); } 3111 }); 3112 var presentGroups = order.filter(function (g) { 3113 return groups[g] && groups[g].length; 3114 }); 3115 3116 // Reiter nur anbieten, wenn sie tatsaechlich Gruppen enthalten. 3117 var tabGroups = {}; 3118 presentGroups.forEach(function (g) { 3119 var t = xlTabOf(g); 3120 if (!tabGroups[t]) { tabGroups[t] = []; } 3121 tabGroups[t].push(g); 3122 }); 3123 tabGroups.all = presentGroups.slice(); 3124 3125 var tabs = xlTabOrder.filter(function (t) { 3126 return tabGroups[t] && tabGroups[t].length; 3127 }); 3128 // Ein einzelner Sachgruppen-Reiter neben "Alle" waere redundant. 3129 if (tabs.length <= 2) { tabs = ['all']; } 3130 3131 // '' bedeutet zugeklappt und ist der Startzustand. 3132 var activeTab = xlLoadTab(); 3133 if (activeTab && tabs.indexOf(activeTab) === -1) { activeTab = ''; xlSetTab(''); } 3134 3135 // Modellbezogene Hinweise (z.B. MOS-Standortangaben) liegen als Geschwister 3136 // der Legende im Markup. Sie werden in den Reiter-Inhalt der zugehoerigen 3137 // Gruppe gezogen, damit sie dort stehen, wo das Modell ausgewaehlt wird. 3138 // Das Markup ist in jedem Chart-Tab identisch -> erstes Vorkommen genuegt. 3139 var notes = {}; 3140 document.querySelectorAll('.xl-legend-note[data-group]').forEach(function (el) { 3141 var g = el.getAttribute('data-group'); 3142 if (g && notes[g] === undefined) { notes[g] = el.innerHTML; } 3143 el.classList.add('is-moved'); 3144 }); 3145 3146 var html = ''; 3147 html += '<div class="xl-legend-global">'; 3148 html += '<span class="xl-legend-global-name">' + xlEsc(xlT('title')) + '</span>'; 3149 html += '<span class="xl-legend-count' + (allOn ? '' : ' is-reduced') + '">' + 3150 xlEsc(String(xlT('visible')).replace('{visible}', visibleCount).replace('{total}', totalCount)) + 3151 '</span>'; 3152 html += '<button type="button" class="xl-legend-global-toggle' + (allOn ? ' is-disabled' : '') + '">' + xlEsc(xlT('all')) + '</button>'; 3153 html += '</div>'; 3154 3155 // Reiterleiste: filtert ausschliesslich die Chip-Liste, nie den Chart. 3156 // Jeder Reiter ist auf-/zuklappbar; ein Zaehler erscheint nur dort, wo 3157 // tatsaechlich Modelle ausgeblendet sind - so muss man sich nicht durch 3158 // die Reiter klicken, um das zu sehen. 3159 html += '<div class="xl-legend-tabs" role="tablist">';
3160 tabs.forEach(function (t) { 3161 var params = {}; 3162 tabGroups[t].forEach(function (g) { 3163 (paramsByGroup[g] || []).forEach(function (p) { 3164 if (sel[p] !== undefined) { params[p] = true; } 3165 }); 3166 }); 3167 var keys = Object.keys(params); 3168 var on = keys.filter(function (p) { return sel[p]; }).length; 3169 var partial = on < keys.length; 3170 var isActive = (t === activeTab); 3171 3172 html += '<button type="button" class="xl-legend-tab' + (isActive ? ' is-active' : '') + '"' + 3173 ' data-tab="' + xlEsc(t) + '" role="tab" aria-expanded="' + (isActive ? 'true' : 'false') + '">'; 3174 html += '<span class="xl-legend-tab-name">' + xlEsc(xlTabLabel(t)) + '</span>'; 3175 html += '<span class="xl-legend-tab-count">(' + 3176 (partial ? (on + '/' + keys.length) : keys.length) + ')</span>'; 3177 html += '<span class="xl-legend-tab-arrow" aria-hidden="true"></span>'; 3178 html += '</button>'; 3179 }); 3180 html += '</div>'; 3181 3182 if (!activeTab) { 3183 legends.forEach(function (el) { 3184 if (el.innerHTML !== html) { el.innerHTML = html; } 3185 }); 3186 return; 3187 } 3188 3189 html += '<div class="xl-legend-groups">'; 3190 3191 presentGroups.forEach(function (g) { 3192 // Reiterfilter: nur die Gruppen des aktiven Reiters rendern. 3193 if (tabGroups[activeTab].indexOf(g) === -1) { return; } 3194 3195 var series = groups[g]; 3196 var meta = xlGroupMeta(g); 3197 var state = states[g] || 'none'; 3198 // Einzige Gruppe mit sichtbaren Modellen -> "Alle ausblenden" würde 3199 // den Graphen leeren und ist daher gesperrt. 3200 var soloGroup = state !== 'none' && visibleGroups.length === 1; 3201 3202 html += '<div class="xl-legend-group is-' + state + '" data-group="' + xlEsc(g) + '">'; 3203 html += '<div class="xl-legend-group-head">'; 3204 html += '<span class="xl-legend-group-dot" style="background:' + xlEsc(meta.color || '#808080') + '"></span>'; 3205 html += '<span class="xl-legend-group-name">' + xlEsc(meta.title || g) + '</span>'; 3206 // "Nur diese Gruppe" ist sinnlos, wenn die Gruppe schon exklusiv sichtbar ist. 3207 html += '<button type="button" class="xl-legend-group-only' + ((state === 'all' && soloGroup) ? ' is-disabled' : '') + '">' + xlEsc(xlT('only')) + '</button>'; 3208 if (state === 'none') { 3209 html += '<button type="button" class="xl-legend-group-toggle" data-on="1">' + xlEsc(xlT('show')) + '</button>'; 3210 } else { 3211 // Ausblenden nur erlauben, wenn danach noch eine andere Gruppe sichtbar bleibt. 3212 html += '<button type="button" class="xl-legend-group-toggle' + (soloGroup ? ' is-disabled' : '') + '" data-on="0">' + xlEsc(xlT('hide')) + '</button>'; 3213 } 3214 html += '</div>'; 3215 3216 html += '<div class="xl-legend-items">'; 3217 series.forEach(function (s) { 3218 var p = xlSeriesParam(s); 3219 if (!p || sel[p] === undefined) { return; } 3220 var o = s.userOptions || s.options || {}; 3221 var run = o.run || ''; 3222 var tip = (o.longname || s.name || p) + (run ? ' \u2014 ' + run : ''); 3223 html += '<button type="button" class="xl-legend-item' + (sel[p] ? '' : ' is-hidden') + '"' + 3224 ' data-param="' + xlEsc(p) + '"' + 3225 ' aria-pressed="' + (sel[p] ? 'true' : 'false') + '"' + 3226 ' title="' + xlEsc(tip) + '">'; 3227 html += '<span class="xl-legend-swatch" style="background:' + xlEsc(s.color || o.color || '#888888') + '"></span>'; 3228 html += '<span class="xl-legend-name">' + xlEsc(s.name || p) + '</span>'; 3229 html += '</button>'; 3230 }); 3231 html += '</div>'; 3232 if (notes[g]) { 3233 html += '<div class="xl-legend-group-note">' + notes[g] + '</div>'; 3234 } 3235 html += '</div>'; 3236 }); 3237 3238 html += '</div>'; 3239 3240 // Identisches Markup für alle Legenden - der Zustand ist global. 3241 legends.forEach(function (el) { 3242 if (el.innerHTML !== html) { el.innerHTML = html; } 3243 }); 3244}; 3245 3246/** 3247 * Einstiegspunkt: nach jedem (Neu-)Aufbau der Charts aufrufen. 3248 * Spiegelt den gespeicherten Zustand auf alle Charts und rendert die Legenden. 3249 */ 3250var buildXlLegends = function () { 3251 if (!document.querySelector('.xl-legend')) { return; } 3252 xlLoadSelection(); 3253 xlApplySelection(null); 3254 3255 if (!xlBound) { 3256 xlBound = true; 3257 3258 // Tabwechsel: Highcharts kennt die Grösse eines versteckten Charts 3259 // nicht, deshalb nach dem Einblenden Zustand + Legende nachziehen. 3260 $(document).on('shown.bs.tab', '.graphtab', function () { 3261 setTimeout(function () { 3262 if (document.querySelector('.xl-legend')) { 3263 xlApplySelection(null); 3264 } 3265 }, 50); 3266 }); 3267 3268 // EIN delegierter Listener auf document - übersteht jedes innerHTML 3269 // und jeden Tabwechsel, kann also nicht mehr mehrfach binden.
3270 // `mouseover` (nicht `mouseenter`) blubbert bis zum document hoch und 3271 // feuert auch ausserhalb der Legende - ein separates `mouseout` 3272 // braucht es deshalb nicht: jede Bewegung neben einen Chip raeumt auf. 3273 document.addEventListener('mouseover', function (e) { 3274 var item = e.target.closest ? e.target.closest('.xl-legend-item') : null; 3275 // Ausgeblendete Modelle haben keine Linie, die man betonen koennte. 3276 if (item && !item.classList.contains('is-hidden')) { 3277 xlHighlight(item.getAttribute('data-param')); 3278 } else if (xlHoverParam !== null) { 3279 xlHighlight(null); 3280 } 3281 }); 3282 3283 document.addEventListener('click', function (e) { 3284 var root = e.target.closest ? e.target.closest('.xl-legend') : null; 3285 if (!root) { return; } 3286 if (e.target.closest('.is-disabled')) { return; } 3287 3288 var item = e.target.closest('.xl-legend-item'); 3289 if (item) { 3290 xlApplySelection(xlActions.toggle(item.getAttribute('data-param'))); 3291 return; 3292 } 3293 // Reiterwechsel ist ein reiner Ansichtswechsel: NICHT ueber 3294 // xlApplySelection laufen lassen, sonst wuerden alle Charts 3295 // unnoetig neu gezeichnet. 3296 var tab = e.target.closest('.xl-legend-tab'); 3297 if (tab) { 3298 xlSetTab(tab.getAttribute('data-tab')); 3299 xlRenderLegends(); 3300 return; 3301 } 3302 if (e.target.closest('.xl-legend-global-toggle')) { 3303 xlApplySelection(xlActions.all()); 3304 return; 3305 } 3306 var grpEl = e.target.closest('.xl-legend-group'); 3307 if (!grpEl) { return; } 3308 var g = grpEl.getAttribute('data-group'); 3309 if (e.target.closest('.xl-legend-group-only')) { 3310 xlApplySelection(xlActions.only(g)); 3311 return; 3312 } 3313 var toggle = e.target.closest('.xl-legend-group-toggle'); 3314 if (toggle) { 3315 xlApplySelection(xlActions.groupSet(g, toggle.getAttribute('data-on') === '1')); 3316 } 3317 }); 3318 } 3319}; 3320 3321/** 3322 * Statistikzeile unter dem Plot: erklaert die drei visuellen Ebenen und 3323 * verdichtet die Kernaussage ("N Modelle, Median X, Spannweite Y-Z"). 3324 * Wird aus den bereits berechneten Aggregatserien gespeist - keine 3325 * zusaetzliche Statistik, keine zusaetzlichen Daten. 3326 */ 3327var xlRenderStats = function () { 3328 var nodes = document.querySelectorAll('.xl-stats'); 3329 if (!nodes.length || typeof Highcharts === 'undefined') { return; } 3330 3331 Array.prototype.forEach.call(nodes, function (el) { 3332 var id = el.getAttribute('data-chart'); 3333 var holder = id ? document.getElementById(id) : null; 3334 var chart = (holder && $(holder).highcharts) ? $(holder).highcharts() : null; 3335 if (!chart || !chart.series) { el.innerHTML = ''; return; } 3336 3337 var ttOpts = (chart.options && chart.options.tooltip) || {}; 3338 var unit = (ttOpts.valueSuffix || '').trim(); 3339 var digits = (typeof ttOpts.xlDigits === 'number') ? ttOpts.xlDigits : 1; 3340 var nf = function (v) { return Highcharts.numberFormat(v, digits); }; 3341 3342 var models = chart.series.filter(function (s) { return xlSeriesParam(s) && s.visible; }); 3343 var median = null; 3344 var band = null; 3345 chart.series.forEach(function (s) { 3346 var role = xlSeriesRole(s); 3347 if (role === 'median') { median = s; } 3348 else if (role === 'band') { band = s; } 3349 }); 3350 3351 var html = '<div class="xl-stats-keys">'; 3352 html += '<span class="xl-stats-key">' + 3353 '<span class="xl-stats-swatch xl-stats-swatch-models"></span>' + 3354 '<span class="xl-stats-label">' + xlEsc(xlStatsT('models')) + '</span></span>'; 3355 3356 if (median && median.visible) { 3357 html += '<span class="xl-stats-key">' + 3358 '<span class="xl-stats-swatch xl-stats-swatch-median" style="background:' + 3359 xlEsc(median.color) + '"></span>' + 3360 '<span class="xl-stats-label">' + xlEsc(xlStatsT('median')) + '</span></span>'; 3361 } 3362 if (band && band.visible) { 3363 html += '<span class="xl-stats-key">' + 3364 '<span class="xl-stats-swatch xl-stats-swatch-band" style="background:' + 3365 xlEsc(band.color) + '"></span>' + 3366 '<span class="xl-stats-label">' + xlEsc(xlStatsT('band')) + 3367 ' <span class="xl-stats-sub">(' + xlEsc(xlStatsT('bandhint')) + ')</span></span></span>'; 3368 } 3369 html += '</div>'; 3370 3371 // Kennzahlen (Modellanzahl / Median / Spannweite) vorerst ausgeblendet: 3372 // Die Modellanzahl steht bereits neben der Ueberschrift "Modellauswahl", 3373 // der Median ist als Linie im Chart erkennbar. Bei Bedarf reaktivieren. 3374 /* 3375 var vals = []; 3376 if (median && median.visible && median.type !== 'column') {
3377 xlRawPoints(median).forEach(function (p) { 3378 var y = Array.isArray(p) ? p[1] : p.y; 3379 if (typeof y === 'number' && isFinite(y)) { vals.push(y); } 3380 }); 3381 } 3382 if (vals.length) { 3383 var sorted = vals.slice().sort(function (a, b) { return a - b; }); 3384 html += '<div class="xl-stats-figures">' + 3385 '<b>' + models.length + ' ' + xlEsc(xlStatsT('count')) + '</b>' + 3386 '<span class="xl-stats-sep">|</span>' + 3387 xlEsc(xlStatsT('median')) + ' ' + nf(xlQuantile(sorted, 0.5)) + ' ' + xlEsc(unit) + 3388 '<span class="xl-stats-sep">|</span>' + 3389 xlEsc(xlStatsT('range')) + ' ' + nf(sorted[0]) + ' â ' + nf(sorted[sorted.length - 1]) + ' ' + xlEsc(unit) + 3390 '</div>'; 3391 } 3392 */ 3393 3394 // Stattdessen steht hier der Hinweis zur Zeitzone - er gehoert 3395 // inhaltlich zur Zeitachse direkt darueber. 3396 var xlStats18n = (typeof xlLegendI18n !== 'undefined' && xlLegendI18n && xlLegendI18n.stats) || {}; 3397 var tz = xlStats18n.timezone || ''; 3398 var tzShort = xlStats18n.timezoneshort || tz; 3399 if (tz) { 3400 html += '<div class="xl-stats-timezone">' + 3401 '<span class="out-xs">' + xlEsc(tz) + '</span>' + 3402 '<span class="in-xs">' + xlEsc(tzShort) + '</span>' + 3403 '</div>'; 3404 } 3405 3406 if (el.innerHTML !== html) { el.innerHTML = html; } 3407 }); 3408}; 3409 3410var drawSingleArrow = function (speed) { 3411 3412 if (speed === 0) { 3413 return []; 3414 } 3415 3416 var length = speed < 100 ? 10 : 11 3417 var triangleOffset = speed < 100 ? 4 : 3; 3418 var lineOffset = speed < 150 ? 3 : 2; 3419 3420 var path = [ 3421 'M', 0, 7, // base of arrow 3422 'L', -1.5, 7, 3423 0, length, 3424 1.5, 7, 3425 0, 7, 3426 0, length * -1 // top 3427 ]; 3428 3429 var triangleCount = Math.floor(speed / 50); 3430 var longLineCount = Math.floor((speed % 50) / 10); 3431 var shortLineCount = Math.floor((speed % 10) / 5); 3432 3433 var offset = length * -1; 3434 3435 for (var i = 0; i < triangleCount; i++) { 3436 path.push('M', 0, offset, 'L', 7, offset, 'L', 0, offset + 2); // triangle 3437 offset += triangleOffset; 3438 } 3439 3440 for (var i = 0; i < longLineCount; i++) { 3441 path.push('M', 0, offset, 'L', 7, offset); // long line 3442 offset += lineOffset; 3443 } 3444 3445 for (var i = 0; i < shortLineCount; i++) { 3446 path.push('M', 0, offset, 'L', 4, offset); // short line 3447 offset += 3; 3448 } 3449 3450 return path; 3451}; 3452 3453var highcharts_arrows=[]; 3454var highcharts_plottype; 3455 3456var drawWindArrowsVH = function (chart, plot) { 3457 if (typeof vhstation_wind_data_dir === 'undefined') return; 3458 if (vhstation_wind_data_dir.length == 0) return; 3459 3460 $.each(highcharts_arrows, function (i, arrow) { arrow.destroy(); }); 3461 3462 highcharts_arrows=[]; 3463 highcharts_plottype=plot; 3464 3465 var lastX = false; 3466 3467 $.each(chart.series[0].data, function (i, point) { 3468 3469 var arrow, x, y; 3470 // Draw the wind arrows 3471 x = point.plotX + chart.plotLeft; 3472 y = chart.plotTop + chart.plotHeight + 20; 3473 3474 if(vhstation_wind_data_ws[i] == 0) 3475 return; 3476 3477 arrow = chart.renderer.path( 3478 drawSingleArrow(vhstation_wind_data_ws[i]) 3479 ).attr({ 3480 rotation: vhstation_wind_data_dir[i], 3481 translateX: x, // rotation center 3482 translateY: y // rotation center 3483 }); 3484 arrow.attr({ 3485 stroke: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black', 3486 'stroke-width': 1.5, 3487 zIndex: 5 3488 }); 3489 arrow.add(); 3490 3491 //Check if arrow should be drawn 3492 if(highcharts_arrows.length > 0 && lastX !== false) { 3493 3494 var lastDrawnIndex = highcharts_arrows.length-1; 3495 3496 var lastWidth = highcharts_arrows[lastDrawnIndex].getBBox().width; 3497 var nowWidth = arrow.getBBox().width; 3498 3499 var combinedWidth = lastWidth / 2 + nowWidth / 2; 3500 3501 if(15 > point.plotX - lastX) { 3502 arrow.destroy(); 3503 return; 3504 } 3505 3506 } 3507 3508 highcharts_arrows.push(arrow); 3509 lastX = point.plotX; 3510 3511 }); 3512 3513}; 3514 3515 3516var drawWindArrows = function (chart, plot) { 3517 if (typeof hccompact_data_direction === 'undefined') return; 3518 3519 $.each(highcharts_arrows, function (i, arrow) { arrow.destroy(); }); 3520 highcharts_arrows=[]; 3521 highcharts_plottype=plot; 3522 3523 var lastX = false;
3524 3525 $.each(chart.series[0].data, function (i, point) { 3526 var arrow, x, y; 3527 3528 3529 // Draw the wind arrows 3530 x = point.plotX + chart.plotLeft; 3531 y = 124; 3532 if(highcharts_plottype=="landing") { y = 278; } 3533 3534 //console.log({compact_interval: compact_interval, h_utc: h_utc, i: i, speed: hccompact_data_windarr[i], first_series_obj: chart.series[0].data[i]}); 3535 3536 if(hccompact_data_windarr[i] == 0) 3537 return; 3538 3539 arrow = chart.renderer.path( 3540 drawSingleArrow(hccompact_data_windarr[i]) 3541 ).attr({ 3542 rotation: hccompact_data_direction[i], 3543 translateX: x, // rotation center 3544 translateY: y // rotation center 3545 }); 3546 arrow.attr({ 3547 stroke: (Highcharts.theme && Highcharts.theme.contrastTextColor) ||cssVar('--hc-windArrows'), 3548 'stroke-width': 1.5, 3549 zIndex: 5 3550 }); 3551 arrow.add(); 3552 3553 //Check if arrow should be drawn 3554 if(highcharts_arrows.length > 0 && lastX !== false) { 3555 3556 var lastDrawnIndex = highcharts_arrows.length-1; 3557 3558 var lastWidth = highcharts_arrows[lastDrawnIndex].getBBox().width; 3559 var nowWidth = arrow.getBBox().width; 3560 3561 var combinedWidth = lastWidth / 2 + nowWidth / 2; 3562 3563 if(15 > point.plotX - lastX) { 3564 arrow.destroy(); 3565 return; 3566 } 3567 3568 //console.log({lastBoundingBox: { x: lastX, width: highcharts_arrows[lastDrawnIndex].getBBox().width }, nowBoundingBox: { x: point.plotX, width: arrow.getBBox().width }}); 3569 3570 } 3571 3572 highcharts_arrows.push(arrow); 3573 lastX = point.plotX; 3574 3575 }); 3576}; 3577 3578var highcharts_blocks=[]; 3579var drawBlocksForWindArrows = function (chart) { 3580 $.each(highcharts_blocks, function (i, line) {line.destroy();}); 3581 highcharts_blocks=[]; 3582 3583 var xAxis = chart.xAxis[0],x,pos,max,isLong,isLast,i,line; 3584 pos = xAxis.min; 3585 max = xAxis.max; 3586 3587 for (i = 0; pos < max ; pos += 36e5, i += 1) { 3588 // Get the X position 3589 isLast = pos === max + 36e5; 3590 x = Math.round(xAxis.toPixels(pos)-3); 3591 3592 isLong = (i+moment.tz(timezone_id).utcOffset()/60) % compact_interval === 0; 3593 3594 line=chart.renderer.path(['M', x, chart.plotTop + chart.plotHeight + (isLong ? 0 : 24), 'L', x, chart.plotTop + chart.plotHeight + 24, 'Z']) 3595 .attr({ 'stroke' : chart.options.chart.plotBorderColor, 'stroke-width': 1 }); 3596 line.add(); 3597 highcharts_blocks.push(line); 3598 } 3599}; 3600 3601var highcharts_nightshadows=[]; 3602var drawNightShadows=function(chart,plot,variant) { 3603 if(typeof highcharts_nightshadows[plot]!='undefined') { 3604 $.each(highcharts_nightshadows[plot], function (i, symbol) {symbol.destroy();}); 3605 } 3606 highcharts_nightshadows[plot]=[]; 3607 3608 // 'xl': deutlich dezentere Toenung, damit die Nacht nicht mehr als grosser 3609 // grauer Block mit den Datenlinien konkurriert. 3610 var shade = (variant === 'xl') 3611 ? cssVar('--hc-xl-night', '#F4F6F8') 3612 : cssVar('--hc-night_shadows'); 3613 3614 var xAxis = chart.xAxis[0]; 3615 var x1,x2,y,pos,max,i,h,interval; 3616 3617 pos = (xAxis.min)-(xAxis.min)%(24*36e5); 3618 max = (xAxis.max)+moment.tz(xAxis.max,timezone_id).utcOffset()/60*36e5; 3619 var sunset = 4; 3620 var sunrise = 5; 3621 if (typeof hclanding_sunrise !== 'undefined') { 3622 sunrise = parseInt(hclanding_sunrise); 3623 } 3624 if (typeof hclanding_sunset !== 'undefined') { 3625 sunset = parseInt(hclanding_sunset); 3626 } 3627 for (i = 0; pos <= max+24*36e5; pos += 24*36e5, i += 1) { 3628 // Get the X position 3629 x1 = Math.round(xAxis.toPixels(pos-sunset*36e5-moment.tz(pos-sunset*36e5,timezone_id).utcOffset()/60*36e5)); 3630 x2 = Math.round(xAxis.toPixels(pos+sunrise*36e5-moment.tz(pos+sunrise*36e5,timezone_id).utcOffset()/60*36e5)); 3631 3632 if(x1<chart.plotLeft) { x1=chart.plotLeft; } 3633 if(x2>chart.plotWidth+chart.plotLeft) { x2=chart.plotWidth+chart.plotLeft; } 3634 group = chart.renderer.g().attr({ 3635 translateX: x1, 3636 translateY: chart.plotTop, 3637 zIndex: 0 3638 }).add(); 3639 //add image 3640 chart.renderer.rect(0,0,x2-x1,chart.plotHeight,1).attr({ 3641 stroke: shade, 3642 fill: shade, 3643 zIndex: 0 3644 }).add(group); 3645 highcharts_nightshadows[plot].push(group); 3646 } 3647} 3648 3649var highcharts_intervals=[];
3650var drawIntervals=function(chart,plot, flag, variant) { 3651 if(typeof highcharts_intervals[plot]!=='undefined') { 3652 $.each(highcharts_intervals[plot], function (i, symbol) {symbol.destroy();}); 3653 } 3654 highcharts_intervals[plot]=[]; 3655 3656 // 'xl': sehr dezente Toenung statt kraeftigem Blau. 3657 var shade = (variant === 'xl') 3658 ? cssVar('--hc-xl-night', '#F4F6F8') 3659 : cssVar('--hc-interval-background'); 3660 3661 var xAxis = chart.xAxis[0]; 3662 var x1,x2,y,pos,max,i,intervall,len; 3663 if (typeof flag === 'undefined') { 3664 intervall = 12; 3665 } 3666 else { 3667 intervall = parseInt(flag); 3668 } 3669 len=Math.round(intervall/4); 3670 3671 pos = (xAxis.min)-(xAxis.min)%(24*36e5); 3672 max = (xAxis.max); 3673 for (i = 0; pos <= max; pos += intervall*36e5, i += 1) { 3674 // Get the X position 3675 3676 if (typeof flag === 'undefined') { 3677 x1 = Math.round(xAxis.toPixels(pos-len*36e5)); 3678 x2 = Math.round(xAxis.toPixels(pos+len*36e5)); 3679 } 3680 else { 3681 x1 = Math.round(xAxis.toPixels(pos-len*36e5-moment.tz(pos-len*36e5,timezone_id).utcOffset()/60*36e5)); 3682 x2 = Math.round(xAxis.toPixels(pos+len*36e5-moment.tz(pos+len*36e5,timezone_id).utcOffset()/60*36e5)); 3683 } 3684 3685 if(x1<chart.plotLeft) { x1=chart.plotLeft; } 3686 if(x2>chart.plotWidth+chart.plotLeft) { x2=chart.plotWidth+chart.plotLeft; } 3687 group = chart.renderer.g().attr({ 3688 translateX: x1, 3689 translateY: chart.plotTop, 3690 zIndex: 0 3691 }).add(); 3692 //add image 3693 chart.renderer.rect(0,0,x2-x1,chart.plotHeight,1).attr({ 3694 stroke: shade, 3695 fill: shade, 3696 }).add(group); 3697 highcharts_intervals[plot].push(group); 3698 } 3699} 3700 3701var highcharts_symbols=[]; 3702var highcharts_symbols_timestamps=[]; 3703var drawWeatherSymbols=function(chart) { 3704 $.each(highcharts_symbols, function (i, symbol) {symbol.destroy();}); 3705 highcharts_symbols=[]; 3706 3707 if(typeof hccompact_data_symbols == 'undefined') return; 3708 3709 var lastDrawnIndex = false; 3710 var lastDrawnSevere = false; 3711 var symbolPixelSize = 24; 3712 var severePixelSize = 40; 3713 3714 var pixelTolerance = 5; 3715 3716 var symbolYMargin = 6; 3717 var severeYMargin = 2; 3718 3719 $.each(chart.series[0].data, function (i, point) { 3720 var group; 3721 h=(point.x-hccompact_model_starttime)/36e5; 3722 3723 highcharts_symbols_timestamps[point.x]=i; 3724 3725 var isSevereSymbol = hccompact_data_symbols[i].search("severe") >= 0; 3726 3727 var pixelSize = isSevereSymbol ? severePixelSize : symbolPixelSize; 3728 var yMargin = isSevereSymbol ? severeYMargin : symbolYMargin; 3729 3730 //Check if pixel space between last drawn symbol and this symbol is enough 3731 if(i !== 0 && lastDrawnIndex !== false) { 3732 if(isSevereSymbol || lastDrawnSevere) { 3733 var pixelDifference = point.plotX - chart.series[0].data[lastDrawnIndex].plotX; 3734 3735 if(isSevereSymbol && !lastDrawnSevere || !isSevereSymbol && lastDrawnSevere) { 3736 if(pixelDifference < (0.5 * severePixelSize + 0.5 * symbolPixelSize) - pixelTolerance) 3737 return; 3738 } else { 3739 if(pixelDifference < severePixelSize - pixelTolerance) 3740 return; 3741 } 3742 } else { 3743 var pixelDifference = point.plotX - chart.series[0].data[lastDrawnIndex].plotX; 3744 if(pixelDifference < symbolPixelSize - pixelTolerance) 3745 return; 3746 } 3747 } 3748 3749 //Check if next symbols are severe and therefore this symbol should not be drawn 3750 if(!isSevereSymbol) { 3751 for(var sevIndex = 1; i + sevIndex <= hccompact_data_symbols.length - 1 && typeof chart.series[0].data[i + sevIndex] !== 'undefined' && chart.series[0].data[i + sevIndex].plotX - point.plotX < (0.5 * severePixelSize + 0.5 * symbolPixelSize) - pixelTolerance; sevIndex++) { 3752 if(hccompact_data_symbols[i + sevIndex].search("severe") >= 0) { 3753 return; 3754 } 3755 } 3756 } 3757 3758 //console.log({plotX: point.plotX, chartLeft: chart.plotLeft, chartWidth: chart.plotWidth }); 3759 3760 if(point.plotX - pixelSize / 2 > chart.plotWidth) 3761 return; 3762 3763 if(point.plotX + pixelSize / 2 < 0) 3764 return; 3765 3766 //console.log({pointX: point.plotX, chartLeft: chart.plotLeft}); 3767 3768 lastDrawnIndex = i; 3769 lastDrawnSevere = false;
3770 3771 if(isSevereSymbol) 3772 lastDrawnSevere = true; 3773 3774 3775 //Calc symbol y by avg 2 highest points of the actuel and 2 nearest points 3776 var pointYArray = [point.plotY]; 3777 var pixelOffsetSum = 0; 3778 3779 for (var iOffset = 1; pixelOffsetSum < pixelSize && iOffset < 200; iOffset++) { 3780 3781 var leftPixelOffset = 0; 3782 var rightPixelOffset = 0; 3783 3784 if(i-iOffset >= 1) { 3785 if(point.plotX - chart.series[0].data[i-iOffset].plotX < pixelSize || iOffset == 1) { 3786 pointYArray.push(chart.series[0].data[i-iOffset].plotY); 3787 leftPixelOffset = point.plotX - chart.series[0].data[i-iOffset].plotX; 3788 } 3789 } 3790 3791 if(i+iOffset <= chart.series[0].data.length - 1) { 3792 if(chart.series[0].data[i+iOffset].plotX - point.plotX < pixelSize || iOffset == 1) { 3793 pointYArray.push(chart.series[0].data[i+iOffset].plotY); 3794 rightPixelOffset = chart.series[0].data[i+iOffset].plotX - point.plotX; 3795 } 3796 } 3797 3798 if(leftPixelOffset + 0.2 < rightPixelOffset && leftPixelOffset != 0) { 3799 rightPixelOffset = leftPixelOffset; 3800 } 3801 3802 pixelOffsetSum = leftPixelOffset > rightPixelOffset ? leftPixelOffset*2 : rightPixelOffset*2; 3803 3804 } 3805 3806 pointYArray = pointYArray.sort(function (a, b) { return a - b; }); 3807 3808 var pointY = 0; 3809 if(pointYArray.length >= 3) 3810 pointY = pointYArray[0] * 0.7 + pointYArray[1] * 0.2 + pointYArray[2] * 0.1; 3811 if(pointYArray.length <= 2) 3812 pointY = pointYArray[0]; 3813 3814 3815 3816 if(pointY - yMargin > point.plotY) 3817 pointY = point.plotY; 3818 3819 3820 group = chart.renderer.g().attr( 3821 { 3822 translateX: point.plotX + chart.plotLeft - (pixelSize / 2), 3823 translateY: pointY + chart.plotTop - (pixelSize + yMargin), 3824 zIndex: 7 3825 } 3826 ).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 3827 //add image 3828 chart.renderer.image('/images/symbole/sym_' + hccompact_data_symbols[i] + '.svg', 0, 0, pixelSize, pixelSize).add(group); 3829 //remember group for cleanup during resize 3830 3831 highcharts_symbols.push(group); 3832 3833 }); 3834} 3835 3836var hcsunsums_labels=[]; 3837var drawSunshineSums=function(chart) { 3838 $.each(hcsunsums_labels, function (i, symbol) {symbol.destroy();}); 3839 hcsunsums_labels=[]; 3840 var xAxis = chart.xAxis[0]; 3841 3842 //alert(pos); 3843 var pos; 3844 pos= (xAxis.min)-(xAxis.min)%(24*36e5)+18*36e5; 3845 3846 var is_this_inside = false;
3847 3848 $.each(hccompact_sunsum, function (i, point) { 3849 var group,x; 3850 3851 3852 var i_next = i+1; 3853 if(typeof hccompact_sunsum[i_next] === 'undefined') 3854 i_next = false; 3855 3856 // position group 3857 x = Math.round(xAxis.toPixels(point[0]-moment.tz(timezone_id).utcOffset()/60*36e5)); 3858 x_next = i_next === false ? false : Math.round(xAxis.toPixels(hccompact_sunsum[i_next][0]-moment.tz(timezone_id).utcOffset()/60*36e5)); 3859 3860 var is_next_inside = x_next === false ? false : x_next < chart.plotLeft + chart.plotWidth && x_next > chart.plotLeft; 3861 var is_before_inside = is_this_inside; 3862 is_this_inside = x < chart.plotLeft + chart.plotWidth && x > chart.plotLeft; 3863 3864 // console.log({is_this_inside, is_next_inside}); 3865 3866 var summe = Math.round(point[1]*10.)/10.; 3867 var text = summe === 0 ? '0' : Highcharts.numberFormat(summe,1).toString(); 3868 var textSize = text.length; 3869 var textWidth = 0; 3870 if(text.indexOf('.') !== -1) { 3871 textSize -= 1; 3872 textWidth += 3.8; 3873 } 3874 textWidth += textSize * 7.5; 3875 3876 var middle_x_day = false; 3877 if(is_this_inside) { 3878 middle_x_day = x; 3879 } 3880 3881 if(!is_this_inside && is_next_inside) { 3882 x = Math.round(xAxis.toPixels(point[0]-moment.tz(timezone_id).utcOffset()/60*36e5+12*36e5)); 3883 middle_x_day = (x - chart.plotLeft) / 2 + chart.plotLeft; 3884 } 3885 3886 if(is_before_inside && !is_this_inside) { 3887 x = Math.round(xAxis.toPixels(point[0]-moment.tz(timezone_id).utcOffset()/60*36e5-12*36e5)); 3888 var middle_x_day = chart.plotLeft + chart.plotWidth - ((chart.plotLeft + chart.plotWidth) - x) / 2; 3889 } 3890 3891 if(middle_x_day !== false) { 3892 group = chart.renderer.g().attr({ 3893 translateX: middle_x_day - textWidth/2 - 3, 3894 translateY: 10, 3895 zIndex: 6 3896 }).add(); 3897 //add image 3898 chart.renderer.label(text).css({ color: cssVar('--color-text') }).add(group); 3899 //remember group for cleanup during resize 3900 hcsunsums_labels.push(group); 3901 } 3902 3903 }) 3904} 3905 3906var hcrainsums_labels=[]; 3907var drawRainSums=function(chart) { 3908 $.each(hcrainsums_labels, function (i, symbol) {symbol.destroy();}); 3909 hcrainsums_labels=[]; 3910 var xAxis = chart.xAxis[0]; 3911 3912 var unit = hccompact_units['rain']=="mm" ? 10. : 100.; 3913 var digits = hccompact_units['rain']=="in" ? 2 : 1; 3914 3915 var pos; 3916 pos= (xAxis.min)-(xAxis.min)%(24*36e5)+2*36e5; 3917 //console.log(pos); 3918 3919 var is_this_inside = false;
3920 3921 $.each(hccompact_rainsum, function (i, point) { 3922 var group,x; 3923 3924 var i_next = i+1; 3925 if(typeof hccompact_rainsum[i_next] === 'undefined') 3926 i_next = false; 3927 3928 // position group 3929 x = Math.round(xAxis.toPixels(point[0]-moment.tz(timezone_id).utcOffset()/60*36e5)); 3930 x_next = i_next === false ? false : Math.round(xAxis.toPixels(hccompact_rainsum[i_next][0]-moment.tz(timezone_id).utcOffset()/60*36e5)); 3931 3932 var is_next_inside = x_next === false ? false : x_next < chart.plotLeft + chart.plotWidth && x_next > chart.plotLeft; 3933 var is_before_inside = is_this_inside; 3934 is_this_inside = x < chart.plotLeft + chart.plotWidth && x > chart.plotLeft; 3935 3936 // console.log({is_this_inside, is_next_inside}); 3937 var summe = Math.round(point[1]*unit)/unit; 3938 var text = summe === 0 ? '0' : Highcharts.numberFormat(summe,digits).toString(); 3939 var textSize = text.length; 3940 var textWidth = 0; 3941 if(text.indexOf('.') !== -1) { 3942 textSize -= 1; 3943 textWidth += 3.8; 3944 } 3945 textWidth += textSize * 7.5; 3946 3947 var middle_x_day = false; 3948 if(is_this_inside) { 3949 middle_x_day = x; 3950 } 3951 3952 if(!is_this_inside && is_next_inside) { 3953 x = Math.round(xAxis.toPixels(point[0]-moment.tz(timezone_id).utcOffset()/60*36e5+12*36e5)); 3954 middle_x_day = (x - chart.plotLeft) / 2 + chart.plotLeft; 3955 } 3956 3957 if(is_before_inside && !is_this_inside) { 3958 x = Math.round(xAxis.toPixels(point[0]-moment.tz(timezone_id).utcOffset()/60*36e5-12*36e5)); 3959 var middle_x_day = chart.plotLeft + chart.plotWidth - ((chart.plotLeft + chart.plotWidth) - x) / 2; 3960 } 3961 3962 if(middle_x_day !== false) { 3963 group = chart.renderer.g().attr({ 3964 translateX: middle_x_day - textWidth/2 - 3, 3965 translateY: 10, 3966 zIndex: 6 3967 }).add(); 3968 //add image 3969 chart.renderer.label(text).css({ color: cssVar('--color-text') }).add(group); 3970 //remember group for cleanup during resize 3971 hcrainsums_labels.push(group); 3972 } 3973 3974 }) 3975} 3976 3977var hchours_labels=[]; 3978hchours_labels[ 'temp']=[]; 3979hchours_labels[ 'xl']=[]; 3980hchours_labels[ 'xl2']=[]; 3981hchours_labels[ 'xl3']=[]; 3982hchours_labels[ 'sun']=[]; 3983hchours_labels[ 'rain']=[]; 3984hchours_labels['pressure']=[]; 3985hchours_labels['ensemble']=[]; 3986hchours_labels['landing']=[]; 3987hchours_labels['obs'] = []; 3988var drawHourlyLabels=function(chart, plot) { 3989 $.each(hchours_labels[plot], function (i, symbol) {symbol.destroy();}); 3990 hchours_labels[plot]=[]; 3991 var xAxis = chart.xAxis[0]; 3992 3993 var x,y,pos,max,i,h,interval; 3994 pos = (xAxis.min)-(Math.abs(xAxis.min))%(24*36e5); 3995 max = (xAxis.max)+moment.tz(xAxis.max,timezone_id).utcOffset()/60*36e5; 3996 3997 if(chart.plotWidth<260 && plot!='obs')return; 3998 if(chart.plotWidth<300 && displayLanguage()=="EN" && plot!='obs')return; 3999 if(chart.plotWidth<420 && plot==='xl2')return; 4000 4001 if(typeof hccompact_superhd != 'undefined'){ 4002 interval=3 4003 } else { 4004 if (chart.plotWidth<540)interval=6; 4005 else interval=3; 4006 } 4007 4008 var labelInterval = 3*36e5; 4009 var maxX = chart.plotWidth + 69; 4010 var minX = 69; 4011 var pixelsPerHour = chart.plotWidth / ((max - xAxis.min) / 1000 / (60*60)) 4012 if (pixelsPerHour < 5) { labelInterval = 6*36e5; } 4013 4014 if(plot== 'temp')y=18; 4015 if(plot== 'sun')y=53; 4016 if(plot== 'rain')y=73; 4017 if(plot=='pressure')y=113; 4018 if(plot=='landing')minX=chart.plotLeft; 4019 if(plot=='ensemble'){ 4020 y=18; 4021 var interval = 1; 4022 var labelInterval = 1*36e5; 4023 var maxX = chart.plotWidth; 4024 4025 var timespan = (xAxis.max - xAxis.min) / 36e5; 4026 var labelWidth = 16; 4027 var labelNum = maxX / labelWidth; 4028 minX = chart.plotLeft - labelWidth; 4029 4030 interval = Math.ceil(timespan / labelNum); 4031 if(interval == 2) interval = 3; 4032 if(interval == 4) interval = 6; 4033 if(interval == 5) interval = 6; 4034 if(interval >= 7 && interval <= 11) interval = 12; 4035 labelInterval = interval*36e5; 4036 max += labelInterval; 4037 } 4038 if(plot=='xl') { 4039 y=18; 4040 interval=12; 4041 labelInterval=12*36e5; 4042 } 4043 if(plot=='xl2') { 4044 y=18; 4045 interval=6; 4046 labelInterval=6*36e5; 4047 } 4048 if(plot=='xl3') { 4049 y=18; 4050 interval=24; 4051 labelInterval=24*36e5; 4052 } 4053 if(plot=='obs') { 4054 y=chart.plotHeight+chart.plotTop; 4055 labelInterval = 1*36e5; 4056 interval = 1; 4057 minX = chart.plotLeft; 4058 4059 var min; 4060 4061 if(typeof hc_obs_max != 'undefined') 4062 max = hc_obs_max+moment.tz(hc_obs_max,timezone_id).utcOffset()/60*36e5; 4063 4064 if(chart.plotWidth < 800) { 4065 labelInterval = 2*36e5; 4066 interval = 2; 4067 } 4068 if(chart.plotWidth < 360) { 4069 labelInterval = 3*36e5; 4070 interval = 3; 4071 } 4072 4073 var timespan = (xAxis.max - xAxis.min) / 36e5; 4074 var labelWidth = 16; 4075 var labelNum = chart.plotWidth / labelWidth; 4076
4077 interval = Math.ceil(timespan / labelNum); 4078 if(interval >= 5) interval = 6; 4079 labelInterval = interval*36e5; 4080 4081 } 4082 4083 if (plot !== 'xl2' && plot !== 'xl3') { 4084 for (i = 0; pos <= max; pos += labelInterval, i += 1) { 4085 // Get the X position 4086 var utcTs = pos-moment.tz(pos, timezone_id).utcOffset()/60*36e5; 4087 x = Math.round(xAxis.toPixels(utcTs)); 4088 if((x<maxX || plot=="ensemble") && x>minX){ 4089 group = chart.renderer.g().attr({ 4090 translateX: x-9, 4091 translateY: y , 4092 zIndex: 6 4093 }).add(); 4094 h=moment(utcTs).tz(timezone_id).hour(); 4095 if(h%interval==0) { 4096 if(h>9) 4097 chart.renderer.label(h).css({'fontSize':'9px','color':cssVar('--color-text')}).add(group); 4098 else 4099 chart.renderer.label('0'+h).css({'fontSize':'9px','color':cssVar('--color-text')}).add(group); 4100 //remember group for cleanup during resize 4101 hchours_labels[plot].push(group); 4102 } 4103 } 4104 } 4105 } 4106 else { 4107 var until = '-'; 4108 var poscorr = until.length === 1 ? 18 : poscorr = until.length === 5 ? 26 : 40; 4109 for (i = 0; pos <= max; pos += labelInterval, i += 1) { 4110 // Get the X position 4111 x = Math.round(xAxis.toPixels(pos)); 4112 if(x<maxX && x>minX){ 4113 group = chart.renderer.g().attr({ 4114 translateX: x-poscorr, 4115 translateY: y , 4116 zIndex: 6 4117 }).add(); 4118 h=(pos)%(24*36e5)/36e5; 4119 if(h%interval==0) { 4120 h += Math.round(moment.tz(pos, timezone_id).utcOffset()/60,1); 4121 if (h<=0) { h+=24;} 4122 if (h>24) {h=h-24;} 4123 var text = ''; 4124 var start=h-interval; if (start < 0) { start = 24+start; } if (start >= 24) { start = start-24; } 4125 if (start>9) { text=start + until; } else { text='0' + start + until; } 4126 if (h>9) { text+=h; } else { text+='0' + h; } 4127 chart.renderer.label(text).css({'fontSize':'9px','color':cssVar('--color-text')}).add(group); 4128 //remember group for cleanup during resize 4129 hchours_labels[plot].push(group); 4130 } 4131 } 4132 } 4133 4134 } 4135} 4136 4137var hcrainpopgrid_box=[]; 4138 4139var nth = function (d) { 4140 if(d>3 && d<21) return 'th'; // thanks kennebec 4141 switch (d % 10) { 4142 case 1: return "st"; 4143 case 2: return "nd"; 4144 case 3: return "rd"; 4145 default: return "th"; 4146 } 4147} 4148 4149var fixLabels = function(chart, plot) { 4150 var labels = $('div.highcharts-xaxis-labels span', chart.container).sort(function(a, b) { 4151 return +parseInt($(a).css('left')) - +parseInt($(b).css('left')); 4152 }); 4153 if (plot === 'landing') { 4154 labels.css('margin-left', (parseInt($(labels.get(1)).css('left')) - parseInt($(labels.get(0)).css('left'))) / 2 ); 4155 } 4156 else { 4157 labels.css('margin-left', (parseInt($(labels.get(1)).css('left')) - parseInt($(labels.get(0)).css('left'))) / 2 ); 4158 } 4159 4160 if(plot=='temp') 4161 labels.css('margin-top',-4); 4162 else if(plot=='ensemble') 4163 labels.css('margin-top', -4); 4164 else 4165 labels.css('margin-top', 5); 4166 4167 4168 var lastTickPosition = chart.xAxis[0].tickPositions.slice(-1)[0]; 4169 var lastTickX = (lastTickPosition - chart.xAxis[0].min) / (chart.xAxis[0].max - chart.xAxis[0].min) * chart.plotWidth + chart.plotLeft; 4170 4171 var xAxisEnd = chart.plotLeft + chart.plotWidth; 4172 //console.log({lastTickX, xAxisEnd}); 4173 4174 labels.last().css('left', lastTickX); 4175 4176 if(xAxisEnd - lastTickX < labels.last().width()) { 4177 labels.last().css('opacity', 0); 4178 } else { 4179 labels.last().css('opacity', 1); 4180 var middlePointOffset = ((xAxisEnd - lastTickX) - labels.last(
4180).width()) / 2; 4181 labels.last().css('margin-left', middlePointOffset); 4182 } 4183 4184}; 4185 4186 4187var highcharts_windblocks=[]; 4188var drawBlocksForWindSymbols = function (chart) { 4189 $.each(highcharts_windblocks, function (i, line) {line.destroy();}); 4190 highcharts_windblocks=[]; 4191 4192 var xAxis = chart.xAxis[0],x,pos,max,i,faktor,len,img,rain_storm,len2,faktor2; 4193 pos = xAxis.min; 4194 max = xAxis.max; 4195 x = Math.round(xAxis.toPixels(0)); 4196 faktor=0.8; 4197 faktor2=0.6; 4198 len = Math.round((xAxis.toPixels(1)-x)*faktor); 4199 len2 = Math.round((xAxis.toPixels(1)-x)*faktor2); 4200 if (len>32) { len=32; faktor=1} 4201 if (len2>18) { len2=18; faktor2=1} 4202 for (i = pos; i <= max ; i += 1) { 4203 x = Math.round(xAxis.toPixels(i)); 4204 if (typeof hccompact_data_14days_rsym[i] !== 'undefined' && typeof hccompact_data_14days_tsym[i] !== 'undefined') { 4205 rain_storm=hccompact_data_14days_tsym[i]; 4206 if (rain_storm === 'null') { 4207 rain_storm=hccompact_data_14days_rsym[i]; 4208 } 4209 if (rain_storm === 'null') { 4210 rain_storm=''; 4211 } 4212 if (rain_storm.length>0) { 4213 group = chart.renderer.g().attr({ 4214 translateX: x - Math.round(len/2), 4215 translateY: chart.plotTop + Math.round(6*faktor), 4216 zIndex: 5 4217 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4218 //add image 4219 chart.renderer.image('/images/symbole/'+rain_storm,0,0,len,len).add(group); 4220 //remember group for cleanup during resize 4221 highcharts_windblocks.push(group); 4222 } 4223 } 4224 if (typeof hccompact_data_14days_gusts_raw[i] !== 'undefined') { 4225 img = getWindSymbol(hc_data_14days_gusts_raw[i]); 4226 if (img.length>0) { 4227 var placement = len2+Math.round(6*faktor2); 4228 group = chart.renderer.g().attr({ 4229 translateX: x - Math.round(len2/2), 4230 translateY: chart.plotTop + chart.plotHeight-placement, 4231 zIndex: 5 4232 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4233 //add image 4234 chart.renderer.image('/images/symbole/'+img,0,0,len2,len2).add(group); 4235 //remember group for cleanup during resize 4236 highcharts_windblocks.push(group); 4237 } 4238 } 4239 //highcharts_windblocks.push(line); 4240 } 4241}; 4242 4243var highcharts_windblocksV2=[]; 4244var drawBlocksForWindSymbolsV2 = function (chart) { 4245 $.each(highcharts_windblocksV2, function (i, line) {line.destroy();}); 4246 highcharts_windblocksV2=[]; 4247 4248 var xAxis = chart.xAxis[0],x,pos,max,i,faktor,len,img,rain,storm,cloudcoverage,len2,faktor2,len3,faktor3; 4249 pos = xAxis.min; 4250 max = xAxis.max; 4251 x = Math.round(xAxis.toPixels(0)); 4252 faktor=0.8; 4253 faktor2=0.6; 4254 faktor3=0.2; 4255 len = Math.round((xAxis.toPixels(1)-x)*faktor); 4256 len2 = Math.round((xAxis.toPixels(1)-x)*faktor2); 4257 len3 = Math.round((xAxis.toPixels(1)-x)*faktor3); 4258 if (len>32) { len=32; faktor=1;} 4259 if (len2>18) { len2=18; faktor2=1;} 4260 if (len3>14) { len2=14; faktor3=1;} 4261 for (i = pos; i <= max ; i += 1) { 4262 x = Math.round(xAxis.toPixels(i)); 4263 if (typeof hc_data_14days_gusts_raw[i] !== 'undefined') { 4264 img = getWindSymbol(hc_data_14days_gusts_raw[i]); 4265 if (img.length>0) { 4266 var placement = len2+Math.round(6*faktor2); 4267 group = chart.renderer.g().attr({ 4268 translateX: x - Math.round(len2/2), 4269 translateY: chart.plotTop + chart.plotHeight-placement, 4270 zIndex: 5 4271 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4272 //add image 4273 chart.renderer.image('/images/symbole/'+img,0,0,len2,len2).add(group); 4274 //remember group for cleanup during resize 4275 highcharts_windblocksV2.push(group); 4276 } 4277 } 4278 //highcharts_windblocksV2.push(line); 4279 } 4280}; 4281var highcharts_14daysshortblocks=[]; 4282var drawBlocksFor14DaysTrendV2short = function (chart) { 4283 $.each(highcharts_14daysshortblocks, function (i, line) {line.destroy();}); 4284 highcharts_14daysshortblocks=[]; 4285 4286 var xAxis = chart.xAxis[0],x,pos,max,i,faktor,len,img,rain,storm,cloudcoverage,len2,faktor2,len3,faktor3; 4287 pos = xAxis.min; 4288 max = xAxis.max; 4289 x = Math.round(xAxis.toPixels(0)); 4290 faktor=0.8; 4291 faktor2=0.6; 4292 faktor3=0.4; 4293 len = Math.round((xAxis.toPixels(1)-x)*faktor); 4294 len2 = Math.round((xAxis.toPixels(1)-x)*faktor2); 4295 len3 = Math.round((xAxis.toPixels(1)-x)*faktor3); 4296 if (len>32) { len=32; faktor=1;} 4297 if (len2>22) { len2=22; faktor2=0.9;} 4298 if (len3>14) { len3=14; faktor3=1;} 4299 for (i = pos; i <= max ; i += 1) { 4300 x = Math.round(xAxis.toPixels(i)); 4301 if (typeof hc_data_14days_gusts_raw[i] !== 'undefined') { 4302 img = getWindSymbol(hc_data_14days_gusts_raw[i]); 4303 if (img.length>0) { 4304 var placement = 35+Math.round(len3*1.5); 4305 group = chart.renderer.g().attr({ 4306 translateX: x - Math.round(len3/3), 4307 translateY: chart.plotTop + chart.plotHeight-placement, 4308 zIndex: 5 4309 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4310 //add image 4311 chart.renderer.image('/images/symbole/'+img,0,0,len3,len3).add(group); 4312 //remember group for cleanup during resize 4313 highcharts_14daysshortblocks.push(group); 4314 } 4315 } 4316 if (typeof hc_data_14days_xaxis2[pos] !== 'undefined') { 4317 group = chart.renderer.g().attr({ 4318 translateX: x-9, 4319 translateY: 0 , 4320 zIndex: 6 4321 }).add(); 4322 chart.renderer.label(hc_data_14days_xaxis2[i]).css({'fontSize':'11px','color':cssVar('--color-text')}
4322).add(group); 4323 highcharts_14daysshortblocks.push(group); 4324 } 4325 if (typeof hc_data_14days_rtype[i] !== 'undefined' && hc_data_14days_rtype[i] !== null && typeof hc_data_14days_rint[i] !== 'undefined' && hc_data_14days_rint[i]>0) { 4326 rain=hc_data_14days_rtype[i]+hc_data_14days_rint[i]; 4327 if (rain === 'null') { 4328 rain=''; 4329 } 4330 if (rain.length>0) { 4331 var placement = 31; 4332 var verschiebung = 0; 4333 if (typeof hc_data_14days_tsym[i] !== 'undefined' && hc_data_14days_tsym[i]>0) { 4334 verschiebung = Math.round(5*faktor2*0.8); 4335 } 4336 group = chart.renderer.g().attr({ 4337 translateX: x - Math.round(len2/2)-verschiebung, 4338 translateY: chart.plotTop + chart.plotHeight-placement, 4339 zIndex: 6 4340 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4341 //add image 4342 chart.renderer.image('/images/layout/icons/trend/precipitation-'+rain+'.svg',0,0,len2,len2).add(group); 4343 highcharts_14daysshortblocks.push(group); 4344 if (typeof hc_data_14days_tsym[i] !== 'undefined' && hc_data_14days_tsym[i] > 0) { 4345 group = chart.renderer.g().attr({ 4346 translateX: x - Math.round(len2/5)+Math.round(verschiebung*faktor2), 4347 translateY: chart.plotTop + chart.plotHeight-placement+Math.round(len2/2.1)-Math.round(verschiebung*faktor2), 4348 zIndex: 7 4349 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4350 //add image 4351 chart.renderer.image('/images/layout/icons/trend/thunderstorm-1.svg',0,0,len2,len2).add(group); 4352 highcharts_14daysshortblocks.push(group); 4353 } 4354 } 4355 } 4356 } 4357 var limit_clear = 90; 4358 var limit_few = 78; 4359 var limit_scattered = 60; 4360 var limit_broken = 30; 4361 if ($('#trend-14days').attr('data-version') !=="v2" && $('#trend-14days').attr('data-version') !=="v2") { 4362 limit_clear = 85; 4363 limit_few = 70; 4364 limit_scattered = 50; 4365 limit_broken = 20; 4366 } 4367 for (i = pos; i <= max ; i += 1) { 4368 var len = xAxis.toPixels(2)-xAxis.toPixels(1); 4369 var suncolor=cssVar('--hc-suncolor_0'); 4370 if (typeof hc_data_14days_sun_rel[i] !== 'undefined') { 4371 if (hc_data_14days_sun_rel[i]>=limit_clear) { 4372 suncolor=cssVar('--hc-suncolor_4'); 4373 } 4374 else if (hc_data_14days_sun_rel[i]>=limit_few) { 4375 suncolor=cssVar('--hc-suncolor_3'); 4376 } 4377 else if (hc_data_14days_sun_rel[i]>=limit_scattered) { 4378 suncolor=cssVar('--hc-suncolor_2'); 4379 } 4380 else if (hc_data_14days_sun_rel[i]>=limit_broken) { 4381 suncolor=cssVar('--hc-suncolor_1'); 4382 } 4383 // Get the X position 4384 var x1 = Math.round(xAxis.toPixels(i)-(len/2))+2; 4385 var x2 = Math.round(xAxis.toPixels(i)+(len/2))-3; 4386 if(x1<chart.plotLeft) { x1=chart.plotLeft; } 4387 if(x2>chart.plotWidth+chart.plotLeft) { x2=chart.plotWidth+chart.plotLeft; } 4388 group = chart.renderer.g().attr({ 4389 translateX: x1, 4390 translateY: chart.plotHeight-13, 4391 zIndex: 0 4392 }).add(); 4393 //add image 4394 chart.renderer.rect(0,0,x2-x1,33,1).attr({ 4395 stroke: suncolor, 4396 fill: suncolor, 4397 zIndex: 0 4398 }).add(group); 4399 highcharts_14daysshortblocks.push(group); 4400 } 4401 } 4402 4403}; 4404 4405 4406var highcharts_gustsblocks=[]; 4407var drawBlocksForGustSymbolsV2 = function (chart) { 4408 $.each(highcharts_gustsblocks, function (i, line) {line.destroy();}); 4409 highcharts_gustsblocks=[]; 4410 var xAxis = chart.xAxis[0],x,pos,max,i,faktor,len,img,len2,faktor2,len3,faktor3; 4411 pos = xAxis.min; 4412 max = xAxis.max; 4413 x = Math.round(xAxis.toPixels(0)); 4414 faktor=0.6; 4415 len = Math.round((xAxis.toPixels(1)-x)*faktor); 4416 if (len>18) { len=18; faktor=1;} 4417 for (i = pos; i <= max ; i += 1) { 4418 x = Math.round(xAxis.toPixels(i)); 4419 if (typeof hc_data_14days_gusts_raw[i] !== 'undefined') { 4420 img = getWindSymbol(hc_data_14days_gusts_raw[i]); 4421 if (img.length>0) { 4422 group = chart.renderer.g().attr({ 4423 translateX: x - Math.round(len/2), 4424 translateY: chart.plotTop + Math.round(6*faktor), 4425 zIndex: 5 4426 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4427 //add image 4428 chart.renderer.image('/images/symbole/'+img,0,0,len,len).add(group); 4429 //remember group for cleanup during resize 4430 highcharts_gustsblocks.push(group); 4431 } 4432 } 4433 } 4434 $.each(chart.series[0].data,function(i,data){ 4435 if (typeof data.dataLabel !== 'undefined') { 4436 data.dataLabel.attr({ 4437 y: chart.yAxis[0].height 4438 }); 4439 } 4440 }); 4441 for (pos = 0; pos < 14; pos += 1) { 4442 // Get the X position 4443 x = Math.round(xAxis.toPixels(pos)); 4444 group = chart.renderer.g().attr({ 4445 translateX: x-9, 4446 translateY: 0 , 4447 zIndex: 6 4448 }).add(); 4449 chart.renderer.label(hc_data_14days_xaxis2[pos]).css({'fontSize':'10px','color':cssVar('--color-text')}
4449).add(group); 4450 highcharts_gustsblocks.push(group); 4451 } 4452}; 4453 4454 4455var highcharts_sunblocks=[]; 4456var highcharts_sunblocks_days=[]; 4457var drawBlocksForSunSymbolsV2 = function (chart) { 4458 $.each(highcharts_sunblocks, function (i, line) {line.destroy();}); 4459 $.each(highcharts_sunblocks_days, function (i, line) {line.destroy();}); 4460 highcharts_sunblocks=[]; 4461 highcharts_sunblocks_days=[]; 4462 4463 4464 var xAxis = chart.xAxis[0],x,pos,max,i,faktor,len,cloudcoverage,len2,faktor2,len3,faktor3; 4465 pos = xAxis.min; 4466 max = xAxis.max; 4467 x = Math.round(xAxis.toPixels(0)); 4468 faktor=0.8; 4469 len = Math.round((xAxis.toPixels(1)-x)*faktor); 4470 if (len>32) { len=32; faktor=1;} 4471 for (i = pos; i <= max ; i += 1) { 4472 x = Math.round(xAxis.toPixels(i)); 4473 if (typeof hc_data_14days_ssym[i] !== 'undefined' && typeof hc_data_14days_sun_maxpos[i] !== 'undefined' 4474 && hc_data_14days_sun_maxpos[i]>0) { 4475 cloudcoverage=hc_data_14days_ssym[i]; 4476 if (cloudcoverage === 'null') { 4477 cloudcoverage=''; 4478 } 4479 if (cloudcoverage.length>0) { 4480 group = chart.renderer.g().attr({ 4481 translateX: x - Math.round(len/2), 4482 translateY: chart.plotTop + Math.round(6*faktor), 4483 zIndex: 5 4484 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4485 chart.renderer.image('/images/layout/icons/trend/cloudcoverage-'+cloudcoverage+'.svg',0,0,len,len).add(group); 4486 highcharts_sunblocks.push(group); 4487 } 4488 } 4489 } 4490 $.each(chart.series[0].data,function(i,data){ 4491 if (typeof data.dataLabel !== 'undefined') { 4492 data.dataLabel.attr({ 4493 y: chart.yAxis[0].height 4494 }); 4495 } 4496 }); 4497 for (pos = 0; pos < 14; pos += 1) { 4498 // Get the X position 4499 x = Math.round(xAxis.toPixels(pos)); 4500 group = chart.renderer.g().attr({ 4501 translateX: x-9, 4502 translateY: 0 , 4503 zIndex: 6 4504 }).add(); 4505 chart.renderer.label(hc_data_14days_xaxis2[pos]).css({'fontSize':'10px','color': cssVar('--color-text')}).add(group); 4506 highcharts_sunblocks_days.push(group); 4507 } 4508}; 4509 4510var highcharts_rainblocks=[]; 4511var highcharts_rainblocks_days=[]; 4512var highcharts_thunderstormblocks=[]; 4513var highcharts_rainprobs=[]; 4514var drawBlocksForRainSymbolsV2 = function (chart) { 4515 $.each(highcharts_rainblocks, function (i, line) {line.destroy();}); 4516 $.each(highcharts_rainblocks_days, function (i, line) {line.destroy();}); 4517 $.each(highcharts_thunderstormblocks, function (i, line) {line.destroy();}); 4518 $.each(highcharts_rainprobs, function (i, line) {line.destroy();}); 4519 highcharts_rainblocks=[];highcharts_rainblocks_days=[];highcharts_thunderstormblocks=[];highcharts_rainprobs=[]; 4520 4521 var xAxis = chart.xAxis[0],x,pos,max,i,faktor,len,rain, len2; 4522 pos = xAxis.min; 4523 max = xAxis.max; 4524 x = Math.round(xAxis.toPixels(0)); 4525 faktor=0.8; 4526 len = Math.round((xAxis.toPixels(1)-x)*faktor); 4527 if (len>24) { len=24; faktor=1;} 4528 len2 = Math.round((xAxis.toPixels(1)-x)*faktor); 4529 if (len2>18) { len2=18; } 4530 for (i = pos; i <= max ; i += 1) { 4531 x = Math.round(xAxis.toPixels(i)); 4532 if (typeof hc_data_14days_rtype[i] !== 'undefined' && hc_data_14days_rtype[i] !== null && typeof hc_data_14days_rint[i] !== 'undefined') { 4533 rain=hc_data_14days_rtype[i]+hc_data_14days_rint[i]; 4534 if (rain === 'null') { 4535 rain=''; 4536 } 4537 if (rain.length>0) { 4538 if (typeof hc_data_14days_tsym[i] !== 'undefined' && hc_data_14days_tsym[i]>0) { 4539 group = chart.renderer.g().attr({ 4540 translateX: x - Math.round(len/2), 4541 translateY: chart.plotTop + 20, 4542 zIndex: 6 4543 }).clip(chart.renderer.clipRect(0, 0, 120, 120)).add(); 4544 //add image 4545 chart.renderer.image('/images/layout/icons/trend/thunderstorm-'+hc_data_14days_tsym[i]+'.svg',0,0,len,len).add(group); 4546 highcharts_thunderstormblocks.push(group); 4547 } 4548 } 4549 } 4550 } 4551 $.each(chart.series[0].data,function(i,data){ 4552 if (typeof data.dataLabel !== 'undefined') { 4553 data.dataLabel.attr({ 4554 y: chart.yAxis[0].height 4555 }); 4556 } 4557 }); 4558 var show_perc = false;
4559 for (pos = 0; pos < 14; pos += 1) { 4560 var len = xAxis.toPixels(2)-xAxis.toPixels(1); 4561 var suncolor='#ccd9f2'; 4562 // Get the X position 4563 x = Math.round(xAxis.toPixels(pos)); 4564 group = chart.renderer.g().attr({ 4565 translateX: x-9, 4566 translateY: 0 , 4567 zIndex: 6 4568 }).add(); 4569 chart.renderer.label(hc_data_14days_xaxis2[pos]).css({'fontSize':'10px','color': cssVar('--color-text')}).add(group); 4570 highcharts_rainblocks_days.push(group); 4571 var percentage_str = '%'; 4572 var corrpos=0; 4573 if (len < 30) { percentage_str=''; show_perc=true;} 4574 var perc_str = hc_data_14days_prob[pos]+percentage_str; 4575 if (perc_str.length-percentage_str.length > 2) { 4576 corrpos=4; 4577 } 4578 if (percentage_str.length === 0){ 4579 if (perc_str.length > 2) { 4580 corrpos=0; 4581 } 4582 else { 4583 corrpos=-4; 4584 } 4585 } 4586 group = chart.renderer.g().attr({ 4587 translateX: x-14-corrpos, 4588 translateY: 20 , 4589 zIndex: 7 4590 }).add(); 4591 chart.renderer.label(perc_str).css({'fontSize':'11px','color': cssVar('--color-text')}).add(group); 4592 highcharts_rainblocks_days.push(group); 4593 } 4594 if (show_perc) { 4595 group = chart.renderer.g().attr({ 4596 translateX: 47, 4597 translateY: 20 , 4598 zIndex: 7 4599 }).add(); 4600 chart.renderer.label('%').css({'fontSize':'11px','color': cssVar('--color-text')}).add(group); 4601 highcharts_rainblocks_days.push(group); 4602 } 4603 for (pos = 0; pos < 14; pos += 1) { 4604 var len = xAxis.toPixels(2)-xAxis.toPixels(1); 4605 var x1 = Math.round(xAxis.toPixels(pos)-(len/2))+2; 4606 var x2 = Math.round(xAxis.toPixels(pos)+(len/2))-3; 4607 if(x1<chart.plotLeft) { x1=chart.plotLeft; } 4608 if(x2>chart.plotWidth+chart.plotLeft) { x2=chart.plotWidth+chart.plotLeft; } 4609 group = chart.renderer.g().attr({ 4610 translateX: x1, 4611 translateY: chart.plotTop+2, 4612 zIndex: 6 4613 }).add(); 4614 chart.renderer.rect(0,0,x2-x1,16,1).attr({ 4615 stroke: cssVar('--hc-rainProps'), 4616 fill: cssVar('--hc-rainProps'), 4617 zIndex: 6 4618 }).add(group); 4619 highcharts_rainprobs.push(group); 4620 } 4621}; 4622 4623var plotGraphCompact = function() { 4624 4625 4626 var margin; 4627 var timezone_id_local = typeof timezone_id !== 'undefined' ? timezone_id : null; 4628 Highcharts.setOptions({ 4629 global: { 4630 /** 4631 * Use moment-timezone.js to return the timezone offset for individual 4632 * timestamps, used in the X axis labels and the tooltip header. 4633 */ 4634 // getTimezoneOffset: function (timestamp) { 4635 // return -moment.tz(timezone_id).utcOffset(); 4636 // } 4637 timezone: timezone_id_local || $('#real-user-timezone').attr('data-value') || 'UTC' 4638 4639 }, 4640 lang: typeof hc_user_settings_lang !== 'undefined' ? hc_user_settings_lang : { 4641 loading: 'Wird geladen...', 4642 months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], 4643 weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], 4644 shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], 4645 } 4646 }); 4647 4648 var zeroline = 0; 4649 if (typeof hccompact_units != 'undefined') { 4650 if(hccompact_units['temp']=="°F") { 4651 zeroline = 32; 4652 } 4653 else if(hccompact_units['temp']=="K") { 4654 zeroline = 273.15; 4655 } 4656 } 4657 4658 if (typeof hccompact_data_temp != 'undefined') { 4659 var yaxismax = false; 4660 if (typeof hccompact_tempmax != 'undefined') { 4661 yaxismax = hccompact_tempmax > -2 && hccompact_tempmax < 2 ? true : false; 4662 } 4663 4664 $('#temp_graph').highcharts({ 4665 chart: { 4666 scrollablePlotArea: {minWidth: getMinWidth()}, 4667 marginBottom: 22, 4668 marginLeft:69, 4669 height: 260, 4670 events: { 4671 load: function(){ 4672 drawWeatherSymbols(this); 4673 drawHourlyLabels(this,'temp'); 4674 drawNightShadows(this, 19, 'xl'); 4675 fixLabels(this,'temp'); 4676 4677 var firstTry = new Date(); 4678 var scrollListenerInterval = function(){ 4679 var scrollAreas = $('.highcharts-scrolling'); 4680 if(scrollAreas.length > 0) { 4681 scrollAreas.on('scroll', function (event) { 4682 let scrollLeft = event.target.scrollLeft; 4683 const containers = document.querySelectorAll('.highcharts-scrolling'); 4684 containers.forEac
4684h(otherContainer => { 4685 if (otherContainer !== event.target) { 4686 otherContainer.scrollLeft = scrollLeft; 4687 } 4688 }); 4689 }); 4690 addGlobalChartScrollHint(document.querySelector('.forecast-compact-wrapper')); 4691 window.clearInterval(intervalId); 4692 } 4693 if( new Date() - firstTry >= 10000) { 4694 window.clearInterval(intervalId); 4695 } 4696 }; 4697 const intervalId = window.setInterval(scrollListenerInterval, 100); 4698 4699 4700 }, 4701 redraw: function(){ 4702 drawWeatherSymbols(this); 4703 drawHourlyLabels(this,'temp'); 4704 drawNightShadows(this, 19, 'xl'); 4705 fixLabels(this,'temp'); 4706 } 4707 } 4708 }, 4709 title: 'false', 4710 legend: 'false', 4711 xAxis: { 4712 opposite:true, 4713 type: 'datetime', 4714 tickInterval: 24*36e5, 4715 gridLineWidth: 1, 4716 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 4717 gridZIndex:2, 4718 minorTickInterval: 3*36e5, 4719 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 4720 minorGridWidth: 1, 4721 min: hccompact_xmin, 4722 max: hccompact_xmax, 4723 dateTimeLabelFormats: { 4724 hour: getDynHourDateFormat(), 4725 day: getDynDayDateFormat() 4726 }, 4727 labels: { 4728 useHTML: true, 4729 align: 'center', 4730 formatter: function () { 4731 var date_format = getDynDayDateFormat(this.value, this.chart.plotWidth); 4732 return Highcharts.dateFormat(date_format, this.value); 4733 }, 4734 style: { 4735 color: cssVar('--color-text') 4736 } 4737 }, 4738 tickLength: 0 4739 }, 4740 yAxis: { 4741 title: { 4742 text: false 4743 }, 4744 labels: { 4745 formatter: function() { 4746 return Highcharts.numberFormat(this.value,0)+" "+hccompact_units['temp']; 4747 }, 4748 style: { 4749 color: cssVar('--color-text') 4750 } 4751 }, 4752 plotLines: [{ 4753 value: zeroline, 4754 width: 1, 4755 color: cssVar('--hc-xl-zeroline', '#C3CAD1'), 4756 zIndex: 2 4757 }], 4758 gridLineWidth: 1, 4759 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 4760 gridZIndex:2, 4761 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 4762 allowDecimals: false, 4763 minorTickInterval: hccompact_units['temp']=="°C" ? 2.5 : 5, 4764 tickInterval: hccompact_units['temp']=="°C" ? 5 : 10, 4765 //gridLineColor: '#C0C0C0', 4766 maxPadding: 0.16, 4767 max: yaxismax ? 5 : null 4768 }, 4769 tooltip: { 4770 crosshairs: true, 4771 shared: true, 4772 useHTML: true, 4773 shape: 'square', 4774 useHTML: true, 4775 outside: false, 4776 positioner: tooltipPositioner, 4777 formatter: function () { 4778 // fix for faulty highcharts tooltip recognition 4779 var date_format = getDynDateFormat(this.x); 4780 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 4781 var c=0; 4782 $.each(this.points, function () { 4783 c++; 4784 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 4785 '<b>'+Highcharts.numberFormat(this.y,1) + '</b> ' + ' ' + hccompact_units['temp']; 4786 }); 4787 i=highcharts_symbols_timestamps[this.x]; 4788 4789 var severeStr = ''; 4790 if(hccompact_data_symbols[i].search('severe') >= 0) { 4791 if(displayLanguage()=="EN"){ 4792 severeStr = '<div style="font-weight:700; "><img style="max-height:16px; margin-right:2px;" src="/images/blitz_icon.png">Severe storms possible</div>'; 4793 } else { 4794 severeStr = '<div style="font-weight:700; "><img style="max-height:16px; margin-right:2px;" src="/images/blitz_icon.png">Schwere Gewitter möglich</div>'; 4795 } 4796 } 4797 4798 return '<div class="highcharts-tooltip"><table><tr><td>' + ttCols(s, this, 48) + '</td><td><img src="/images/symbole/sym_'+hccompact_data_symbols[i]+'.svg" width=32></img></td></tr></table>'+severeStr+'</div>'; 4799 } 4800 }, 4801 credits: { enabled: false }, 4802 exporting: { enabled: false }, 4803 series: hccompact_data_temp, 4804 reflow: true 4805 }); 4806 } 4807 4808 if (typeof hccompact_data_wind != 'undefined') { 4809 $('#wind_graph').highcharts({ 4810 chart: { 4811 scrollablePlotArea: {minWidth: getMinWidth()}, 4812 marginLeft:69, 4813 spacingLeft:0, 4814 height: 150, 4815 events: { 4816 load: function(){ 4817 //drawBlocksForWindArrows(this); 4818 drawNightShadows(this, 20, 'xl'); 4819 drawWindArrows(this); 4820 }, 4821 redraw: function(){ 4822 //drawBlocksForWindArrows(this); 4823 drawNightShadows(this, 20, 'xl'); 4824 drawWindArrows(this); 4825 } 4826 } 4827 }, 4828 title: 'false', 4829 legend: 'false', 4830 xAxis: { 4831 type: 'datetime', 4832 offset: 24, 4833 tickInterval: 24*36e5, 4834 gridLineWidth: 1, 4835 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 4836 gridZIndex:2, 4837 minorTickInterval: 3*36e5, 4838 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 4839 minorGridWidth: 1, 4840 min: hccompact_xmin, 4841 max: hccompact_xmax, 4842 dateTimeLabelFormats: { 4843 hour: '%H:%M', 4844 day: '<b>%a</b>, %e. %b' 4845 }, 4846 tickLength: 0, 4847 labels: { enabled:false } 4848 }, 4849 yAxis: { 4850 title: { 4851 text: false 4852 }, 4853 labels: { 4854 formatter: function() { 4855 return Highcharts.numberFormat(this.value,0)+" "+hccompact_units['wind']; 4856 }, 4857 style: { 4858 color: cssVar('--color-text') 4859 } 4860 }, 4861 plotLines: [{ 4862 value: 0, 4863 width: 1, 4864 color: cssVar('--hc-xl-zeroline', '#C3CAD1'), 4865 zIndex: 2 4866 }], 4867 gridLineWidth: 1, 4868 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 4869 gridZIndex:2, 4870 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 4871 allowDecimals: false, 4872 minorTickInterval: hccompact_units['wind']==='m/s' ? 5 : hccompact_units['wind']==='Bft' ? 1 : hccompact_units['wind']==='kn' ? 7.5 : hccompact_units['wind']==='mph' ? 7.5 : 7.5, 4873 tickInterval: hccompact_units['wind']==='m/s' ? 10 : hccompact_units['wind']==='Bft' ? 3 : hccompact_units['wind']==='kn' ? 15 : hccompact_units['wind']==='mph' ? 15 : 15, 4874 //gridLineColor: '#C0C0C0' 4875 }, 4876 tooltip: { 4877 crosshairs: true, 4878 shared: true, 4879 valueSuffix: ' '+hccompact_units['wind'],
4880 shape: 'square', 4881 useHTML: true, 4882 outside: false, 4883 positioner: tooltipPositioner, 4884 formatter: function () { 4885 // fix for faulty highcharts tooltip recognition 4886 var date_format = getDynDateFormat(this.x); 4887 var digits = hccompact_units['wind'] == 'm/s' ? 1 : 0; 4888 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 4889 var c=0; 4890 4891 var sortedPoints = this.points.sort(function(a, b){ 4892 return ((a.y > b.y) ? -1 : ((a.y < b.y) ? 1 : 0)); 4893 }); 4894 4895 $.each(sortedPoints, function () { 4896 c++; 4897 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 4898 '<b>'+Highcharts.numberFormat(this.y,digits) + '</b> ' + ' ' + hccompact_units['wind']; 4899 }); 4900 return '<div class="highcharts-tooltip">' + ttCols(s, this) + '</div>'; 4901 } 4902 }, 4903 credits: { enabled: false }, 4904 exporting: { enabled: false }, 4905 series: hccompact_data_wind, 4906 reflow: true 4907 }); 4908 } 4909 4910 if (typeof hccompact_data_pressure != 'undefined') { 4911 var pressure_decimals = false; 4912 var pressure_minortick = 2; 4913 var pressure_tick = 10; 4914 if (typeof hccompact_units['pressure'] !== 'undefined' && hccompact_units['pressure'] === 'inHg') { 4915 pressure_decimals=true; 4916 pressure_minortick = 0.1; 4917 pressure_tick=0.3; 4918 } 4919 $('#pressure_graph').highcharts({ 4920 chart: { 4921 scrollablePlotArea: {minWidth: getMinWidth()}, 4922 marginBottom: 45, 4923 marginLeft:69, 4924 spacingLeft:0, 4925 height: 160, 4926 events: { 4927 load: function(){ 4928 drawHourlyLabels(this,'pressure'); 4929 drawNightShadows(this, 21, 'xl'); 4930 fixLabels(this); 4931 }, 4932 redraw: function(){ 4933 drawHourlyLabels(this,'pressure'); 4934 drawNightShadows(this, 21, 'xl'); 4935 fixLabels(this); 4936 } 4937 } 4938 }, 4939 title: 'false', 4940 legend: { 4941 useHTML: true 4942 }, 4943 xAxis: { 4944 type: 'datetime', 4945 tickInterval: 24*36e5, 4946 gridLineWidth: 1, 4947 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 4948 gridZIndex:2, 4949 minorTickInterval: 3*36e5, 4950 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 4951 minorGridWidth: 1, 4952 min: hccompact_xmin, 4953 max: hccompact_xmax, 4954 dateTimeLabelFormats: { 4955 hour: '%H:%M', 4956 day: '<b>%a</b>, %e. %b' 4957 }, 4958 labels: { 4959 useHTML: true, 4960 align: 'center', 4961 formatter: function () { 4962 var date_format = getDynDayDateFormat(this.value, this.chart.plotWidth); 4963 return Highcharts.dateFormat(date_format, this.value); 4964 }, 4965 style: { 4966 color: cssVar('--color-text') 4967 } 4968 }, 4969 tickLength: 0, 4970 }, 4971 yAxis: { 4972 title: { 4973 text: false 4974 }, 4975 labels: { 4976 formatter: function() { 4977 return Highcharts.numberFormat(this.value,0)+(hccompact_units['pressure'] =='mbar' ? hccompact_units['pressure'] : ' '+hccompact_units['pressure']); 4978 }, 4979 style: { 4980 color: cssVar('--color-text') 4981 } 4982 }, 4983 offset: hccompact_units['pressure'] =='mbar' ? (-6) : hccompact_units['pressure'] =='inHg' ? -4 : (-5), 4984 gridLineWidth: 1, 4985 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 4986 gridZIndex:2, 4987 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 4988 allowDecimals: pressure_decimals, 4989 minorTickInterval: pressure_minortick, 4990 //gridLineColor: '#C0C0C0', 4991 tickInterval: pressure_tick, 4992 maxPadding: 0, 4993 minPadding: 0 4994 }, 4995 tooltip: { 4996 crosshairs: true, 4997 shared: true, 4998 valueSuffix: ' '+hccompact_units['pressure'],
4999 shape: 'square', 5000 useHTML: true, 5001 zIndex: 50, 5002 outside: false, 5003 positioner: tooltipPositioner, 5004 formatter: function () { 5005 // fix for faulty highcharts tooltip recognition 5006 var date_format = getDynDateFormat(this.x); 5007 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 5008 var c=0; 5009 $.each(this.points, function () { 5010 c++; 5011 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 5012 '<b>'+Highcharts.numberFormat(this.y,1) + '</b> ' + ' '+hccompact_units['pressure']; 5013 }); 5014 return '<div class="highcharts-tooltip">' + ttCols(s, this) + '</div>'; 5015 } 5016 }, 5017 credits: { enabled: false }, 5018 exporting: { enabled: false }, 5019 series: hccompact_data_pressure, 5020 reflow: true 5021 }); 5022 } 5023 5024 if (typeof hccompact_data_sun != 'undefined') { 5025 var langOpts = { 5026 weekday: "long", 5027 year: "numeric", 5028 month: "short", 5029 day: "numeric", 5030 }; 5031 5032 var hccompact_sun_frontend = hccompact_data_sun.map(serie => ({ 5033 ...serie, 5034 data: serie.data.map(point => ({ ...point, timestamp: point.x, x: point.x - point.z })) 5035 })).filter(serie => serie.data.length > 0); 5036 5037 var minimalSunZ = hccompact_sun_frontend.length === 0 ? 36e5 : Math.min(...hccompact_sun_frontend.map(serie => Math.min(...serie.data.map(point => point.z)))); 5038 5039 $('#sun_graph').highcharts({ 5040 plotOptions: { 5041 series: { 5042 states: { 5043 inactive: { 5044 opacity: 1 5045 } 5046 } 5047 }, 5048 variwide: { 5049 color: "#e7d621", 5050 borderColor: "#F7E631", 5051 cropThreshold: 500, 5052 pointPadding: 0, 5053 groupPadding: 0, 5054 borderWidth: 1, 5055 } 5056 }, 5057 chart: { 5058 scrollablePlotArea: {minWidth: getMinWidth()}, 5059 marginBottom: 45, 5060 marginLeft: 69, 5061 height: 100, 5062 events: { 5063 load: function () { 5064 drawSunshineSums(this); 5065 drawHourlyLabels(this, 'sun'); 5066 drawNightShadows(this, 22, 'xl'); 5067 fixLabels(this); 5068 }, 5069 redraw: function () { 5070 drawSunshineSums(this); 5071 drawHourlyLabels(this, 'sun'); 5072 drawNightShadows(this, 22, 'xl'); 5073 fixLabels(this); 5074 } 5075 }, 5076 type: 'variwide' 5077 }, 5078 title: 'false', 5079 legend: { 5080 useHTML: true 5081 }, 5082 xAxis: { 5083 type: 'datetime', 5084 tickInterval: 24 * 36e5, 5085 gridLineWidth: 1, 5086 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5087 gridZIndex: 2, 5088 minorTickInterval: 3 * 36e5, 5089 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5090 minorGridWidth: 1, 5091 min: hccompact_xmin + (minimalSunZ / 2), 5092 max: hccompact_xmax - (minimalSunZ / 2), 5093 labels: { 5094 useHTML: true, 5095 align: 'center', 5096 formatter: function () { 5097 var date_format = getDynDayDateFormat(this.value, this.chart.plotWidth); 5098 return Highcharts.dateFormat(date_format, this.value); 5099 }, 5100 style: { 5101 color: cssVar('--color-text') 5102 } 5103 }, 5104 tickLength: 0 5105 }, 5106 yAxis: { 5107 title: { 5108 text: false 5109 }, 5110 floor: 0, 5111 labels: { 5112 formatter: function () { 5113 return Highcharts.numberFormat(1 / (60 / this.value) * 100, 0) + " %"; 5114 }, 5115 style: { 5116 color: cssVar('--color-text') 5117 } 5118 }, 5119 min: 0, 5120 max: 80, 5121 gridLineWidth: 1, 5122 gridZIndex: 2, 5123 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5124 showLastLabel: false, 5125 allowDecimals: false, 5126 minorTickInterval: 1, 5127 tickInterval: 30, 5128 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4') 5129 //tickAmount: 1 5130 }, 5131 tooltip: { 5132 crosshairs: true, 5133 shared: true, 5134 valueSuffix: ' min',
5135 shape: 'square', 5136 useHTML: true, 5137 zIndex: 50, 5138 outside: false, 5139 positioner: tooltipPositioner, 5140 formatter: function (input) { 5141 var point = this.points[0]; 5142 //console.log(point); 5143 var hoursStr = `(${new Date(point.point.x).toLocaleString(displayLanguage, { timeStyle: "short" })} - ${new Date(point.point.timestamp).toLocaleString(displayLanguage, { timeStyle: "short" })})`; 5144 5145 let timestamp = new Date(this.x); 5146 var percentage = (1 / (60 / point.y)) * 100; 5147 var hourmins = point.y * point.point.hours; 5148 var useHours = hourmins > 60; 5149 5150 if (useHours) { 5151 hourmins = hourmins / 60; 5152 } 5153 5154 return `<span style="font-size:10px">${timestamp.toLocaleDateString(displayLanguage(), langOpts)} ${hoursStr}</span> 5155 <br/><span style="color:${point.series.color}">â</span> ${point.series.name}: 5156 <b>${Highcharts.numberFormat(hourmins, useHours ? 1 : 0)}</b> ${hccompact_units[ useHours ? 'sunhours' : 'sunmin' ]} (${Highcharts.numberFormat(percentage, 0)}%)`; 5157 } 5158 }, 5159 credits: {enabled: false}, 5160 exporting: {enabled: false}, 5161 series: hccompact_sun_frontend, 5162 reflow: true 5163 }); 5164 } 5165 5166 if (typeof hccompact_data_rain != 'undefined') { 5167 var hccompact_rain_frontend = hccompact_data_rain.map(serie => ({ 5168 ...serie, 5169 data: serie.data.map(point => ({ ...point, timestamp: point.x, x: point.x - point.z })) 5170 })).filter(serie => serie.data.length > 0); 5171 5172 var minimalRainZ = hccompact_rain_frontend.length === 0 ? 36e5 : Math.min(...hccompact_rain_frontend.map(serie => Math.min(...serie.data.map(point => point.z)))); 5173 5174 $('#rain_graph').highcharts({ 5175 chart: { 5176 scrollablePlotArea: {minWidth: getMinWidth()}, 5177 marginBottom: 45, 5178 marginLeft:69, 5179 height: 120, 5180 type: "variwide", 5181 events: { 5182 load: function(){ 5183 drawRainSums(this); 5184 drawHourlyLabels(this,'rain'); 5185 drawNightShadows(this, 23, 'xl'); 5186 fixLabels(this); 5187 }, 5188 redraw: function(){ 5189 drawRainSums(this); 5190 drawHourlyLabels(this,'rain'); 5191 drawNightShadows(this, 23, 'xl'); 5192 fixLabels(this); 5193 } 5194 } 5195 }, 5196 plotOptions:{ 5197 series: { 5198 pointPadding: 0, 5199 groupPadding: 0 5200 }, 5201 variwide: { 5202 color: cssVar('--hc-rain'), 5203 borderColor: cssVar('--hc-rain'), 5204 stacking: 'normal', 5205 cropThreshold: 500, 5206 pointPadding: 0, 5207 groupPadding: 0, 5208 borderWidth: 1, 5209 } 5210 }, 5211 title: 'false', 5212 legend: { enabled: false }, 5213 xAxis: { 5214 type: 'datetime', 5215 tickInterval: 24*36e5, 5216 gridLineWidth: 1, 5217 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5218 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5219 gridZIndex:2, 5220 minorTickInterval: 3*36e5, 5221 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5222 minorGridWidth: 1, 5223 endOnTick:false, 5224 min: hccompact_xmin + (minimalRainZ / 2), 5225 max: hccompact_xmax - (minimalRainZ / 2), 5226 dateTimeLabelFormats: { 5227 hour: '%H:%M', 5228 day: '<b>%a</b>, %e. %b' 5229 }, 5230 labels: { 5231 useHTML: true, 5232 align: 'center', 5233 formatter: function () { 5234 var date_format = getDynDayDateFormat(this.value, this.chart.plotWidth); 5235 return Highcharts.dateFormat(date_format, this.value); 5236 }, 5237 style: { 5238 color: cssVar('--color-text') 5239 } 5240 }, 5241 tickLength: 0 5242 }, 5243 yAxis: { 5244 title: { 5245 text: false 5246 }, 5247 floor: 0, 5248 labels: { 5249 formatter: function() { 5250 var digits = 0; 5251 if (hccompact_units['rain'] == 'in') { digits=1; } 5252 return Highcharts.numberFormat(this.value, digits)+" "+hccompact_units['rain'] + "/" + hccompact_units['sunhours'] 5253 }, 5254 style: { 5255 color: cssVar('--color-text') 5256 } 5257 }, 5258 gridLineWidth: 1, 5259 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5260 gridZIndex:2, 5261 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5262 min: 0, 5263 softMax: hccompact_units['rain']=="mm" ? 2 : 0.2, 5264 maxPadding: 0.2, 5265 allowDecimals: hccompact_units['rain']=="mm" ? true : true, 5266 minorTickInterval: hccompact_units['rain']=="mm" ? 1 : 0.01, 5267 tickInterval: hccompact_units['rain']=="mm" ? 1 : 0.05, 5268 }, 5269 tooltip: { 5270 crosshairs: true, 5271 shared: true, 5272 valueSuffix: ' '+hccompact_units['rain'],
5273 shape: 'square', 5274 useHTML: true, 5275 zIndex: 50, 5276 outside: false, 5277 positioner: tooltipPositioner, 5278 formatter: function () { 5279 var point = this.points[0]; 5280 5281 var date_format = getDynDateFormat(this.x); 5282 var digits = hccompact_units['rain'] == 'in' ? 2 : 1; 5283 var hoursStr = `(${new Date(point.point.x).toLocaleString(displayLanguage, { timeStyle: "short" })} - ${new Date(point.point.timestamp).toLocaleString(displayLanguage, { timeStyle: "short" })})`; 5284 5285 let sumStr = (point.point.hours > 1 ? Highcharts.numberFormat((Math.round(point.total * Math.pow(10, digits)) / Math.pow(10, digits)) * point.point.hours, digits) + " "+hccompact_units['rain']+" (~ " : ""); 5286 5287 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x) + hoursStr + '</span> '; 5288 $.each(this.points, function () { 5289 let sumStr = (point.point.hours > 1 ? Highcharts.numberFormat((Math.round(this.y * Math.pow(10, digits)) / Math.pow(10, digits)) * point.point.hours, digits) + " "+hccompact_units['rain']+" (~ " : ""); 5290 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 5291 sumStr + '<b>'+ Highcharts.numberFormat(this.y,digits) + '</b> ' + ' ' +hccompact_units['rain'] + "/" + hccompact_units['sunhours']+ (sumStr.length > 0 ? ")" : ""); 5292 }); 5293 s+='<br/><span style="color:#000000">' + 'â' + '</span> Total: '+sumStr +'<b>' + Highcharts.numberFormat(point.total,digits) + '</b> '+hccompact_units['rain'] + "/" + hccompact_units['sunhours'] + (sumStr.length > 0 ? ")" : ""); 5294 return ttCols(s, this); 5295 } 5296 }, 5297 credits: { enabled: false }, 5298 exporting: { enabled: false }, 5299 series: hccompact_rain_frontend, 5300 reflow: true 5301 }); 5302 } 5303 5304 if (typeof hccompact_data_rainsum != 'undefined') { 5305 $('#rainsum_graph').highcharts({ 5306 chart: { 5307 scrollablePlotArea: {minWidth: getMinWidth()}, 5308 marginBottom: 22, 5309 marginLeft:69, 5310 height: 90, 5311 events: { 5312 load: function(){ 5313 drawNightShadows(this, 24, 'xl'); 5314 }, 5315 redraw: function(){ 5316 drawNightShadows(this, 24, 'xl'); 5317 } 5318 } 5319 }, 5320 title: 'false', 5321 legend: { 5322 useHTML: true 5323 }, 5324 xAxis: { 5325 type: 'datetime', 5326 tickInterval: 24*36e5, 5327 gridLineWidth: 1, 5328 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5329 gridZIndex:2, 5330 minorTickInterval: 3*36e5, 5331 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5332 minorGridWidth: 1, 5333 min: hccompact_xmin, 5334 max: hccompact_xmax, 5335 dateTimeLabelFormats: { 5336 hour: '%H:%M', 5337 day: '%e. %b' 5338 }, 5339 labels: {enabled:false}, 5340 tickLength: 0 5341 }, 5342 yAxis: { 5343 title: { 5344 text: false 5345 }, 5346 labels: { 5347 formatter: function() { 5348 var digits = 0; 5349 if (hccompact_units['rain'] == 'in') { digits=1; } 5350 return Highcharts.numberFormat(this.value, digits)+" "+hccompact_units['rain'] 5351 }, 5352 style: { 5353 color: cssVar('--color-text') 5354 } 5355 }, 5356 min:0, 5357 gridLineWidth: 1, 5358 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5359 gridZIndex:2, 5360 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5361 softMax: 1, //hccompact_units['rain']=="mm" ? 1 : 0.1, 5362 allowDecimals: hccompact_units['rain']=="mm" ? false : true, 5363 minorTickInterval: hccompact_units['rain']=="mm" ? 1 : 0.02, 5364 //gridLineColor: '#C0C0C0', 5365 alignTicks: false, 5366 tickInterval: hccompact_units['rain']=="mm" ? 5 : 0.5 5367 }, 5368 tooltip: { 5369 crosshairs: true, 5370 shared: true, 5371 valueSuffix: ' '+hccompact_units['rain'],
5372 shape: 'square', 5373 useHTML: true, 5374 zIndex: 50, 5375 outside: false, 5376 positioner: tooltipPositioner, 5377 formatter: function () { 5378 var date_format = getDynDateFormat(this.x); 5379 var digits = 1; 5380 if (hccompact_units['rain'] == 'in') { digits=2; } 5381 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 5382 $.each(this.points, function () { 5383 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 5384 '<b>'+Highcharts.numberFormat((this.y).toFixed(digits),digits) + '</b> ' + ' ' +hccompact_units['rain']; 5385 }); 5386 return ttCols(s, this); 5387 } 5388 }, 5389 credits: { enabled: false }, 5390 exporting: { enabled: false }, 5391 series: hccompact_data_rainsum, 5392 reflow: true 5393 }); 5394 } 5395 5396 if (typeof hccompact_data_snowheight != 'undefined') { 5397 $('#snowheight_graph').highcharts({ 5398 chart: { 5399 scrollablePlotArea: {minWidth: getMinWidth()}, 5400 marginBottom: 22, 5401 marginLeft:69, 5402 height: 110, 5403 events: { 5404 load: function(){ 5405 drawNightShadows(this, 32, 'xl'); 5406 }, 5407 redraw: function(){ 5408 drawNightShadows(this, 32, 'xl'); 5409 } 5410 } 5411 }, 5412 title: 'false', 5413 legend: { 5414 useHTML: true 5415 }, 5416 xAxis: { 5417 type: 'datetime', 5418 tickInterval: 24*36e5, 5419 gridLineWidth: 1, 5420 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5421 gridZIndex:2, 5422 minorTickInterval: 3*36e5, 5423 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5424 minorGridWidth: 1, 5425 min: hccompact_xmin, 5426 max: hccompact_xmax, 5427 dateTimeLabelFormats: { 5428 hour: '%H:%M', 5429 day: '%e. %b' 5430 }, 5431 labels: {enabled:false}, 5432 tickLength: 0 5433 }, 5434 yAxis: { 5435 title: { 5436 text: false 5437 }, 5438 labels: { 5439 formatter: function() { 5440 var digits = 0; 5441 //if (hccompact_units['snow'] == 'in') { digits=1; } 5442 return Highcharts.numberFormat(this.value, digits)+" "+hccompact_units['snow'] 5443 }, 5444 style: { 5445 color: cssVar('--color-text') 5446 } 5447 }, 5448 min:0, 5449 gridLineWidth: 1, 5450 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5451 gridZIndex:2, 5452 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5453 softMax: hccompact_units['snow']=="cm" ? 5 : 2, 5454 allowDecimals: hccompact_units['snow']=="cm" ? false : true, 5455 minorTickInterval: hccompact_units['snow']=="cm" ? ( 5456 hccompact_snowmax > 100 ? 25 : 5457 hccompact_snowmax > 50 ? 10 : 5458 hccompact_snowmax > 20 ? 5 : 5459 1 5460 ) : ( 5461 hccompact_snowmax > 100 ? 10 : 5462 hccompact_snowmax > 50 ? 5 : 5463 hccompact_snowmax > 20 ? 2 : 5464 0.5 5465 ), 5466 //gridLineColor: '#C0C0C0', 5467 alignTicks: false, 5468 tickInterval: hccompact_units['snow']=="cm" ? ( 5469 hccompact_snowmax > 100 ? 50 : 5470 hccompact_snowmax > 50 ? 20 : 5471 hccompact_snowmax > 20 ? 10 : 5472 5 5473 ) : ( 5474 hccompact_snowmax > 100 ? 20 : 5475 hccompact_snowmax > 50 ? 10 : 5476 hccompact_snowmax > 20 ? 4 : 5477 1 5478 ) 5479 }, 5480 tooltip: { 5481 crosshairs: true, 5482 shared: true, 5483 valueSuffix: ' '+hccompact_units['snow'],
5484 shape: 'square', 5485 useHTML: true, 5486 zIndex: 50, 5487 outside: false, 5488 positioner: tooltipPositioner, 5489 formatter: function () { 5490 var date_format = getDynDateFormat(this.x); 5491 5492 if (hccompact_units['snow'] == 'in') { digits=1; } 5493 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 5494 $.each(this.points, function () { 5495 var digits = 0; 5496 if (hccompact_units['snow'] == 'in') { 5497 digits = 1; 5498 } 5499 else { 5500 if (this.y > 0 && this.y < 2) { digits = 1; } 5501 } 5502 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 5503 '<b>'+Highcharts.numberFormat((this.y).toFixed(digits),digits) + '</b> ' + ' ' +hccompact_units['snow']; 5504 }); 5505 return ttCols(s, this); 5506 } 5507 }, 5508 credits: { enabled: false }, 5509 exporting: { enabled: false }, 5510 series: hccompact_data_snowheight, 5511 reflow: true 5512 }); 5513 } 5514 5515 if (typeof hccompact_data_rainpop != 'undefined') { 5516 $('#rainpop_graph').highcharts({ 5517 chart: { 5518 scrollablePlotArea: {minWidth: getMinWidth()}, 5519 marginBottom: 22, 5520 marginLeft:69, 5521 height: 100, 5522 events: { 5523 load: function(){ 5524 drawNightShadows(this, 25, 'xl'); 5525 5526 }, 5527 redraw: function(){ 5528 drawNightShadows(this, 25, 'xl'); 5529 5530 } 5531 }, 5532 }, 5533 title: 'false', 5534 legend: { 5535 useHTML: true 5536 }, 5537 xAxis: { 5538 type: 'datetime', 5539 tickInterval: 24*36e5, 5540 gridLineWidth: 1, 5541 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5542 gridZIndex:2, 5543 minorTickInterval: 3*36e5, 5544 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5545 minorGridWidth: 1, 5546 min: hccompact_xmin, 5547 max: hccompact_xmax, 5548 dateTimeLabelFormats: { 5549 hour: '%H:%M', 5550 day: '%e. %b' 5551 }, 5552 labels: {enabled:false}, 5553 tickLength: 0, 5554 plotBands: (typeof hccompact_data_rainpopEmpty != 'undefined' ? hccompact_data_rainpopEmpty : []) 5555 }, 5556 yAxis: { 5557 title: { 5558 text: false 5559 }, 5560 labels: { 5561 formatter: function() { 5562 return Highcharts.numberFormat(this.value, 0)+" %"; 5563 }, 5564 style: { 5565 color: cssVar('--color-text') 5566 } 5567 }, 5568 gridLineWidth: 1, 5569 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5570 gridZIndex:2, 5571 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5572 allowDecimals: false, 5573 minorTickInterval: 1, 5574 //gridLineColor: '#C0C0C0', 5575 maxPadding: 0, 5576 max: 101, 5577 endOnTick: false, 5578 tickInterval: 50 5579 }, 5580 tooltip: { 5581 crosshairs: true, 5582 shared: true, 5583 valueSuffix: ' %', 5584 shape: 'square', 5585 useHTML: true, 5586 zIndex: 50, 5587 outside: false, 5588 positioner: tooltipPositioner, 5589 formatter: function () { 5590 // fix for faulty highcharts tooltip recognition 5591 var date_format = getDynDateFormat(this.x); 5592 var date_format_from = getDynDateFormat(this.x-3*3600*1000); 5593 var s = '<span style="font-size:10px;">'+hccompact_units['from']+' '+Highcharts.dateFormat(date_format_from, (this.x-3*3600*1000))+ '<br class="visible-xs-inline" /> '+hccompact_units['until']+' '+Highcharts.dateFormat(date_format, this.x)+'</span> '; 5594 var c=0; 5595 $.each(this.points, function () { 5596 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 5597 '<b>'+Highcharts.numberFormat(this.y,0) + '</b> ' + ' %'; 5598 }); 5599 return '<div class="highcharts-tooltip">' + ttCols(s, this) + '</div>'; 5600 } 5601 }, 5602 credits: { enabled: false }, 5603 exporting: { enabled: false }, 5604 series: hccompact_data_rainpop, 5605 reflow: true 5606 }); 5607 } 5608 5609 if (typeof hccompact_data_humidity != 'undefined') { 5610 $('#humidity_graph').highcharts({ 5611 chart: { 5612 scrollablePlotArea: {minWidth: getMinWidth()}, 5613 marginBottom: 22, 5614 marginLeft:69, 5615 height: 75, 5616 type: 'area', 5617 events: { 5618 load: function(){ 5619 drawNightShadows(this, 26, 'xl'); 5620 }, 5621 redraw: function(){ 5622 drawNightShadows(this, 26, 'xl'); 5623 } 5624 } 5625 }, 5626 title: 'false', 5627 legend: { 5628 useHTML: true 5629 }, 5630 xAxis: { 5631 type: 'datetime', 5632 tickInterval: 24*36e5, 5633 gridLineWidth: 1, 5634 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5635 gridZIndex:2, 5636 minorTickInterval: 3*36e5, 5637 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5638 minorGridWidth: 1, 5639 min: hccompact_xmin, 5640 max: hccompact_xmax, 5641 dateTimeLabelFormats: { 5642 hour: '%H:%M', 5643 day: '%e. %b' 5644 }, 5645 labels: {enabled:false}, 5646 tickLength: 0 5647 }, 5648 yAxis: { 5649 title: { 5650 text: false 5651 }, 5652 floor: 0, 5653 labels: { 5654 formatter: function() { 5655 return Highcharts.numberFormat(this.value,0)+" %"; 5656 }, 5657 style: { 5658 color: cssVar('--color-text') 5659 } 5660 5661 }, 5662 gridLineWidth: 1, 5663 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5664 gridZIndex:2, 5665 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5666 min:0, 5667 max:100, 5668 allowDecimals: false, 5669 minorTickInterval: 1, 5670 tickInterval: 25, 5671 //gridLineColor: '#C0C0C0' 5672 //tickAmount: 1 5673 }, 5674 tooltip: { 5675 crosshairs: true, 5676 shared: true, 5677 valueSuffix: ' %',
5678 shape: 'square', 5679 useHTML: true, 5680 zIndex: 50, 5681 outside: false, 5682 positioner: tooltipPositioner, 5683 formatter: function () { 5684 // fix for faulty highcharts tooltip recognition 5685 var date_format = getDynDateFormat(this.x); 5686 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 5687 var c=0; 5688 $.each(this.points, function () { 5689 c++; 5690 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 5691 '<b>'+Highcharts.numberFormat(this.y,0) + '</b> ' + ' %'; 5692 }); 5693 return '<div class="highcharts-tooltip">' + ttCols(s, this) + '</div>'; 5694 } 5695 }, 5696 plotOptions: { 5697 area: { 5698 fillColor: { 5699 linearGradient: { 5700 x1: 0, 5701 y1: 0, 5702 x2: 0, 5703 y2: 1 5704 }, 5705 stops: [ 5706 [0, cssVar('--hc-humidy_0')], 5707 [1, cssVar('--hc-humidy_1')] 5708 ] 5709 }, 5710 marker: { 5711 radius: 2 5712 }, 5713 lineWidth: 1, 5714 states: { 5715 hover: { 5716 lineWidth: 1 5717 } 5718 }, 5719 threshold: null 5720 } 5721 }, 5722 credits: { enabled: false }, 5723 exporting: { enabled: false }, 5724 series: hccompact_data_humidity, 5725 reflow: true 5726 }); 5727 } 5728 5729 if (typeof hccompact_data_clouds != 'undefined') { 5730 $('#clouds_graph').highcharts({ 5731 chart: { 5732 scrollablePlotArea: {minWidth: getMinWidth()}, 5733 marginBottom: 22, 5734 marginLeft:69, 5735 height: 90, 5736 type: 'heatmap', 5737 plotBorderWidth: 1 5738 }, 5739 title: 'false', 5740 legend: { enabled : false }, 5741 xAxis: { 5742 type: 'datetime', 5743 tickInterval: 24*36e5, 5744 gridLineWidth: 1, 5745 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5746 gridZIndex:6, 5747 minorTickInterval: 3*36e5, 5748 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5749 minorGridWidth: 36e5, 5750 min: hccompact_xmin + 0.5 * 36e5, 5751 max: hccompact_xmax - 0.5 * 36e5, 5752 dateTimeLabelFormats: { 5753 hour: '%H:%M', 5754 day: '%e. %b' 5755 }, 5756 labels: {enabled:false}, 5757 tickLength: 0 5758 }, 5759 yAxis: { 5760 title: { 5761 text: false 5762 }, 5763 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5764 gridZIndex:6, 5765 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5766 categories: hccompact_units['levels'], 5767 tickInterval: 1, 5768 labels: { 5769 style: { 5770 color: cssVar('--color-text') 5771 } 5772 } 5773 }, 5774 tooltip: { enabled: false }, 5775 colorAxis: { 5776 dataClasses:[{ 5777 from :0, to :12.5, color : cssVar('--hc-cloudcolor_0') },{ 5778 from :12.5, to :25, color : cssVar('--hc-cloudcolor_1') },{ 5779 from :25, to :37.5, color : cssVar('--hc-cloudcolor_2') },{ 5780 from :37.5, to :50, color : cssVar('--hc-cloudcolor_3') },{ 5781 from :50, to :62.5, color : cssVar('--hc-cloudcolor_4') },{ 5782 from :62.5, to :75, color : cssVar('--hc-cloudcolor_5') },{ 5783 from :75, to :87.5, color : cssVar('--hc-cloudcolor_6') },{ 5784 from :87.5, to :100, color : cssVar('--hc-cloudcolor_7') }] 5785 }, 5786 credits: { enabled: false }, 5787 exporting: { enabled: false }, 5788 series: hccompact_data_clouds, 5789 reflow: true 5790 }); 5791 } 5792 5793 if (typeof hccompact_data_visibility != 'undefined') { 5794 $('#visibility_graph').highcharts({ 5795 chart: { 5796 scrollablePlotArea: {minWidth: getMinWidth()}, 5797 marginLeft:69, 5798 height: 150, 5799 type: 'area', 5800 events: { 5801 load: function(){ 5802 drawNightShadows(this, 27, 'xl'); 5803 }, 5804 redraw: function(){ 5805 drawNightShadows(this, 27, 'xl'); 5806 } 5807 } 5808 }, 5809 title: 'false', 5810 legend: { 5811 useHTML: true 5812 }, 5813 xAxis: { 5814 type: 'datetime', 5815 tickInterval: 24*36e5, 5816 gridLineWidth: 1, 5817 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5818 gridZIndex:2, 5819 minorTickInterval: 3*36e5, 5820 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5821 minorGridWidth: 1, 5822 min: hccompact_xmin, 5823 max: hccompact_xmax, 5824 dateTimeLabelFormats: { 5825 hour: '%H:%M', 5826 day: '%e. %b' 5827 }, 5828 labels: {enabled:false}, 5829 tickLength: 0 5830 }, 5831 yAxis: { 5832 title: { 5833 text: false 5834 }, 5835 labels: { 5836 format: "{value} "+hccompact_units['visibility'], 5837 style: { 5838 color: cssVar('--color-text') 5839 } 5840 }, 5841 plotLines: [{ 5842 value: 1, 5843 width: 2, 5844 color: '#F7E631', 5845 zIndex: 3 5846 }], 5847 gridLineWidth: 1, 5848 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 5849 gridZIndex:2, 5850 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 5851 allowDecimals: false, 5852 minorTickInterval: 1, 5853 //gridLineColor: '#C0C0C0', 5854 maxPadding: 0, 5855 tickInterval: 1, 5856 endOnTick: false, 5857 }, 5858 tooltip: { 5859 crosshairs: true, 5860 shared: true, 5861 valueSuffix: ' '+hccompact_units['visibility'],
5862 shape: 'square', 5863 useHTML: true, 5864 zIndex: 50, 5865 outside: false, 5866 positioner: tooltipPositioner, 5867 formatter: function () { 5868 var date_format = getDynDateFormat(this.x); 5869 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+'</span> '; 5870 $.each(this.points, function () { 5871 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + '<b>'+Highcharts.numberFormat(this.y,1) + '</b> ' + ' ' +hccompact_units['visibility']; 5872 }); 5873 return ttCols(s, this); 5874 } 5875 }, 5876 plotOptions: { 5877 area: { 5878 fillColor: { 5879 linearGradient: { 5880 x1: 0, 5881 y1: 0, 5882 x2: 0, 5883 y2: 1 5884 }, 5885 stops: [ 5886 [0, '#005288'], 5887 [1, '#7dbbea'] 5888 ] 5889 } 5890 } 5891 }, 5892 credits: { enabled: false }, 5893 exporting: { enabled: false }, 5894 series: hccompact_data_visibility, 5895 reflow: true 5896 }); 5897 } 5898 5899 // landing page diagram 5900 if (typeof hclanding_data_temp != 'undefined') { 5901 $('#temp_graph').highcharts({ 5902 chart: { 5903 // marginLeft:69, 5904 spacingBottom:40, 5905 height: 300, 5906 events: { 5907 load: function(){ 5908 drawWeatherSymbols(this,hclanding_data_temp); 5909 drawHourlyLabels(this,'landing'); 5910 drawNightShadows(this,28); 5911 fixLabels(this,'landing'); 5912 drawWindArrows(this,'landing'); 5913 }, 5914 redraw: function(){ 5915 drawWeatherSymbols(this,hclanding_data_temp); 5916 drawHourlyLabels(this,'landing'); 5917 drawNightShadows(this,28); 5918 fixLabels(this,'landing'); 5919 drawWindArrows(this,'landing'); 5920 } 5921 } 5922 }, 5923 title: { 5924 text: undefined 5925 }, 5926 legend: { 5927 enabled: false 5928 }, 5929 xAxis: { 5930 opposite: true, 5931 offset: 0, 5932 type: 'datetime', 5933 tickInterval: 24*36e5, 5934 gridLineWidth: 1, 5935 gridLineColor: cssVar(' --hc-gridLineColor777777'), 5936 gridZIndex:2, 5937 minorTickInterval: 3*36e5, 5938 minorGridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 5939 minorGridWidth: 1, 5940 min: hccompact_xmin, 5941 max: hccompact_xmax, 5942 dateTimeLabelFormats: { 5943 hour: '%H:%M', 5944 day: '<b>%a</b>, %e. %b' 5945 }, 5946 labels: { 5947 useHTML: true, 5948 align: 'center', 5949 formatter: function () { 5950 var date_format = getDynDayDateFormat(this.value, this.chart.plotWidth); 5951 return Highcharts.dateFormat(date_format, this.value); 5952 }, 5953 style: { 5954 color: cssVar('--color-text') 5955 } 5956 }, 5957 tickLength: 0 5958 }, 5959 yAxis: [{ 5960 title: { text: false }, 5961 labels: { 5962 format: "{value}"+hccompact_units['temp'], 5963 style: { 5964 color: cssVar('--color-text') 5965 } 5966 }, 5967 plotLines: [{ 5968 value: zeroline, 5969 width: 2, 5970 color: cssVar('hc-plotLines808080'), 5971 zIndex: 2 5972 }], 5973 gridLineWidth: 1, 5974 //gridLineColor: cssVar('--hc-gridLineColor777777'), 5975 gridZIndex:2, 5976 zIndex: 15, 5977 minorGridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 5978 allowDecimals: false, 5979 minorTickInterval: hccompact_units['temp']=="°C" ? 2 : 5, 5980 tickInterval: hccompact_units['temp']=="°C" ? 4 : 10, 5981 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 5982 maxPadding: 0.12 5983 },{ 5984 title: { text: false }, 5985 floor: 0, 5986 labels: { 5987 format: "{value}"+hccompact_units['rain'], 5988 style: { color: cssVar('--hc-hclanding_data_temp_rain') } 5989 }, 5990 min:0, 5991 softMax: hccompact_units['rain']=="mm" ? 4 : 0.2, 5992 allowDecimals: true, 5993 tickAmount:5, 5994 zIndex: 10, 5995 gridLineColor: 'transparent', 5996 minorGridLineColor: 'transparent', 5997 opposite:true, 5998 type: 'bar' 5999 },{ 6000 title: { text: false }, 6001 labels: { enabled: false }, 6002 gridLineWidth: 1, 6003 softMax: 20000, 6004 min: 0, 6005 gridZIndex:2, 6006 zIndex: 5, 6007 minorGridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 6008 allowDecimals: false, 6009 gridLineColor: cssVar('--hc-gridLineColorC0C0C0'), 6010 }], 6011 plotOptions: { 6012 series: { 6013 stacking: 'normal' 6014 } 6015 }, 6016 tooltip: { 6017 crosshairs: true, 6018 shared: true, 6019 useHTML: true,
6020 shape: 'square', 6021 useHTML: true, 6022 outside: false, 6023 positioner: tooltipPositioner, 6024 formatter: function () { 6025 // fix for faulty highcharts tooltip recognition 6026 var date_format = getDynDateFormat(this.x); 6027 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 6028 var c=0; 6029 $.each(this.points, function () { 6030 c++; 6031 if (this.y != 0.0 || c == 1 || c == 2) { 6032 if (c != 4 && c != 5 && c != 6 && c != 2 && c != 3) { 6033 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> ' + this.series.name + ': '; 6034 s += '<b>' + Highcharts.numberFormat(this.y, 1) + '</b> ' + ' '; 6035 } else if (c == 2) { 6036 s += '<br/>' + '<span style="color:' + cssVar('--hc-tooltip_blue') + '">' + 'â' + '</span> ' + this.series.name + ': '; 6037 s += '<b>' + Highcharts.numberFormat(this.y, 1) + '</b> ' + ' '; 6038 } else { 6039 var digits = 0; 6040 if (c == 3 || c == 4) { 6041 digits = (hccompact_units['rain'] === 'in' ? 2 : 1); 6042 } 6043 s += '<br/>' + '<span style="color:' + cssVar('--hc-tooltip_grey') + '">' + 'â' + '</span> ' + this.series.name + ': '; 6044 s += '<b>' + Highcharts.numberFormat(this.y, digits) + '</b> ' + ' '; 6045 } 6046 if (c == 1 || c == 2) { 6047 s += hccompact_units['temp']; 6048 } else if (c == 5 || c == 6) { 6049 s += hccompact_units['wind']; 6050 } else { 6051 s += hccompact_units['rain']; 6052 } 6053 } 6054 }); 6055 i=highcharts_symbols_timestamps[this.x]; 6056 return '<div class="highcharts-tooltip"><table><tr><td>' + ttCols(s, this, 48) + '</td><td><img src="/images/symbole/sym_'+hccompact_data_symbols[i]+'.svg" width=32></img></td></tr></table></div>'; 6057 } 6058 }, 6059 credits: { enabled: false }, 6060 exporting: { enabled: false }, 6061 series: hclanding_data_temp, 6062 reflow: true 6063 }); 6064 } 6065}; 6066 6067var sort_range_value = [0, 0]; 6068var sort_range_start = 0; 6069var sort_range_end = 0; 6070var sort_slider = null; 6071var setupSortRangeSlider = function() { 6072 if(typeof hcensemble_heat_timestamps === 'undefined' || hcensemble_heat_timestamps.length < 2) return; 6073 6074 if(isEnsembleDurationParameter() && !isEnsembleDailyParameter()) { 6075 var plotBandMin = hcensemble_heat_timestamps[0]; 6076 plotBandMin -= hcensemble_heat_timestamps[1] - hcensemble_heat_timestamps[0]; 6077 hcensemble_heat_timestamps.unshift(plotBandMin); 6078 } else if(isEnsembleDurationParameter() && isEnsembleDailyParameter()) { 6079 var lastIndex = hcensemble_heat_timestamps.length - 1; 6080 var plotBandMax = hcensemble_heat_timestamps[lastIndex]; 6081 plotBandMax += hcensemble_heat_timestamps[lastIndex] - hcensemble_heat_timestamps[lastIndex - 1]; 6082 hcensemble_heat_timestamps.push(plotBandMax); 6083 } 6084 6085 sort_range_start = 0; 6086 sort_range_end = hcensemble_heat_timestamps.length - 1; 6087 6088 var el_start = $('#sort-range-slider-container').attr('data-start-ts'); 6089 var el_end = $('#sort-range-slider-container').attr('data-end-ts'); 6090 var isFullRange = $('#sort-range-slider-container').attr('data-full-range') == 1; 6091 6092 var timezone = $('#real-user-timezone').attr('data-value'); 6093 6094 if(!isFullRange) { 6095 var newStartTs = 0; 6096 var newEndTs = 0; 6097 var newStartIndex = 0; 6098 var newEndIndex = 0; 6099 6100 hcensemble_heat_timestamps.forEach(function(ts, index) { 6101 6102 if(el_start != 'start') { 6103 if(Math.abs(ts - el_start) < Math.abs(newStartTs - el_start)) { 6104 newStartTs = ts; 6105 newStartIndex = index; 6106 } 6107 } 6108 6109 if(el_end != 'end') { 6110 if(Math.abs(ts - el_end) < Math.abs(newEndTs - el_end)) { 6111 newEndTs = ts;
6112 newEndIndex = index; 6113 } 6114 } 6115 6116 }); 6117 6118 sort_range_value = [newStartIndex, newEndIndex]; 6119 6120 } else { 6121 sort_range_value = [sort_range_start, sort_range_end]; 6122 } 6123 6124 var moment_from_value = function(val) { 6125 if(val > sort_range_end) 6126 val = sort_range_end 6127 if(val < sort_range_start) 6128 val = sort_range_start 6129 6130 return moment(hcensemble_heat_timestamps[val]); 6131 } 6132 6133 var time_format = getTimezoneFormat('time'); 6134 var date_format = getTimezoneFormat('shortdate', true); 6135 6136 var tooltipFix = function() { 6137 //Fix tooltip position 6138 var margin = 10; 6139 6140 var arrowPosX = $('#sort-range-slider').parent().find('.tooltip-main .tooltip-arrow').offset().left + $('#sort-range-slider').parent().find('.tooltip-main .tooltip-arrow').outerWidth() / 2; 6141 var tooltipWidth = $('#sort-range-slider').parent().find('.tooltip-main .tooltip-inner').outerWidth(); 6142 6143 var windowWidth = $(window).width(); 6144 6145 if(arrowPosX < tooltipWidth / 2 + margin) { 6146 var translate = tooltipWidth / 2 - arrowPosX + margin; 6147 $('#sort-range-slider').parent().find('.tooltip-main .tooltip-inner').css('transform', 'translateX('+translate+'px)'); 6148 } 6149 6150 if(windowWidth - arrowPosX < tooltipWidth / 2 + margin) { 6151 var translate = -(tooltipWidth / 2 - (windowWidth - arrowPosX) + margin); 6152 $('#sort-range-slider').parent().find('.tooltip-main .tooltip-inner').css('transform', 'translateX('+translate+'px)'); 6153 } 6154 } 6155 6156 var formatter = function(value) { 6157 6158 if(Array.isArray(value)) { 6159 var start_moment = moment_from_value(value[0]); 6160 var end_moment = moment_from_value(value[1]); 6161 6162 var format = date_format + ' ' + time_format; 6163 var tooltip = ''; 6164 if(end_moment > start_moment) { 6165 tooltip = start_moment.tz(timezone).format(format) + ' - ' + end_moment.tz(timezone).format(format); 6166 } 6167 else { 6168 tooltip = end_moment.tz(timezone).format(format) + ' - ' + start_moment.tz(timezone).format(format); 6169 } 6170 6171 return tooltip; 6172 } else { 6173 var moment_val = moment_from_value(value); 6174 return moment_val.tz(timezone).format('lll'); 6175 } 6176 } 6177 var isSliding = false; 6178 var onSlideStart = function(event) { 6179 // sort_range_value[0] = sort_range_start; 6180 // sort_range_value[1] = sort_range_end; 6181 isSliding = true; 6182 onSlide(event, true); 6183 }; 6184 6185 var onSlide = function(event, start) { 6186 //Update global vars 6187 var oldValue = sort_range_value; 6188 sort_range_value = event.value; 6189 6190 if(sort_range_value[0] != oldValue[0] || sort_range_value[1] != oldValue[1] || start) { 6191 6192 tooltipFix(); 6193 6194 var start_moment = moment_from_value(sort_range_value[0]); 6195 var end_moment = moment_from_value(sort_range_value[1]); 6196 sortRangeUpdatePlotBands(start_moment, end_moment); 6197 } 6198 6199 }; 6200 6201 var onSlideStop = function(event) { 6202 isSliding = false; 6203 if(!$('#sort-range-slider-container').is(':hover')) 6204 sortRangeUpdatePlotBands(false); 6205 6206 $('#forecast-sort-selector .mod-fc-ensemble-sort.btn-active').trigger('click'); 6207 }; 6208 6209 6210 sort_slider = $('#sort-range-slider').bootstrapSlider({ 6211 range: true, 6212 min: sort_range_start, 6213 max: sort_range_end, 6214 value: sort_range_value, 6215 formatter: formatter, 6216 }); 6217 6218 sort_slider.on('slide', onSlide); 6219 sort_slider.on('slideStart', onSlideStart); 6220 sort_slider.on('slideStop', onSlideStop); 6221 6222 6223 $('#sort-range-slider-container').hover(function() { onSlide({value: sort_range_value}, true); }, function() { if(!isSliding) sortRangeUpdatePlotBands(false); }); 6224 6225} 6226 6227var sortRangeUpdatePlotBands = function(start_moment, end_moment) { 6228 if(!$('#ensemble_graph').length) return; 6229 var chart = $('#ensemble_graph').highcharts(); 6230 var xAxis = chart.xAxis[0]; 6231 var opacity = 1; 6232 if(xAxis) { 6233 if(start_moment) { 6234 xAxis.options.plotBands[0].to = +start_moment; 6235 xAxis.options.plotBands[1].from = +end_moment; 6236 xAxis.plotLinesAndBands[0].options.to = +start_moment; 6237 xAxis.plotLinesAndBands[1].options.from = +end_moment; 6238 } else { 6239 opacity = 0; 6240 } 6241 6242 xAxis.plotLinesAndBands[0].svgElem.animate({opacity: opacity}); 6243 xAxis.plotLinesAndBands[1].svgElem.animate({opacity: opacity}); 6244 6245 xAxis.plotLinesAndBands[0].render(); 6246 xAxis.plotLinesAndBands[1].render(); 6247 } 6248} 6249 6250var showSortRangeSlider = function() { 6251 if(!$('#forecast-sort-selector .mod-fc-ensemble-sort.btn-active[data-value="none"]').length) { 6252 $('#forecast-sort-range-selector').fadeIn(300); 6253 } else { 6254 $('#forecast-sort-range-selector').fadeOut(300); 6255 } 6256} 6257 6258var plotGraphEnsembleLong = function() { 6259 if(!$('#ensemble_graph').length || typeof hcensemble_unit === 'undefined') return; 6260 6261 var timezone_id_local = typeof timezone_id !== 'undefined' ? timezone_id : null; 6262 Highcharts.setOptions({ 6263 global: { 6264 timezone: timezone_id_local || $('#real-user-timezone').attr('data-value') || 'UTC' 6265 }, 6266 lang: typeof hc_user_settings_lang !== 'undefined' ? hc_user_settings_lang : default_lang_settings 6267 }); 6268 6269 var hcensemble_yminortick=0.1; 6270 var hcensemble_ytick=1.0; 6271 var hcensemble_positive=0; 6272
6273 if (hcensemble_unit== "°C")hcensemble_yminortick=2.5; 6274 else if(hcensemble_unit== "K")hcensemble_yminortick=2.5; 6275 else if(hcensemble_unit== "°F")hcensemble_yminortick=5.0; 6276 else if(hcensemble_unit== "mm")hcensemble_yminortick=1.0; 6277 else if(hcensemble_unit== "cm")hcensemble_yminortick=1.0; 6278 else if(hcensemble_unit== "in")hcensemble_yminortick=0.05; 6279 else if(hcensemble_unit== "hPa")hcensemble_yminortick=0.5; 6280 else if(hcensemble_unit=="mbar")hcensemble_yminortick=0.5; 6281 else if(hcensemble_unit=="m/s")hcensemble_yminortick=0.5; 6282 else if(hcensemble_unit=="inHg")hcensemble_yminortick=0.05; 6283 else if(hcensemble_unit=="km/h")hcensemble_yminortick=5; 6284 else if(hcensemble_unit=="kph")hcensemble_yminortick=5; 6285 else if(hcensemble_unit=="J/kg")hcensemble_yminortick=10; 6286 else if(hcensemble_unit== "mph")hcensemble_yminortick=5; 6287 else if(hcensemble_unit== "kn")hcensemble_yminortick=5; 6288 else if(hcensemble_unit== "dBz")hcensemble_yminortick=5; 6289 else if(hcensemble_unit== "%")hcensemble_yminortick=10; 6290 6291 if (hcensemble_unit== "mm")hcensemble_positive=1; 6292 else if(hcensemble_unit== "cm")hcensemble_positive=1; 6293 else if(hcensemble_unit== "in")hcensemble_positive=1; 6294 else if(hcensemble_unit== "km/h")hcensemble_positive=1; 6295 else if(hcensemble_unit== "kph")hcensemble_positive=1; 6296 else if(hcensemble_unit== "m/s")hcensemble_positive=1; 6297 else if(hcensemble_unit== "kn")hcensemble_positive=1; 6298 else if(hcensemble_unit== "Bft")hcensemble_positive=1; 6299 else if(hcensemble_unit== "J/kg")hcensemble_positive=1; 6300 else if(hcensemble_unit=="kg/m²")hcensemble_positive=1; 6301 else if(hcensemble_unit== "mph")hcensemble_positive=1; 6302 else if(hcensemble_unit== "dBz")hcensemble_positive=1; 6303 6304 if (hcensemble_unit== "°C")hcensemble_ytick=5; 6305 else if(hcensemble_unit== "K")hcensemble_ytick=5; 6306 else if(hcensemble_unit== "°F")hcensemble_ytick=10; 6307 else if(hcensemble_unit== "mm")hcensemble_ytick=5.0; 6308 else if(hcensemble_unit== "cm")hcensemble_ytick=1.0; 6309 else if(hcensemble_unit== "in")hcensemble_ytick=0.1; 6310 else if(hcensemble_unit== "mph")hcensemble_ytick=10; 6311 else if(hcensemble_unit=="mbar")hcensemble_ytick=5; 6312 else if(hcensemble_unit=="m/s")hcensemble_ytick=5; 6313 else if(hcensemble_unit=="inHg")hcensemble_ytick=0.1; 6314 else if(hcensemble_unit=="km/h")hcensemble_ytick=15; 6315 else if(hcensemble_unit=="kph")hcensemble_ytick=15; 6316 else if(hcensemble_unit=="J/kg")hcensemble_ytick=50; 6317 else if(hcensemble_unit== "mph")hcensemble_ytick=10; 6318 else if(hcensemble_unit== "kn")hcensemble_ytick=10; 6319 else if(hcensemble_unit== "dBz")hcensemble_ytick=15; 6320 else if(hcensemble_unit== "%")hcensemble_ytick=20; 6321 var zeroline = 0; 6322 if(hcensemble_unit== "°F") { 6323 zeroline = 32; 6324 } 6325 else if(hcensemble_unit=="K") { 6326 zeroline = 273.15; 6327 } 6328 6329 var highcharts_options= function(plot) { 6330 var ev = null; 6331 if (plot === true) { 6332 ev = { 6333 load: function(){ 6334 if(!isEnsembleDailyParameter()) drawHourlyLabels(this,'ensemble'); 6335 if(!hcensembleheat_data && !isEnsembleDailyParameter()) drawNightShadows(this,30,'xl'); 6336 6337 var shouldFixLabels = true; 6338 if(hcensembleheat_data) { 6339 if(isEnsembleDailyParameter() && !isEnsembleDurationParameter()) shouldFixLabels = false; 6340 } else { 6341 if(isEnsembleDailyParameter()) shouldFixLabels = false; 6342 } 6343 6344 if(shouldFixLabels) fixLabels(this,'ensemble'); 6345 }, 6346 redraw: function(){ 6347 if(!isEnsembleDailyParameter()) drawHourlyLabels(this,'ensemble'); 6348 if(!hcensembleheat_data && !isEnsembleDailyParameter()) drawNightShadows(this,30,'xl'); 6349 6350 var shouldFixLabels = true; 6351 if(hcensembleheat_data) { 6352 if(isEnsembleDailyParameter() && !isEnsembleDurationParameter()) shouldFixLabels = false;
6353 } else { 6354 if(isEnsembleDailyParameter()) shouldFixLabels = false; 6355 } 6356 6357 if(shouldFixLabels) fixLabels(this,'ensemble'); 6358 } 6359 }; 6360 } 6361 else { 6362 ev = { 6363 load: function(){ 6364 fixLabels(this,'ensemble'); 6365 }, 6366 redraw: function(){ 6367 fixLabels(this,'ensemble'); 6368 } 6369 }; 6370 } 6371 6372 var scrollablePlotArea = {}; 6373 if(ensemble_model == 'ecmwf-46') { 6374 scrollablePlotArea.minWidth = 1600*3; 6375 } 6376 else if(ensemble_model == 'euro' || ensemble_model == 'ecmwf-aifs' || ensemble_model == 'usa' || ensemble_model == 'gem') { 6377 scrollablePlotArea.minWidth = 1600; 6378 } 6379 else if (ensemble_model == 'icon-eu' || ensemble_model == 'icon-world') { 6380 scrollablePlotArea.minWidth = 1600/3; 6381 } 6382 6383 hc_config = { 6384 chart: { 6385 marginLeft:75, 6386 spacingLeft:0, 6387 spacingBottom: 30, 6388 height: 320, 6389 events: ev, 6390 scrollablePlotArea: scrollablePlotArea 6391 }, 6392 title: 'false', 6393 legend: { 6394 'enabled' : false 6395 /*useHTML: true, 6396 itemWidth: 100, 6397 align: 'left', 6398 width: 505,*/ 6399 }, 6400 plotOptions: { 6401 heatmap: { 6402 states: { 6403 inactive: { 6404 opacity: 1 6405 } 6406 }, 6407 pointPlacement: isEnsembleDurationParameter() && !isEnsembleDailyParameter() ? -0.5 : (isEnsembleDailyParameter() && isEnsembleDurationParameter() ? 'between' : 'on') 6408 } 6409 }, 6410 xAxis: { 6411 opposite:true, 6412 type: 'datetime', 6413 tickInterval: 24*36e5, 6414 // XL-Optik: Tagesgrenze als EINE dezente Linie, Raster hinter 6415 // den Daten statt darueber (frueher gridZIndex 2). 6416 gridLineWidth: 1, 6417 lineWidth: 0, 6418 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 6419 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 6420 gridZIndex: 1, 6421 // Das 3h-Raster bleibt - bei Ensembles ist die Stundenorientierung 6422 // Teil der Information -, wird aber auf den hellen XL-Ton gesetzt. 6423 minorTickInterval: !isEnsembleDailyParameter() ? 3*36e5 : null, 6424 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 6425 minorGridLineWidth: 1, 6426 minorGridWidth: 1, 6427 min: hccompact_xmin, 6428 max: hccompact_xmax, 6429 dateTimeLabelFormats: { 6430 hour: getDynHourDateFormat(), 6431 day: getDynDayDateFormat() 6432 }, 6433 labels: { 6434 useHTML: true, 6435 align: 'center', 6436 formatter: function () { 6437 var date_format = getDynDayDateFormat(this.value, this.chart.plotWidth); 6438 return Highcharts.dateFormat(date_format, this.value); 6439 }, 6440 style: { 6441 color: cssVar('--hc-xl-label', '#79838D'), 6442 fontSize: '12px' 6443 } 6444 }, 6445 tickLength: 0 6446 }, 6447 yAxis: { 6448 title: { 6449 text: false 6450 }, 6451 labels: { 6452 formatter: function() { 6453 var digits=0; 6454 if (hcensemble_unit === 'in') { digits=1; } 6455 if (hcensemble_unit === 'inHg') { digits=1; } 6456 return Highcharts.numberFormat(this.value,digits)+(hcensemble_unit === 'mbar' ? "":" ")+hcensemble_unit; 6457 }, 6458 style: { 6459 color: cssVar('--hc-xl-label', '#79838D'), 6460 fontSize: '12px' 6461 } 6462 6463 }, 6464 plotLines: [{ 6465 value: zeroline, 6466 width: 1, 6467 color: cssVar('--hc-xl-zeroline', '#C3CAD1'), 6468 zIndex: 2 6469 }], 6470 gridLineWidth: 1, 6471 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 6472 gridZIndex: 1, 6473 lineWidth: 0, 6474 // Waagerechte Zwischenlinien entfallen wie in XL - sie waren 6475 // reines Rauschen. Die Tick-Abstaende selbst bleiben unberuehrt. 6476 minorGridLineWidth: 0, 6477 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 6478 allowDecimals: false, 6479 minorTickInterval: hcensemble_yminortick, 6480 tickInterval: hcensemble_ytick, 6481 }, 6482 tooltip: { 6483 crosshairs: true, 6484 shared: true, 6485 useHTML: true,
6486 shape: 'square', 6487 useHTML: true, 6488 positioner: function (w,h,p) { 6489 this.chart.pointer.chartPosition = null; 6490 return { x: -100, y: 0 }; 6491 }, 6492 formatter: function () { 6493 // fix for faulty highcharts tooltip recognition 6494 var date_format = getDynDateFormat(this.x); 6495 var x_ts = this.x 6496 if(isEnsembleDailyParameter()) { 6497 date_format = getDynDayLongFormat(x_ts); 6498 } 6499 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, x_ts)+ '</span> '; 6500 var c=0; 6501 var max=-9e30; 6502 var min= 9e30; 6503 var mean=0; 6504 var mean_run=null; 6505 var main=null; 6506 var high=0; 6507 var low=0; 6508 var count=0; 6509 var p=null; 6510 $.each(this.points, function () { 6511 if(this.point.series.name=="Percentile"){p=this.point;} 6512 if(this.point.series.name=="Mean"){mean_run=this.y;} 6513 if(this.point.series.name!="Main"){ 6514 if(typeof this.point.low!=undefined)if(this.point.low<min)min=this.point.low; 6515 if(typeof this.point.high!=undefined)if(this.point.high>max)max=this.point.high; 6516 if(this.y<min)min=this.y; 6517 if(this.y>max)max=this.y; 6518 mean+=this.y; 6519 count++; 6520 }else{ 6521 main=this.y; 6522 } 6523 }); 6524 if (count>0) { mean=mean/count; } 6525 if(p!=null){high=p.high;low=p.low; } 6526 var digits = 0; 6527 6528 if( hcensemble_unit=="mm" || 6529 hcensemble_unit=="cm" || 6530 hcensemble_unit=="hPa" || 6531 hcensemble_unit=="mbar" || 6532 hcensemble_unit=="m/s" || 6533 hcensemble_unit=="K" || 6534 hcensemble_unit=="°C" || 6535 ensemble_param == 'sonnenscheindauer24h' ){ 6536 digits = 1; 6537 } 6538 else if( hcensemble_unit=="in" || 6539 hcensemble_unit=="inHg" ){ 6540 digits = 2; 6541 } 6542 else if (ensemble_param === 'supercellindex') { digits=2; } 6543 6544 var s1,s2,s3; 6545 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, x_ts)+ '</span> <br/>'; 6546 var s0=""; 6547 if(displayLanguage()=="EN") { 6548 if(main!=null){s0 = '<span style="font-size:12px;color:var(--color-text-black);"><span style="color:black;">■</span> Main run:</span> ' + '<b>'+Highcharts.numberFormat(main,digits) + '</b> ' + ' ' + hcensemble_unit + '<br/>';} 6549 if(main!=null){s1 = '<span style="font-size:12px;color:var(--color-text);">'+(mean_run !== null ? '<span style="font-size:12px;color:#004a97">●</span> ':'')+'Ensemble mean:</span> ' + '<b> '+Highcharts.numberFormat(mean_run !== null ? mean_run:mean,digits) + '</b> ' + ' ' + hcensemble_unit + '<br/>';} 6550 else {s1 = '<span style="font-size:12px;color:var(--color-text);">'+(mean_run !== null ? '<span style="font-size:12px;color:#004a97">●</span> ':'')+'Ensemble mean:</span> ' + '<b> '+Highcharts.numberFormat(mean_run !== null ? mean_run:mean,digits) + '</b> ' + ' ' + hcensemble_unit + '<br/>';} 6551 s2 = '<td>' + '<span style="font-size:12px;color:var(--hc-max-red);">Maximum:</span> ' + '</td><td><b> '+Highcharts.numberFormat(max,digits) + '</b> ' + ' ' + hcensemble_unit + '</td>'; 6552 s3 = '<td>' + '<span style="font-size:12px;color:#337ab7">Minimum:</span> ' + '</td><td><b> '+Highcharts.numberFormat(min,digits) + '</b> ' + ' ' + hcensemble_unit + '</td>'; 6553 }else{ 6554 if(main!=null){s0 = '<span style="font-size:12px;color:var(--color-text-black);"><span style="color:black;">■</span> Hauptlauf:</span> ' + '<b>'+Highcharts.numberFormat(main,digits) + '</b> ' + ' ' + hcensemble_unit + '<br/>';} 6555 if(main!=null){s1 = '<span style="font-size:12px;color:var(--color-text);">'+(mean_run !== null ? '<span style="font-size:12px;color:#004a97">●</span> ':'')+'Ensemble Mittelwert:</span> ' + '<b> '+Highcharts.numberFormat(mean_run !== null ? mean_run:mean,digits) + '</b> ' + ' ' + hcensemble_unit + '<br/>';} 6556 else {s1 = '<span style="font-size:12px;color:var(--color-text);">'+(mean_run !== null ? '<span style="font-size:12px;color:#004a97">●</span> ':'')+' Ensemble Mittelwert:</span> ' + '<b> '+Highcharts.numberFormat(mean_run !== null ? mean_run:mean,digits) + '</b> ' + ' ' + hcensemble_unit + '<br/>';} 6557 s2 = '<td>' + '<span style="font-size:12px;color:var(--hc-max-red);">Maximum:</span> ' + '</td><td><b> '+Highcharts.numberFormat(max,digits) + '</b> ' + ' ' + hcensemble_unit + '</td>'; 6558 s3 = '<td>' + '<span style="font-size:12px;color:#337ab7">Minimum:</span> ' + '</td><td><b> '+Highcharts.numberFormat(min,digits) + '</b> ' + ' ' + hcensemble_unit + '</td>'; 6559 } 6560 if(typeof hcensemble_percentiles =='undefined' || typeof this.points[2]=== 'undefined') 6561 $('#ensemble-tooltip').html('<div class="highcharts-tooltip">' +s+s0+s1+'<table><tr>'+s2+'</tr><tr>'+s3+ '</tr></table></div>'); 6562 else{ 6563 s2 += '<td> <span style="font-size:12px;color:var(--hc-max-red);">90% Percentile:</span> ' + '</td><td><b> '+Highcharts.numberFormat(high,digits) + '</b> ' + ' ' + hcensemble_unit + '</td>'; 6564 s3 += '<td> <span style="font-size:12px;color:#337ab7">10% Percentile:</span> ' + '</td><td><b> '+Highcharts.numberFormat(low,digits) + '</b> ' + ' ' + hcensemble_unit + '</td>'; 6565 $('#ensemble-tooltip').html('<div class="highcharts-tooltip2">' +s+s0+s1+'<table><tr>'+s2+'</tr><tr>'+s3+ '</tr></table></div>'); 6566 } 6567 //return '<div class="highcharts-tooltip"></div>'; 6568 return ''; 6569 } 6570 }, 6571 credits: { enabled: false }, 6572 exporting: {
6573 enabled: highcharts_exporting, 6574 allowHTML: true, 6575 filename: ( 6576 (document.querySelector('.panel-heading > span.title')?.innerText || '') + '_' + (document.querySelector('#ensemble-run')?.getAttribute('data-run') || '')).replace(/ü/g, 'ue').replace(/[^\w\s]/g, '').replace(/\s+/g, '_'), 6577 buttons: { 6578 contextButton: { 6579 menuItems: ["downloadPNG", "downloadSVG"], 6580 symbolStroke: cssVar('--color-text'), 6581 theme: { 6582 fill: cssVar('--background-body'), 6583 stroke: cssVar('--background-body'), 6584 style: { 6585 color: cssVar('--color-text'), 6586 fontWeight: 'bold' 6587 }, 6588 states: { 6589 hover: { 6590 fill: cssVar('--background-body'), 6591 style: { color: cssVar('--background-body') } 6592 }, 6593 select: { 6594 fill: cssVar('--background-body'), 6595 style: { color: cssVar('--background-body') } 6596 } 6597 } 6598 } 6599 } 6600 }, 6601 chartOptions: { 6602 chart: { 6603 events: { 6604 load: function() { 6605 return; 6606 }, 6607 redraw: function() { 6608 return; 6609 } 6610 }, 6611 backgroundColor: cssVar('--background-body') 6612 }, 6613 credits: { 6614 enabled: true, 6615 text: window.location.hostname.split('.').slice(-2).join('.'), 6616 position: { 6617 align: 'right', 6618 verticalAlign: 'bottom', 6619 x: -10, 6620 y: -5 6621 }, 6622 style: { 6623 fontSize: '8px', 6624 color: cssVar('--hc-label-textcolor') 6625 } 6626 }, 6627 title: { 6628 text: document.querySelector('.panel-heading > span.title')?.innerText+' ('+document.querySelector('#ensemble-run')?.getAttribute('data-run')+')', 6629 align: 'left', 6630 x: 5, 6631 style: { 6632 fontSize: '11px', 6633 'color': cssVar('--color-text') 6634 } 6635 }, 6636 subtitle: { 6637 text:document.getElementById('myHeadline')?.textContent, 6638 align: 'left', 6639 x: 5, 6640 style: { 6641 fontSize: '11px', 6642 'color': cssVar('--color-text') 6643 } 6644 }, 6645 xAxis: { 6646 labels: { 6647 formatter: function () { 6648 return Highcharts.dateFormat('%e.%m.', this.value); 6649 }, 6650 style: { 6651 fontSize: '7px', 6652 'color': cssVar('--color-text') 6653 }, 6654 x: 18, 6655 y: -5 6656 }, 6657 6658 tickInterval: 24 * 36e5 // Täglicher Tick-Intervall 6659 }, 6660 yAxis: { 6661 labels: { 6662 style: { 6663 fontSize: '8px', 6664 'color': cssVar('--color-text') 6665 }, 6666 } 6667 } 6668 } 6669 }, 6670 navigation: { 6671 buttonOptions: { 6672 verticalAlign: 'bottom', 6673 y: 25 6674 }, 6675 contextButton: { 6676 menuItems: ['downloadPNG', 'downloadSVG', 'separator', 'label'] 6677 } 6678 },
6679 series: xlEnsembleSeries(hcensemblelong_data), 6680 reflow: true 6681 }; 6682 6683 if(ensemble_param == 'relfeuchte' || ensemble_param == 'relfeuchte700' || ensemble_param == 'bedeckungsgrad') { 6684 hc_config.yAxis.min = 0; 6685 hc_config.yAxis.floor = 0; 6686 hc_config.yAxis.max = 100; 6687 hc_config.yAxis.ceiling = 100; 6688 } 6689 6690 return hc_config; 6691 }; 6692 6693 if (typeof hcensemblelong_data != 'undefined' && hcensemblelong_data !== null) { 6694 6695 var ho=null; 6696 ho = highcharts_options(true); 6697 if(hcensemble_positive===1){ ho.yAxis.min=0; ho.yAxis.softMax=1;} 6698 if (ensemble_param === 'supercellindex') { ho.yAxis.max=1; ho.yAxis.min=-1; } 6699 $('#ensemble_graph').highcharts(ho); 6700 6701 var ensembleChart = $('#ensemble_graph').highcharts(); 6702 6703 if(ensembleChart.yAxis[0].dataMax === ensembleChart.yAxis[0].dataMin && ensembleChart.yAxis[0].dataMax === 0) { 6704 ensembleChart.update({ 6705 yAxis: { 6706 softMin: 0, 6707 softMax: 0.0001 6708 } 6709 }, true, false, false); 6710 } 6711 } 6712 else if(typeof hcensembleheat_data != 'undefined' && hcensembleheat_data !== null) { 6713 var ho=null; 6714 ho = highcharts_options(true); 6715 6716 sortEnsembleHeatmapData(); 6717 6718 var category_count = (hc_sorted_heat_cat.length - 1); 6719 var max_category_count = 53; 6720 var step = Math.ceil(category_count / max_category_count); 6721 6722 ho.chart.type = 'heatmap'; 6723 ho.chart.height = Math.ceil((category_count / step) * 8 + 200); 6724 ho.chart.marginLeft = undefined; 6725 ho.chart.spacingBottom = 15; 6726 ho.chart.animation = { 6727 duration: 70 6728 }; 6729 6730 if(ho.chart.scrollablePlotArea.minWidth) { 6731 ho.chart.scrollablePlotArea.minWidth *= 0.9375; 6732 } 6733 6734 if(isEnsembleDailyParameter()) { 6735 ho.chart.scrollablePlotArea.minWidth = hcensemble_heat_timestamps.length * 95; 6736 } 6737 6738 ho.xAxis.gridZIndex = 4; 6739 ho.xAxis.gridLineColor = 'rgba(0,0,0,0.2)'; 6740 ho.xAxis.minorGridLineColor = 'rgba(0,0,0,0.1)'; 6741 6742 var plotBandMin = hcensemble_heat_timestamps[0]; 6743 var plotBandMax = hcensemble_heat_timestamps[sort_range_end]; 6744 ho.xAxis.min = plotBandMin; 6745 ho.xAxis.max = plotBandMax; 6746 ho.xAxis.plotBands = [ 6747 { 6748 borderColor: 'rgba(0,0,0,0.4)', 6749 borderWidth: 1, 6750 color: 'rgba(0,0,0,0.4)', 6751 from: plotBandMin, 6752 to: hcensemble_heat_timestamps[sort_range_value[0]], 6753 zIndex: 4 6754 }, 6755 { 6756 borderColor: 'rgba(0,0,0,0.4)', 6757 borderWidth: 1, 6758 color: 'rgba(0,0,0,0.4)', 6759 from: hcensemble_heat_timestamps[sort_range_value[1]], 6760 to: plotBandMax, 6761 zIndex: 4 6762 } 6763 ]; 6764 6765 ho.yAxis = { 6766 title: 'false', 6767 type: 'category', 6768 categories: hc_sorted_heat_cat, 6769 reversed: true, 6770 floor: 0, 6771 ceiling: hc_sorted_heat_cat.length - 1, 6772 gridLineColor: cssVar('--hc-gridLineColore6e6e6'), 6773 labels: { 6774 step: step, 6775 style: { 6776 fontSize: '9px' 6777 ,'color': cssVar('--color-text') 6778 } 6779 } 6780 }; 6781 ho.legend.enabled = true; 6782 ho.legend.useHTML = true; 6783 ho.legend.width = 300; 6784 ho.legend.symbolWidth = 300; 6785 ho.legend.title = {text: $('#myHeadline').text() + (hcensemble_unit !== '' ? '(' + hcensemble_unit + ')' : ''), style: {fontSize: '11px','color': cssVar('--color-text')}}; 6786 ho.colorAxis = ensembleColorAxis(); 6787 ho.series = hc_sorted_heat_data; 6788 ho.tooltip = { 6789 shared: true, 6790 split: true, 6791 useHTML: true, 6792 padding: 4, 6793 outside: false, 6794 formatter: function () { 6795 var s = '<div style="margin-left: 8px;">' 6796 var x_ts = this.point.x 6797 var date_format = getDynDateFormat(x_ts); 6798 if(isEnsembleDailyParameter()) { 6799 date_format = getDynDayLongFormat(x_ts); 6800 } 6801 6802 var member = hc_sorted_heat_cat_long[this.point.y]; 6803 s += '<span style="font-size:10px;">'+Highcharts.dateFormat(date_format, x_ts)+ '</span> '; 6804 6805 var digits = 0; 6806 6807 if( hcensemble_unit=="mm" || 6808 hcensemble_unit=="cm" || 6809 hcensemble_unit=="hPa" || 6810 hcensemble_unit=="mbar" || 6811 hcensemble_unit=="m/s" || 6812 hcensemble_unit=="K" || 6813 hcensemble_unit=="°C" || 6814 ensemble_param=='sonnenscheindauer24h' ) { 6815 digits = 1; 6816 } 6817 else if( hcensemble_unit=="in" || 6818 hcensemble_unit=="inHg" ){ 6819 digits = 2; 6820 } 6821 else if (ensemble_param === 'supercellindex') { digits=2; } 6822 6823 var val = Highcharts.numberFormat(this.point.value, digits); 6824 6825 s += '<br/>' + '<span style="color:' + this.point.color + '">' + 'â' + '</span> '+ member + ': ' + 6826 '<b>'+ val + '</b> ' + hcensemble_unit; 6827 s += '</div>'; 6828 return s; 6829 } 6830 }; 6831 6832 $('#ensemble_graph').highcharts(ho); 6833 6834 setTimeout(function() { 6835 sortRangeUpdatePlotBands(false); 6836 }, 1000); 6837 } 6838 addGlobalChartScrollHint(document.querySelector('.panel-body' + 6839 '')); 6840}; 6841 6842var isEnsembleDurationParameter = function(param) { 6843 if(!param) param = ensemble_param; 6844 6845 return $.inArray(ensemble_param, ['mintemperatur', 'maxtemperatur', 'niederschlag', 'niederschlag24h', 'schnee24h', 'niederschlagssumme', 'windboeen', 'wind', 'wind850', 'sonnenscheindauer24h']) !== -1; 6846} 6847 6848var isEnsembleDailyParameter = function(param) { 6849 if(!param) param = ensemble_param; 6850 6851 return $.inArray(ensemble_param, ['sonnenscheindauer24h', 'niederschlag24h', 'schnee24h']) !== -1; 6852} 6853 6854var hc_sorted_heat_data = []; 6855var hc_sorted_heat_cat = []; 6856var hc_sorted_heat_cat_long = []; 6857var sortEnsembleHeatmapData = function() { 6858 var sort = $('#forecast-sort-selector').attr('data-value') || 'none'; 6859 6860 var series_array = hcensembleheat_data; 6861 6862 if(sort == 'none') { 6863 hc_sorted_heat_data = $.extend(true, [], hcensembleheat_data); 6864 hc_sorted_heat_cat = hcensemble_heat_categories; 6865 hc_sorted_heat_cat_long = hcensemble_heat_categories_long; 6866 return; 6867 } 6868 6869 var poolSortValues = function(member_values) { 6870 if(member_values == null) return null; 6871 if(sort == 'avg') { 6872 return member_values.reduce(function(prev, cur) { return prev+cur.val; }, member_values[0].val) / member_values.length; 6873 } 6874 if(sort == 'min') { 6875 // Für Parameter wo es kontextuell Sinn macht, ist die Min-Sortierung der niedrigste Max-Wert anstelle des absoluten Min-Wertes 6876 if($.inArray(ensemble_param, ['niederschlag', 'niederschlagssumme', 'schnee', 'mlcape', 'reflektivitaet']) !== -1) { 6877 return -member_values.reduce(function(prev, cur) { return Math.max(prev,cur.val); }, member_values[0].val); 6878 } else { 6879 return -member_values.reduce(function(prev, cur) { return Math.min(prev,cur.val); }, member_values[0].val); 6880 } 6881 } 6882 if(sort == 'max') { 6883 return member_values.reduce(function(prev, cur) { return Math.max(prev,cur.val); }, member_values[0].val); 6884 } 6885 } 6886 6887 var member_array = []; 6888 var gapIndex = hcensemble_heat_categories.indexOf(''); // Gap Category 6889 member_array[gapIndex] = null; 6890 6891 var start_sort_ts = hcensemble_heat_timestamps[sort_range_value[0]]; 6892 var end_sort_ts = hcensemble_heat_timestamps[sort_range_value[1]]; 6893 var lessEquals = isEnsembleDurationParameter() && !isEnsembleDailyParameter(); 6894 var greaterEquals = isEnsembleDurationParameter() && isEnsembleDailyParameter(); 6895 6896 if((lessEquals || greaterEquals) && start_sort_ts == end_sort_ts){ 6897 var count = hcensemble_heat_timestamps.length; 6898 if(sort_range_value[1] + 1 < count) { 6899 end_sort_ts = hcensemble_heat_timestamps[sort_range_value[1] + 1]; 6900 } else { 6901 start_sort_ts = hcensemble_heat_timestamps[sort_range_value[0] - 1]; 6902 } 6903 } 6904 6905 if($.isArray(series_array)) { 6906 series_array.forEach(function(series, sindex) { 6907 if($.isArray(series.data)) { 6908 series.data.forEach(function(data, dindex) { 6909 var ts = data[0] || 0; 6910 var y = data[1] || 0; 6911 var val = data[2] || 0; 6912 6913 if(lessEquals) { 6914 if(ts <= start_sort_ts || ts > end_sort_ts) return; 6915 } else if(greaterEquals) { 6916 if(ts < start_sort_ts || ts >= end_sort_ts) return; 6917 } else { 6918 if(ts < start_sort_ts || ts > end_sort_ts) return; 6919 } 6920 6921 if(y < gapIndex) { 6922 member_array[y] = null; 6923 return; 6924 } 6925 6926 if(typeof member_array[y] === 'undefined') member_array[y] = []; 6927 6928 member_array[y].push({y: y, val: val}); 6929 }); 6930 } 6931 }); 6932 } 6933 6934 var member_sorted = member_array.map(poolSortValues); 6935 var keys = keys = Object.keys(member_sorted); 6936 keys.sort(function(a,b) { 6937 if(member_sorted[b] === null && member_sorted[a] === null) return 0; 6938 if(member_sorted[a] === null && member_sorted[b] !== null) return -1; 6939 if(member_sorted[a] !== null && member_sorted[b] === null) return 1; 6940 6941 return member_sorted[b]-member_sorted[a] 6942 }); 6943 6944 var member_sorted = member_sorted.filter(function (el) { 6945 return el != null; 6946 }); 6947 6948 hc_sorted_heat_cat = []; 6949 hc_sorted_heat_cat_long = []; 6950 keys.forEach(function(index) { 6951 index = +index; 6952 if(typeof hcensemble_heat_categories[index] !== 'undefined') { 6953 hc_sorted_heat_cat.push(hcensemble_heat_categories[index]); 6954 } 6955 if(typeof hcensemble_heat_categories_long[index] !== 'undefined') { 6956 hc_sorted_heat_cat_long.push(hcensemble_heat_categories_long[index]); 6957 } 6958 }); 6959 6960 hc_sorted_heat_data = []; 6961 if($.isArray(series_array)) { 6962 series_array.forEach(function(series, sindex) { 6963 hc_sorted_heat_data[sindex] = $.extend({}, series); 6964 hc_sorted_heat_data[sindex].data = []; 6965 if($.isArray(series.data)) { 6966 series.data.forEach(function(data, dindex) { 6967 var ts = data[0] || 0; 6968 var y = data[1] || 0; 6969 var val = data[2] || 0; 6970 6971 var sortedIndex = keys.indexOf(""+y); 6972 hc_sorted_heat_data[sindex].data.push([ts, sortedIndex, val]); 6973 }); 6974 } 6975 }); 6976 } 6977} 6978 6979var ensembleColorAxis = function() { 6980 6981 //Special Funktion um die Ticks bei log-Farbachsen zu bestimmen 6982 var log2lin = function(num) { 6983 const isNegative = num < 0; 6984 6985 let adjustedNum = Math.abs(num); 6986 6987 if (adjustedNum < 10) { 6988 adjustedNum += (10 - adjustedNum) / 10; 6989 } 6990 6991 const result = Math.log(adjustedNum) / Math.LN10; 6992 return isNegative ? -result : result; 6993 }; 6994 6995 var axis_min = null; 6996 var axis_max = null; 6997 var log = false;
6998 var ticks = undefined; 6999 var tickInterval = undefined; 7000 7001 if (hcensemble_unit== "°C") { axis_min=-40; axis_max=50; ticks = [-30, -20, -10, 0, 10, 20, 30, 40]; } 7002 else if(hcensemble_unit== "K") { axis_min=233.15; axis_max=323.15; } 7003 else if(hcensemble_unit== "°F") { axis_min=-40; axis_max=122; ticks = [-22, -4, 14, 32, 50, 68, 86, 104]; } 7004 else if(hcensemble_unit== "hPa") { axis_min=900; axis_max=1062; ticks = [910, 930, 950, 970, 990, 1010, 1030, 1050]; } 7005 else if(hcensemble_unit=="mbar") { axis_min=900; axis_max=1062; ticks = [910, 930, 950, 970, 990, 1010, 1030, 1050]; } 7006 else if(hcensemble_unit=="inHg") { axis_min=26.58; axis_max=31.36; } 7007 else if(hcensemble_unit=="%") { axis_min=0; axis_max=100; } 7008 7009 var stops = null; 7010 if($.inArray(ensemble_param, ['mintemperatur', 'maxtemperatur', 'temperatur', 'taupunkt', 'temperatur1000', 'temperatur925', 'temperatur850', 'temperatur700', 'feuchtkugeltemperatur']) !== -1) { 7011 stops = [ 7012 [0, '#ff6eff'], 7013 [0.21, '#32007f'], 7014 [0.22, '#00287f'], 7015 [0.31, '#1392ff'], 7016 [0.44, '#d9ecff'], 7017 [0.45, '#b1f1d6'], 7018 [0.51, '#07a127'], 7019 [0.62, '#f3fb01'], 7020 [0.71, '#f46d0b'], 7021 [0.78, '#af0f14'], 7022 [0.81, '#640000'], 7023 [0.89, '#fff0f0'], 7024 [1, '#6d6d6d'], 7025 ]; 7026 } 7027 if($.inArray(ensemble_param, ['relfeuchte', 'relfeuchte700']) !== -1) { 7028 stops = [ 7029 [0, '#ff9226'], 7030 [0.3, '#ffee32'], 7031 [0.6, '#9ac825'], 7032 [0.8, '#36a318'], 7033 [1, '#4a3f7c'], 7034 ]; 7035 } 7036 else if($.inArray(ensemble_param, ['niederschlag', 'niederschlagssumme', 'niederschlag24h', 'schnee24h']) !== -1) { 7037 7038 if(hcensemble_unit== "mm") { ticks = [log2lin(0.5), log2lin(2), log2lin(5), log2lin(10), log2lin(20), log2lin(50), log2lin(100)]; } 7039 else if(hcensemble_unit== "in") { ticks = [log2lin(0.02), log2lin(0.2), log2lin(0.4), log2lin(0.6), log2lin(1), log2lin(1.5), log2lin(2), log2lin(3), log2lin(4)]; } 7040 7041 if(ensemble_model == 'rapid-id2' && ensemble_param == 'niederschlag') { 7042 if(hcensemble_unit== "mm") { axis_min=0; axis_max=125; } 7043 else if(hcensemble_unit== "in") { axis_min=0; axis_max=5; } 7044 } else if(ensemble_param == 'niederschlag' || ensemble_param == 'niederschlag24h' || ensemble_param == 'schnee24h') { 7045 if(hcensemble_unit== "mm") { axis_min=0; axis_max=300; ticks.push(log2lin(200)); } 7046 else if(hcensemble_unit== "in") { axis_min=0; axis_max=12; ticks = [log2lin(0.04), log2lin(0.5), log2lin(1), log2lin(1.5), log2lin(2), log2lin(3), log2lin(4), log2lin(6), log2lin(8), log2lin(10)]; } 7047 } 7048 else { 7049 if(hcensemble_unit== "mm") { axis_min=0; axis_max=500; ticks.push(log2lin(200), log2lin(350)); } 7050 else if(hcensemble_unit== "in") { axis_min=0; axis_max=20; ticks = [log2lin(0.04), log2lin(0.5), log2lin(1), log2lin(2), log2lin(3), log2lin(4), log2lin(6), log2lin(8), log2lin(10), log2lin(15)]; } 7051 } 7052 log = true; 7053 7054 var logMax = log2lin(axis_max); 7055 var stopMult = function(num) { 7056 return log2lin(num) / logMax; 7057 }; 7058 var mult = axis_max / 125; 7059 stops = [ 7060 [stopMult(0*mult), '#f0f0f0'], 7061 [stopMult(0.1*mult), '#b4d7ff'], 7062 [stopMult(4*mult), '#00367f'], 7063 [stopMult(5*mult), '#148f1b'], 7064 [stopMult(7*mult), '#fff42b'], 7065 [stopMult(10*mult), '#f06000'], 7066 [stopMult(20*mult), '#bf0000'], 7067 [stopMult(30*mult), '#64007f'], 7068 [stopMult(80*mult), '#f9e6ff'], 7069 [stopMult(125*mult), '#969696'], 7070 ]; 7071 7072 } 7073 else if(ensemble_param == 'schnee') { 7074 if(hcensemble_unit== "cm") { axis_min=0; axis_max=400; ticks = [log2lin(0.5), log2lin(2), log2lin(5), log2lin(10), log2lin(20), log2lin(50), log2lin(100), log2lin(200), log2lin(300)]; } 7075 else if(hcensemble_unit== "in") { axis_min=0; axis_max=160; ticks = [log2lin(0.2), log2lin(0.8), log2lin(2), log2lin(4), log2lin(8), log2lin(20), log2lin(40), log2lin(80), log2lin(120)]; } 7076 7077 log = true; 7078 7079 var logMax = log2lin(axis_max); 7080 var stopMult = function(num) { 7081 return log2lin(num) / logMax; 7082 }; 7083 var mult = axis_max / 400; 7084 stops = [ 7085 [stopMult(0*mult), '#f8f8f8'], 7086 [stopMult(0.9*mult), '#aaaac8'], 7087 [stopMult(1*mult), '#75baff'], 7088 [stopMult(9*mult), '#00327f'], 7089 [stopMult(10*mult), '#4b007f'], 7090 [stopMult(30*mult), '#c200fb'], 7091 [stopMult(60*mult), '#f4ceff'], 7092 [stopMult(150*mult), '#df093f'], 7093 [stopMult(400*mult), '#460000'], 7094 ]; 7095 7096 } else if(ensemble_param == 'luftdruck') { 7097 var stopMult = function(num) { 7098 return (num - 900) / (1062 - 900); 7099 }; 7100 stops = [ 7101 [0, '#ff6eff'], 7102 [stopMult(962), '#32007f'], 7103 [stopMult(963), '#00287f'], 7104 [stopMult(978), '#00528f'], 7105 [stopMult(990), '#c7e4ff'], 7106 [stopMult(1002), '#07a127'],
7107 [stopMult(1020), '#f3fb01'], 7108 [stopMult(1032), '#e83709'], 7109 [stopMult(1044), '#780000'], 7110 [stopMult(1058), '#fff0f0'], 7111 [1, '#c5c5c5'], 7112 ]; 7113 } else if(ensemble_param == 'geopotential') { 7114 if (hcensemble_unit== "m") { axis_min=4640; axis_max=6100; ticks = [4700, 5000, 5200, 5400, 5600, 5800, 6050]; } 7115 else if(hcensemble_unit== "ft") { axis_min=15223; axis_max=20013; ticks = [15400, 16400, 17100, 17700, 18400, 19000, 19850]; } 7116 7117 var stopMult = function(num) { 7118 return (num - 4640) / (6100 - 4640); 7119 }; 7120 stops = [ 7121 [0, '#ff6eff'], 7122 [stopMult(5060), '#32007f'], 7123 [stopMult(5080), '#00287f'], 7124 [stopMult(5200), '#00528f'], 7125 [stopMult(5320), '#0082ef'], 7126 [stopMult(5500), '#d9ecff'], 7127 [stopMult(5520), '#aaf682'], 7128 [stopMult(5660), '#f4d90b'], 7129 [stopMult(5780), '#dc2708'], 7130 [stopMult(5980), '#640000'], 7131 [1, '#ffb4b4'], 7132 ]; 7133 } 7134 else if($.inArray(ensemble_param, ['windboeen', 'wind', 'wind850']) !== -1) { 7135 if(hcensemble_unit=="m/s") { 7136 axis_min=0; axis_max=51; tickInterval=4; 7137 var stopMult = function(num) { return (num - axis_min) / (axis_max - axis_min); }; 7138 7139 stops = [ 7140 [0, '#ffffff'], 7141 [stopMult(9), '#3c96f5'], 7142 [stopMult(12), '#1eb41e'], 7143 [stopMult(18), '#c8ffbe'], 7144 [stopMult(19.5), '#fffaaa'], 7145 [stopMult(24), '#ffa000'], 7146 [stopMult(25.5), '#ff6000'], 7147 [stopMult(31.5), '#a50000'], 7148 [stopMult(33), '#a900ba'], 7149 [stopMult(38.5), '#ffffff'], 7150 [1, '#643c32'], 7151 ]; 7152 } else if(hcensemble_unit == 'Bft') { 7153 axis_min=0.5; axis_max=12.5; tickInterval=1; 7154 var stopMult = function(num) { return (num - axis_min) / (axis_max - axis_min); }; 7155 7156 stops = [ 7157 [0, '#7d7d7d'], 7158 [stopMult(4), '#68ac06'], 7159 [stopMult(6), '#b5d000'], 7160 [stopMult(8), '#ffe204'], 7161 [stopMult(9), '#f4880b'], 7162 [stopMult(10), '#ff3131'], 7163 [stopMult(11), '#ff3891'], 7164 [stopMult(12), '#ff8cbf'], 7165 [1, '#ff8cbf'], 7166 ]; 7167 } else { 7168 if(hcensemble_unit=="km/h" || hcensemble_unit=="kph") { axis_min=0; axis_max=299.9; tickInterval = 30; } 7169 else if(hcensemble_unit== "mph") { axis_min=0; axis_max=186; tickInterval = 15; } 7170 else if(hcensemble_unit== "kn") { axis_min=0; axis_max=162; tickInterval = 15;} 7171 7172 var stopMult = function(num) { 7173 return (num - 0) / (300 - 0); 7174 }; 7175 7176 stops = [ 7177 [0, '#449900'], 7178 [stopMult(50), '#fafc22'], 7179 [stopMult(80), '#fb7929'], 7180 [stopMult(100), '#fc2256'], 7181 [stopMult(130), '#fc22f6'], 7182 [stopMult(200), '#ffffff'], 7183 [1, '#6969ff'], 7184 ]; 7185 } 7186 } else if(ensemble_param == 'reflektivitaet') { 7187 axis_min=0; axis_max=71; tickInterval=5; 7188 7189 var stopMult = function(num) { 7190 return (num - axis_min) / (axis_max - axis_min); 7191 }; 7192 stops = [ 7193 [0, '#5f5f5f'], 7194 [stopMult(10), '#00e2ee'], 7195 [stopMult(19.99), '#0000f6'], 7196 [stopMult(20), '#00f700'], 7197 [stopMult(34.99), '#008f00'], 7198 [stopMult(35), '#ffff00'], 7199 [stopMult(40), '#e7b400'], 7200 [stopMult(45), '#ff6400'], 7201 [stopMult(50), '#ff0000'], 7202 [stopMult(59.99), '#9e0000'], 7203 [stopMult(60), '#ffc8ff'], 7204 [stopMult(70), '#8c008c'], 7205 [1, '#8c008c'], 7206 ]; 7207 } else if(ensemble_param == 'supercellindex') { 7208 axis_min=-0.6; axis_max=1; 7209 7210 var stopMult = function(num) { 7211 return (num - axis_min) / (axis_max - axis_min); 7212 }; 7213 stops = [ 7214 [0, '#00367f'], 7215 [stopMult(-0.05), '#d2e9ff'], 7216 [stopMult(0), '#ffffff'], 7217 [stopMult(0.05), '#63ed07'], 7218 [stopMult(0.1), '#97c90e'], 7219 [stopMult(0.2), '#e8dc00'], 7220 [stopMult(0.3), '#fff42b'], 7221 [stopMult(0.4), '#ffa66a'], 7222 [stopMult(0.5), '#f84e78'], 7223 [stopMult(0.6), '#f71e54'], 7224 [stopMult(0.7), '#bf0000'], 7225 [stopMult(0.8), '#880000'], 7226 [stopMult(0.9), '#64007f'], 7227 [1, '#c200fb'], 7228 ]; 7229 } else if(ensemble_param == 'mlcape') { 7230 axis_min=10.1; axis_max=12000; 7231 ticks = [log2lin(10), log2lin(20), log2lin(40), log2lin(100), log2lin(200), log2lin(400), log2lin(1000), log2lin(2000), log2lin(4000), log2lin(8000)]; 7232 log = true; 7233 7234 var stopMult = function(num) { 7235 return (log2lin(num) - log2lin(axis_min)) / (log2lin(axis_max) - log2lin(axis_min)); 7236 }; 7237 // stopMult = function(num) { 7238 // return (num - axis_min) / (axis_max - axis_min); 7239 // }; 7240 stops = [ 7241 [0, '#1e7800'], 7242 [stopMult(400), '#fafc22'], 7243 [stopMult(1000), '#fb7929'],
7244 [stopMult(1400), '#fc222f'], 7245 [stopMult(2400), '#fc22f6'], 7246 [stopMult(5000), '#fedffd'], 7247 [stopMult(8000), '#6969ff'], 7248 [1, '#6969ff'], 7249 ]; 7250 } else if(ensemble_param == 'sonnenscheindauer24h') { 7251 axis_min=0; axis_max= hcensemble_max_sunshine || null; 7252 7253 stops = [ 7254 [0, '#4c473b'], [0.5, '#d9aa36'], [1, '#fff72e'], 7255 ]; 7256 7257 if(hcensemble_max_sunshine === 0) { 7258 stops = [ 7259 [0, '#4c473b'], [1, '#4c473b'], 7260 ]; 7261 } 7262 } else if(ensemble_param == 'bedeckungsgrad') { 7263 axis_min=0; axis_max= 100; 7264 7265 stops = [ 7266 [0, '#ffea00'], [0.4, '#a29617'], [0.6, '#7d7520'], [1, '#323232'], 7267 ]; 7268 } else if(ensemble_param == 'dirstrahlung' || ensemble_param == 'diffstrahlung') { 7269 axis_min=0; axis_max= 500; 7270 7271 if(typeof hcensemble_data_max !== 'undefined') { 7272 if(hcensemble_data_max > 500) axis_max = 700; 7273 if(hcensemble_data_max > 700) axis_max = 900; 7274 if(hcensemble_data_max > 900) axis_max = 1000; 7275 } 7276 7277 stops = [ 7278 [0, '#4c473b'], [0.5, '#d9aa36'], [1, '#fff72e'], 7279 ]; 7280 } 7281 7282 var colorAxis = { 7283 stops: stops, 7284 min: axis_min, 7285 max: axis_max, 7286 startOnTick: false, 7287 endOnTick: false, 7288 tickPositions: ticks, 7289 tickInterval: tickInterval, 7290 gridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 7291 labels: { 7292 format: '{value}', 7293 style: { 7294 fontSize: "9px", 7295 'color': cssVar('--color-text') 7296 } 7297 }, 7298 type: log ? 'logarithmic' : 'linear', 7299 allowNegativeLog: true 7300 }; 7301 7302 if(!ticks) colorAxis.tickPixelInterval = 50; 7303 7304 // console.log(colorAxis); 7305 return colorAxis; 7306} 7307 7308var loadGraphEnsembleLong = function() { 7309 ajaxLoaderShow(); 7310 var params = { 7311 'city_id' : $('#city-id').val(), 7312 'model' : ensemble_model, 7313 'model_view' : $('#forecast-view-selector').attr('data-value'), 7314 'param' : ensemble_param 7315 }; 7316 hcensemblelong_data = null; 7317 hcensembleheat_data = null; 7318 $.get(get_url_path()+'/ajax/ensemble', params, function (data) { 7319 $('#ensemble-response').html(data); 7320 ajaxLoaderHide(); 7321 $('#myHeadline').css("visibility", 'visible'); 7322 $('#forecast-ensemble-parameters').css("visibility", 'visible'); 7323 setupSortRangeSlider(); 7324 plotGraphEnsembleLong(); 7325 showSortRangeSlider();
7326 setAccListener(); 7327 }); 7328}; 7329 7330var plotWeatherTrend14days = function() { 7331 if (typeof hccompact_data_14days_maxmin != 'undefined') { 7332 var tempsize = 16; 7333 if ($('body').width()<768) { 7334 tempsize = 10; 7335 } 7336 var zeroline = 0; 7337 if(hccompact_units['temp']== "°F") { 7338 zeroline = 32; 7339 } 7340 else if(hccompact_units['temp']=="K") { 7341 zeroline = 273.15; 7342 } 7343 Highcharts.chart('trend-14days', { 7344 chart: { 7345 type: 'line', 7346 height: 360, 7347 marginTop: 30, 7348 events: { 7349 load: function(){ 7350 drawBlocksForWindSymbols(this); 7351 //drawWindArrows(this); 7352 }, 7353 redraw: function(){ 7354 drawBlocksForWindSymbols(this); 7355 //drawWindArrows(this); 7356 } 7357 } 7358 }, 7359 title: false, 7360 xAxis: [{ 7361 categories: hccompact_data_14days_xaxis, 7362 tickInterval: 1, 7363 gridLineWidth: 1, 7364 gridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 7365 gridZIndex:2, 7366 offset: 0 7367 },{ 7368 categories: hccompact_data_14days_xaxis2, 7369 tickInterval: 1, 7370 gridLineWidth: 1, 7371 gridLineColor: cssVar('--hc-gridLineColorCCCCCC'), 7372 gridZIndex:3, 7373 opposite:true, 7374 offset: 0, 7375 plotBands: hccompact_data_14days_weekend 7376 }], 7377 yAxis: { 7378 title: false, 7379 labels: { 7380 enabled: false 7381 }, 7382 max: hccompact_data_14days_yhigh+5, 7383 min: hccompact_data_14days_ylow, 7384 plotLines: [{ 7385 value: zeroline, 7386 width: 2, 7387 color: '#808080', 7388 zIndex: 2 7389 }], 7390 }, 7391 tooltip: { 7392 crosshairs: true, 7393 shared: true, 7394 useHTML: true, 7395 outside: false, 7396 positioner: tooltipPositioner, 7397 formatter: function() { 7398 var s = []; 7399 var counter=0; 7400 var durchlauf=1; 7401 var tmaxmin=''; 7402 var windtext=''; 7403 var counter=0; 7404 var img = '', rain='',maxminv=''; 7405 s.push('<div class="w14-bg">'); 7406 $.each(this.points, function(i, p) { 7407 if (counter===0 && typeof hccompact_data_14days_gusts[a] !== 'undefined' 7408 && typeof hccompact_data_14days_gusts_raw[a] !== 'undefined') { 7409 var a=this.series.data.indexOf( this.point ); 7410 img = getWindSymbol(hccompact_data_14days_gusts_raw[a]); 7411 if (img.length>0) { 7412 if (displayFCUnitV() == 'kmh') { 7413 b = Math.round(Math.ceil(b/5)*5); 7414 } 7415 else { 7416 b = Math.round(b); 7417 } 7418 var einheit = $('#w-14days-data').attr('data-gunit'); 7419 windtext = $('#w-14days-data').attr('data-gusts')+' '+b+(einheit === 'Bft' ? ' ':'')+einheit; 7420 } 7421 } 7422 if (counter===0 && typeof hccompact_data_14days_rsym !== 'undefined') { 7423 var a=this.series.data.indexOf( this.point ); 7424 var b=hccompact_data_14days_tsym[a]; 7425 var c=hccompact_data_14days_rsym[a]; 7426 if (b !== 'null') { 7427 rain = b; 7428 } 7429 else if (c !== 'null') { 7430 rain = c; 7431 } 7432 } 7433 counter++; 7434 }); 7435 7436 if (img.length>0 || rain.length>0) { 7437 s.push('<div class="w14-s">'); 7438 if (rain.length>0) { 7439 s.push('<img src="/images/symbole/'+rain+'" alt="" /> '); 7440 } 7441 if (img.length>0) { 7442 s.push('<img src="/images/symbole/'+img+'" alt="'+windtext+'" />'); 7443 } 7444 s.push('</div>'); 7445 } 7446 7447 counter=0; 7448 $.each(this.points, function(i, p) { 7449 if (counter===0) { 7450 s.push('<div class="w14-date">'+p.x +'</div>'); 7451 s.push('<div class="clearfix"></div>'); 7452 } 7453 if (durchlauf === 1 || durchlauf === 2) { 7454 var a=this.series.data.indexOf( this.point ); 7455 $.each(hccompact_data_14days_maxmin, function(j,q) { 7456 if (j === durchlauf) { 7457 if (typeof q.data !== 'undefined' && typeof q.data[a] !== 'undefined' && q.data[a] !== null) { 7458 if (durchlauf === 1) { 7459 tmaxmin=$('#w-14days-data').attr('data-max'); //'Höchsttemperatur'; 7460 maxminv='max'; 7461 } 7462 else { 7463 tmaxmin=$('#w-14days-data').attr('data-min'); //'Tiefsttemperatur'; 7464 maxminv='min'; 7465 } 7466 s.push('<div class="w14-tmaxmin">'+tmaxmin+': <span class="w-t'+maxminv+'-v">'+Highcharts.numberFormat(q.data[a],0)+hccompact_units['temp']+'</span></div>'); 7467 } 7468 } 7469 }); 7470 durchlauf++; 7471 } 7472 var min_max=-999, min_min=1000; 7473 if (p.point.low < min_min) { min_min=p.point.low; } 7474 if (p.point.high < min_min) { min_min=p.point.high; } 7475 if (p.point.low > min_max) { min_max=p.point.low; } 7476 if (p.point.high > min_max) { min_max=p.point.high; } 7477 if (min_max !== -999 && min_min !== 1000) { 7478 s.push('<div class="w14-tmaxmin-range">'+p.series.name +' '+$('#w-14days-data').attr('data-from')+' '+Highcharts.numberFormat(min_min,0) +hccompact_units['temp']+' '+$('#w-14days-data').attr('data-to')+' ' +Highcharts.numberFormat(min_max,0) +hccompact_units['temp']+ '</div>'); 7479 } 7480 counter++; 7481 }); 7482 if (windtext.length>0) { 7483 s.push(windtext); 7484 } 7485 counter=0; 7486 $.each(this.points, function(i, p) { 7487 if (counter===0 && typeof hccompact_data_14days_prob !== 'undefined') { 7488 var a=this.series.data.indexOf( this.point ); 7489 if (hccompact_data_14days_word[a].length>0) { 7490 s.push('<div class="w14-prob">' + 7491 hccompact_data_14days_word[a] +'</div>'); 7492 } 7493 } 7494 counter++; 7495 }); 7496 s.push('</div>'); 7497 7498 return '<div class="highcharts-tooltip highcharts-tooltip-14">' + s.join('') + '</div>'; 7499 } 7500 }, 7501 plotOptions: { 7502 line: { 7503 dataLabels: { 7504 enabled: true, 7505 formatter: function () { 7506 return Highcharts.numberFormat(this.y,0)+(hccompact_units['temp'] == 'K' ? '':'°'); 7507 }, 7508 style: { 7509 fontSize: tempsize, 7510 'color': cssVar('--color-text') 7511 } 7512 }, 7513 enableMouseTracking: false 7514 } 7515 }, 7516 credits: { enabled: false }, 7517 exporting: { enabled: false }, 7518 series: hccompact_data_14days_maxmin 7519 }); 7520 } 7521}; 7522 7523var plotWeatherTrend14daysV2 = function() { 7524 if (typeof hc_data_14days_maxmin != 'undefined') { 7525 var tempsize = 16; 7526 if ($('body').width()<768) { 7527 tempsize = 10; 7528 } 7529 var zeroline = 0; 7530 if(hccompact_units['temp']== "°F") { 7531 zeroline = 32; 7532 } 7533 else if(hccompact_units['temp']=="K") { 7534 zeroline = 273.15; 7535 } 7536 plotWeatherTrend14daysV2short(62); 7537 7538 var hc_axis_height = 0; 7539 Highcharts.chart('trend-14days-sun', { 7540 chart: { 7541 type: 'column', 7542 height: 220, 7543 marginTop:20, 7544 marginLeft:62, 7545 events: { 7546 load: function(){ 7547 //yAxis Scaling 7548 var topSpacing = 42+16+8; 7549 var bottomSpacing = 4; 7550 7551 hc_axis_height = this.plotHeight - topSpacing - bottomSpacing; 7552 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7553 drawBlocksForSunSymbolsV2(this); 7554 }, 7555 redraw: function(){ 7556 //yAxis Scaling 7557 var topSpacing = 42+16+8; 7558 var bottomSpacing = 4; 7559 7560 var yAxisHeight = this.plotHeight - topSpacing - bottomSpacing; 7561 if(yAxisHeight !== hc_axis_height) { 7562 hc_axis_height = yAxisHeight; 7563 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7564 } 7565 drawBlocksForSunSymbolsV2(this); 7566 } 7567 } 7568 }, 7569 title: false, 7570 xAxis: [{ 7571 categories: hc_data_14days_xaxis, 7572 tickInterval: 1, 7573 gridLineWidth: 1, 7574 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7575 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7576 lineWidth: 1, 7577 7578 gridZIndex: 1, 7579 plotBands: hc_data_14days_weekend, 7580 labels: { 7581 style: { 7582 color: cssVar('--color-text') 7583 } 7584 } 7585 }], 7586 yAxis: [{ 7587 title: false, 7588 tickInterval: hc_data_14days_sun_high, 7589 minorTickInterval: 1, 7590 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7591 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7592 7593 // maxPadding: 0.5, 7594 //tickLength: 10, 7595 // max: hc_data_14days_sun_high, 7596 ceiling: hc_data_14days_sun_high, 7597 // endOnTick: false, 7598 // min: 0, 7599 floor: 0, 7600 top: 42+16+8, 7601 height: '55%', 7602 labels: { 7603 formatter: function () { 7604 return Highcharts.numberFormat(this.value, 0)+hccompact_units['sunhours']; 7605 }, 7606 x: -7, 7607 style: { 7608 color: cssVar('--color-text') 7609 } 7610 } 7611 7612 }, { 7613 title: false, 7614 opposite: true, 7615 labels: { enabled: false }, 7616 tickAmount: 2, 7617 min: 0, 7618 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7619 gridLineWidth: 1, 7620 max: hc_data_14days_sun_high 7621 }], 7622 credits: { enabled: false }, 7623 exporting: { enabled: false },
7624 tooltip: tooltip14DaysTrendSun, 7625 series: hc_data_14days_sun 7626 }); 7627 7628 var hc_axis_height = 0; 7629 Highcharts.chart('trend-14days-rain', { 7630 chart: { 7631 type: 'column', 7632 height: 230, 7633 marginTop:20, 7634 marginLeft:62, 7635 events: { 7636 load: function(){ 7637 //yAxis Scaling 7638 var topSpacing = 17+16+8; 7639 var bottomSpacing = 4; 7640 7641 hc_axis_height = this.plotHeight - topSpacing - bottomSpacing; 7642 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7643 drawBlocksForRainSymbolsV2(this); 7644 }, 7645 redraw: function(){ 7646 //yAxis Scaling 7647 var topSpacing = 17+16+8; 7648 var bottomSpacing = 4; 7649 7650 var yAxisHeight = this.plotHeight - topSpacing - bottomSpacing; 7651 if(yAxisHeight !== hc_axis_height) { 7652 hc_axis_height = yAxisHeight; 7653 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7654 } 7655 drawBlocksForRainSymbolsV2(this); 7656 } 7657 } 7658 }, 7659 title: false, 7660 xAxis: [{ 7661 categories: hc_data_14days_xaxis, 7662 tickInterval: 1, 7663 gridLineWidth: 1, 7664 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7665 gridZIndex: 1, 7666 7667 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7668 lineWidth: 1, 7669 offset: 0, 7670 plotBands: hc_data_14days_weekend, 7671 labels: { 7672 style: { 7673 color: cssVar('--color-text') 7674 } 7675 } 7676 }], 7677 yAxis: [{ 7678 title: false, 7679 tickInterval: (hc_data_14days_rain_high <= 20 ? 5 : ((hc_data_14days_rain_high > 300 ? 100 : (hc_data_14days_rain_high > 120 ? 50 : 10)))), 7680 minorTickInterval: "auto", 7681 max: hc_data_14days_rain_high, 7682 floor: 0, 7683 top: 17+16+8, 7684 height: '55%', 7685 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7686 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7687 labels: { 7688 formatter: function () { 7689 var digits = 0; 7690 if (hccompact_units['rain'] == 'in') { digits=1; } 7691 return Highcharts.numberFormat(this.value, digits)+hccompact_units['rain']; 7692 }, 7693 x: -7, 7694 style: { 7695 color: cssVar('--color-text') 7696 } 7697 } 7698 }, { 7699 title: false, 7700 opposite: true, 7701 labels: { enabled: false }, 7702 tickAmount: 2, 7703 min: 0, 7704 max: hc_data_14days_rain_high, 7705 }], 7706 credits: { enabled: false }, 7707 exporting: { enabled: false }, 7708 tooltip: tooltip14DaysTrendRain, 7709 series: hc_data_14days_rain 7710 }); 7711 7712 var hc_axis_height = 0; 7713 Highcharts.chart('trend-14days-gusts', { 7714 chart: { 7715 type: 'column', 7716 height: 220, 7717 marginTop:20, 7718 marginLeft:62, 7719 events: { 7720 load: function(){ 7721 //yAxis Scaling 7722 var topSpacing = 20; 7723 var bottomSpacing = 4; 7724 7725 hc_axis_height = this.plotHeight - topSpacing - bottomSpacing; 7726 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7727 drawBlocksForGustSymbolsV2(this); 7728 }, 7729 redraw: function(){ 7730 //yAxis Scaling 7731 var topSpacing = 20; 7732 var bottomSpacing = 4; 7733 7734 var yAxisHeight = this.plotHeight - topSpacing - bottomSpacing; 7735 if(yAxisHeight !== hc_axis_height) { 7736 hc_axis_height = yAxisHeight; 7737 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7738 } 7739 drawBlocksForGustSymbolsV2(this); 7740 } 7741 } 7742 }, 7743 title: false, 7744 xAxis: [{ 7745 categories: hc_data_14days_xaxis, 7746 tickInterval: 1, 7747 gridLineWidth: 1, 7748 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7749 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7750 lineWidth: 1, 7751 gridZIndex: 1, 7752 offset: 0, 7753 labels: { 7754 style: { 7755 color: cssVar('--color-text') 7756 } 7757 }, 7758 plotBands: hc_data_14days_weekend 7759 }], 7760 yAxis: [{ 7761 title: false, 7762 tickInterval: hccompact_units['wind'] == 'Bft' ? 3 : (hc_data_14days_gusts_high <= 20 ? 5 : ((hc_data_14days_gusts_high > 300 ? 100 : (hc_data_14days_gusts_high >= 100 ? 50 : 20)))), 7763 minorTickInterval: hccompact_units['wind'] == 'Bft' ? 1 : "auto", 7764 max: hccompact_units['wind'] == 'Bft' ? 13 : hc_data_14days_gusts_high, 7765 min: 0, 7766 floor: 0, 7767 top: 20, 7768 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7769 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7770 height: '55%', 7771 labels: { 7772 formatter: function () { 7773 var digits = 0; 7774 return hccompact_units['wind'] == 'Bft' ? (this.value <= 12 ? Highcharts.numberFormat(this.value, digits)+hccompact_units['wind'] : '') : Highcharts.numberFormat(this.value, digits)+hccompact_units['wind']; 7775 }, 7776 x: -7, 7777 style: { 7778 color: cssVar('--color-text') 7779 } 7780 } 7781 }, { 7782 title: false, 7783 opposite: true, 7784 labels: { enabled: false }, 7785 tickAmount: 2, 7786 min: 0, 7787 max: hc_data_14days_gusts_high, 7788 }], 7789 credits: { enabled: false }, 7790 exporting: { enabled: false }, 7791 tooltip: tooltip14DaysTrendGusts, 7792 series: hc_data_14days_wind 7793 }); 7794 } 7795}; 7796 7797var plotWeatherTrend14daysV2short = function(mLeft) { 7798 var hc_axis_height = 0; 7799 if (typeof hc_data_14days_maxmin != 'undefined') { 7800 var tempsize = 16; 7801 if ($('body').width()<768) { 7802 tempsize = 10; 7803 } 7804 var zeroline = 0; 7805 if(hccompact_units['temp']== "°F") { 7806 zeroline = 32; 7807 } 7808 else if(hccompact_units['temp']=="K") { 7809 zeroline = 273.15; 7810 } 7811 var mLabels = { enabled: false }; 7812 if (typeof mLeft == 'undefined') { 7813 mLeft=0; 7814 } 7815 else { 7816 mLabels = { 7817 format: '{value}'+hccompact_units['temp'], 7818 x: -7, 7819 style: { 7820 color: cssVar('--color-text') 7821 } 7822 }; 7823 } 7824 Highcharts.chart('trend-14days', { 7825 chart: { 7826 7827 type: 'line', 7828 height: 360, 7829 marginTop: 22, 7830 marginLeft: mLeft, 7831 events: { 7832 load: function(){ 7833 //yAxis Scaling 7834 var topSpacing = 22; 7835 var bottomSpacing = 16; 7836 7837 hc_axis_height = this.plotHeight - topSpacing - bottomSpacing; 7838 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7839 drawBlocksFor14DaysTrendV2short(this); 7840 }, 7841 redraw: function(){ 7842 var topSpacing = 22; 7843 var bottomSpacing = 16; 7844 7845 var yAxisHeight = this.plotHeight - topSpacing - bottomSpacing; 7846 if(yAxisHeight !== hc_axis_height) { 7847 hc_axis_height = yAxisHeight; 7848 this.yAxis[0].update({height: hc_axis_height, top: topSpacing}, true); 7849 } 7850 drawBlocksFor14DaysTrendV2short(this); 7851 }, 7852 render: function() { 7853 // Vorherige Linie entfernen, falls vorhanden 7854 if (this.customLeftBorder) this.customLeftBorder.destroy(); 7855 7856 // Neue Linie zeichnen 7857 this.customLeftBorder = this.renderer.path([ 7858 'M', this.plotLeft, this.plotTop, 7859 'L', this.plotLeft, this.plotTop + this.plotHeight 7860 ]) 7861 .attr({ 7862 stroke: cssVar('--hc-xl-dayline', '#DCE2E8'), 7863 'stroke-width': 1, 7864 zIndex: 5 7865 }) 7866 .add(); 7867 } 7868 } 7869 }, 7870 title: false, 7871 xAxis: [{ 7872 categories: hc_data_14days_xaxis, 7873 labels: { 7874 style: {color : cssVar('--color-text')} 7875 }, 7876 tickInterval: 1, 7877 gridLineWidth: 1, 7878 lineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7879 lineWidth: 1, 7880 gridLineColor: cssVar('--hc-xl-dayline', '#DCE2E8'), 7881 gridZIndex: 1, 7882 offset: 0, 7883 7884 plotBands: hc_data_14days_weekend 7885 }], 7886 yAxis: [{ 7887 title: false, 7888 labels: { enabled: false }, 7889 max: hc_data_14days_yhigh, 7890 min: hc_data_14days_ylow, 7891 gridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7892 minorGridLineColor: cssVar('--hc-xl-grid', '#EEF1F4'), 7893 tickInterval: hccompact_units['temp'] == '°F' ? 10: 5, 7894 minorTickInterval: hccompact_units['temp'] == '°F' ? 'auto': 1, 7895 plotLines: [{ 7896 value: zeroline, 7897 width: 1, 7898 color: cssVar('--hc-xl-zeroline', '#C3CAD1'), 7899 zIndex: 2 7900 }], 7901 top: 22, 7902 height: '55%', 7903 labels: mLabels 7904 }, 7905 { 7906 title: false, 7907 opposite: true, 7908 labels: { enabled: false }, 7909 }], 7910 tooltip: tooltip14DaysTrend, 7911 plotOptions: { 7912 line: { 7913 dataLabels: { 7914 enabled: true, 7915 formatter: function () { 7916 return Highcharts.numberFormat(this.y,0)+(hccompact_units['temp'] == 'K' ? '':'°'); 7917 }, 7918 style: { 7919 fontSize: tempsize, 7920 'color': cssVar('--color-text') 7921 } 7922 }, 7923 enableMouseTracking: false 7924 } 7925 }, 7926 credits: { enabled: false }, 7927 exporting: { enabled: false }, 7928 series: hc_data_14days_maxmin 7929 }); 7930 7931 } 7932}; 7933 7934var getDateForTitle = function(timeserie) { 7935 fromyear = new Date(timeserie[0].data[0][0]).getFullYear(); 7936 untilyear = new Date(timeserie[0]['data'][timeserie[0]['data'].length - 1][0]).getFullYear(); 7937 if (fromyear != untilyear) { 7938 frommonth = new Date(timeserie[0].data[0][0]).getMonth() +1; 7939 untilmonth = new Date(timeserie[0]['data'][timeserie[0]['data'].length - 1][0]).getMonth() +1; 7940 return frommonth+"/"+fromyear+" - "+untilmonth+"/"+untilyear+" "; 7941 } else { 7942 return fromyear+" "; 7943 } 7944} 7945var plotKlimaVergleich = function() { 7946 7947 var exportConfig = {
7948 enabled: highcharts_exporting 7949 }; 7950 7951 var themedExportConfig = { 7952 enabled: highcharts_exporting, 7953 allowHTML: true, 7954 buttons: { 7955 contextButton: { 7956 symbolStroke: cssVar('--color-text'), 7957 theme: { 7958 fill: cssVar('--background-body'), 7959 stroke: cssVar('--background-body'), 7960 style: { 7961 color: cssVar('--color-text'), 7962 fontWeight: 'bold' 7963 }, 7964 states: { 7965 hover: { 7966 fill: cssVar('--background-body'), 7967 style: { color: cssVar('--background-body') } 7968 }, 7969 select: { 7970 fill: cssVar('--background-body'), 7971 style: { color: cssVar('--background-body') } 7972 } 7973 } 7974 } 7975 } 7976 }, 7977 chartOptions: { 7978 title: { 7979 style: { 7980 color: cssVar('--color-text') 7981 } 7982 }, 7983 chart: { 7984 events: { 7985 load: function () { 7986 return; 7987 }, 7988 redraw: function () { 7989 return; 7990 } 7991 }, 7992 backgroundColor: cssVar('--background-body') 7993 }, 7994 } 7995 }; 7996 7997 if (typeof station_rr24_acc_data != 'undefined') { 7998 $('#klimavergleich-chart-rr24h').highcharts({ 7999 chart: { 8000 height: 320//, 8001 }, 8002 title: {text: ($('#klimavergleich-chart-rr24h').prev('label').length > 0) ? $('#klimavergleich-chart-rr24h').prev('label').text()+getDateForTitle(station_rr24_acc_data) : 'Chart'}, 8003 legend: { 8004 useHTML: true 8005 }, 8006 xAxis: [{ 8007 type: 'datetime', 8008 dateTimeLabelFormats: { 8009 hour: false, 8010 day: '%b %Y' 8011 }, 8012 labels:{ 8013 useHTML: true, 8014 align: 'center', 8015 formatter: function () { 8016 return Highcharts.dateFormat('%b %Y', this.value); 8017 } 8018 } 8019 },{ 8020 type: 'datetime', 8021 dateTimeLabelFormats: { 8022 hour: '%H:%M', 8023 day: '%e. %b' 8024 }, 8025 labels:{ 8026 useHTML: true, 8027 align: 'center', 8028 formatter: function () { 8029 var date_format; 8030 var day = Highcharts.dateFormat("%e", this.value); 8031 var hour = Highcharts.dateFormat("%H", this.value); 8032 if(hour%24==0) 8033 date_format='%e. %b'; 8034 else 8035 date_format='%H:%M'; 8036 return Highcharts.dateFormat(date_format, this.value); 8037 } 8038 } 8039 }], 8040 yAxis: [{ 8041 title: { 8042 text: 'Monatssummen' 8043 }, 8044 floor: 0, 8045 labels: { 8046 format: "{value} mm" 8047 }, 8048 min:0, 8049 softMax: 10, 8050 allowDecimals: false, 8051 minorTickInterval: 1, 8052 //gridLineColor: '#C0C0C0', 8053 tickAmount: 6 8054 },{ 8055 title: { 8056 text: 'Akkumulierter Niederschlag' 8057 }, 8058 floor: 0, 8059 labels: { 8060 format: "{value} mm" 8061 }, 8062 opposite: true, 8063 min:0, 8064 softMax: 10, 8065 allowDecimals: false, 8066 minorTickInterval: 1, 8067 //gridLineColor: '#C0C0C0', 8068 tickAmount: 6 8069 }], 8070 tooltip: { 8071 crosshairs: true, 8072 shared: true, 8073 valueSuffix: ' mm',
8074 shape: 'square', 8075 useHTML: true, 8076 zIndex: 50, 8077 /*positioner: function (w,h,p) { 8078 if(p.plotX/this.chart.chartWidth>0.5) 8079 return { x: 65, y: 0 }; 8080 else 8081 return { x: this.chart.chartWidth-w-10, y: 0 }; 8082 },*/ 8083 formatter: function () { 8084 var date_format; 8085 date_format="%A, den %e.%B"; 8086 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 8087 this.points.sort( ordertooltip ); 8088 $.each(this.points, function () { 8089 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 8090 '<b>'+Math.round(this.y*10)/10 + '</b> ' + ' mm'; 8091 }); 8092 return s; 8093 } 8094 }, 8095 credits: { enabled: false }, 8096 exporting: { exportConfig }, 8097 series: station_rr24_acc_data, 8098 reflow: true 8099 }); 8100 } 8101 8102 if (typeof station_kvrr24sum_data != 'undefined') { 8103 $('#klimavergleich-chart-single-rr24sum').highcharts({ 8104 chart: { 8105 height: 400//, 8106 }, 8107 title: { 8108 text: ($('#klimavergleich-chart-single-rr24sum').prev('label').length > 0) ? $('#klimavergleich-chart-single-rr24sum').prev('label').text() + getDateForTitle(station_kvrr24sum_data) : 'Chart' 8109 }, 8110 legend: { 8111 useHTML: true, 8112 itemStyle: { 8113 color: cssVar('--hc-label-textcolor'), 8114 }, 8115 }, 8116 xAxis: { 8117 type: 'datetime', 8118 dateTimeLabelFormats: { 8119 hour: '%H:%M', 8120 day: '%e. %b' 8121 }, 8122 labels:{ 8123 useHTML: true, 8124 align: 'center', 8125 formatter: function () { 8126 var date_format; 8127 var day = Highcharts.dateFormat("%e", this.value); 8128 var hour = Highcharts.dateFormat("%H", this.value); 8129 if(hour%24==0) 8130 date_format='%e. %b'; 8131 else 8132 date_format='%H:%M'; 8133 return Highcharts.dateFormat(date_format, this.value); 8134 }, 8135 style: { 8136 color: cssVar('--color-text'), 8137 }, 8138 }, 8139 tickLength: 7, 8140 lineColor: cssVar('--hc-lineColor-bright'), 8141 tickColor: cssVar('--hc-lineColor-bright'), 8142 }, 8143 yAxis: { 8144 title: false, 8145 floor: 0, 8146 labels: { 8147 format: "{value} mm", 8148 style: { 8149 color: cssVar('--color-text'), 8150 } 8151 }, 8152 min:0, 8153 softMax: 100, 8154 allowDecimals: false, 8155 minorTickInterval: 10, 8156 //gridLineColor: '#C0C0C0', 8157 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8158 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8159 tickAmount: 6 8160 }, 8161 tooltip: { 8162 crosshairs: true, 8163 shared: true, 8164 valueSuffix: ' mm', 8165 shape: 'square', 8166 useHTML: true, 8167 zIndex: 50, 8168 /*positioner: function (w,h,p) { 8169 if(p.plotX/this.chart.chartWidth>0.5) 8170 return { x: 65, y: 0 }; 8171 else 8172 return { x: this.chart.chartWidth-w-10, y: 0 }; 8173 },*/ 8174 formatter: function () { 8175 var date_format; 8176 date_format="%A, den %e.%B"; 8177 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 8178 //this.points.sort( ordertooltip ); 8179 $.each(this.points, function () { 8180 if (this.series.name !== 'arearange' && this.series.name !== 'arearange2' && this.series.name !== 'arearange3') { 8181 var anzeigename = this.series.name; 8182 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%d.
8182%m.%Y', this.x)); 8183 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8184 '<b>'+Math.round(this.y*10)/10 + '</b> ' + ' mm'; 8185 } 8186 }); 8187 return s; 8188 } 8189 }, 8190 credits: { enabled: false }, 8191 exporting: themedExportConfig, 8192 series: station_kvrr24sum_data, 8193 reflow: true 8194 }); 8195 } 8196 8197 if (typeof station_kvrr24mon_data != 'undefined') { 8198 $('#klimavergleich-chart-single-rr24mon').highcharts({ 8199 chart: { 8200 height: 400//, 8201 }, 8202 title: {text:($('#klimavergleich-chart-single-rr24mon').prev('label').length > 0) ? $('#klimavergleich-chart-single-rr24mon').prev('label').text()+getDateForTitle(station_kvrr24mon_data) : 'Chart'}, 8203 legend: { 8204 useHTML: true, 8205 itemStyle: { 8206 color: cssVar('--hc-label-textcolor'), 8207 }, 8208 }, 8209 xAxis: { 8210 type: 'datetime', 8211 dateTimeLabelFormats: { 8212 hour: false, 8213 day: '%b %Y' 8214 }, 8215 labels:{ 8216 useHTML: true, 8217 align: 'center', 8218 formatter: function () { 8219 return Highcharts.dateFormat('%b %Y', this.value); 8220 }, 8221 style: { 8222 color: cssVar('--color-text'), 8223 }, 8224 }, 8225 tickLength: 7, 8226 lineColor: cssVar('--hc-lineColor-bright'), 8227 tickColor: cssVar('--hc-lineColor-bright'), 8228 }, 8229 yAxis: { 8230 title: false, 8231 labels: { 8232 format: "{value} mm", 8233 style: { 8234 color: cssVar('--color-text'), 8235 } 8236 }, 8237 floor: 0, 8238 min:0, 8239 softMax: 50, 8240 allowDecimals: false, 8241 minorTickInterval: 5, 8242 //gridLineColor: '#C0C0C0', 8243 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8244 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8245 tickAmount: 6 8246 }, 8247 plotOptions: { 8248 column: { 8249 borderColor: cssVar('--hc-bar-stroke-color'), 8250 } 8251 }, 8252 tooltip: { 8253 crosshairs: true, 8254 shared: true, 8255 valueSuffix: ' mm', 8256 shape: 'square', 8257 useHTML: true, 8258 zIndex: 50, 8259 /*positioner: function (w,h,p) { 8260 if(p.plotX/this.chart.chartWidth>0.5) 8261 return { x: 65, y: 0 }; 8262 else 8263 return { x: this.chart.chartWidth-w-10, y: 0 }; 8264 },*/ 8265 formatter: function () { 8266 var todayHint= Highcharts.dateFormat('%B %Y', this.x) == Highcharts.dateFormat('%B %Y', new Date()) 8267 ? ' ('+simpleTrans('partialData')+')' 8268 : ''; 8269 var s = '<span style="font-size:10px">' + Highcharts.dateFormat('%B %Y', this.x) + todayHint + '</span> '; 8270 $.each(this.points, function () { 8271 var anzeigename = this.series.name; 8272 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%B %Y', this.x)); 8273 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> ' + anzeigename + ': ' + 8274 '<b>' + Math.round(this.y * 10) / 10 + '</b> ' + ' mm' + todayHint; 8275 }); 8276 return s; 8277 } 8278 }, 8279 credits: { enabled: false }, 8280 exporting: themedExportConfig, 8281 series: station_kvrr24mon_data, 8282 reflow: true 8283 }); 8284 } 8285 8286 if (typeof station_kvrr24mondiff_data != 'undefined') { 8287 $('#klimavergleich-chart-single-rr24mondiff').highcharts({ 8288 chart: { 8289 height: 320//, 8290 }, 8291 title: {text: ($('#klimavergleich-chart-single-rr24mondiff').prev('label').length > 0) ? $('#klimavergleich-chart-single-rr24mondiff').prev('label').text()+" "+getDateForTitle(station_kvrr24mondiff_data) : 'Chart'}, 8292 legend: { 8293 useHTML: true, 8294 itemStyle: { 8295 color: cssVar('--hc-label-textcolor'), 8296 }, 8297 }, 8298 xAxis: { 8299 type: 'datetime', 8300 dateTimeLabelFormats: { 8301 hour: false, 8302 day: '%b %Y' 8303 }, 8304 labels:{ 8305 useHTML: true, 8306 align: 'center', 8307 formatter: function () { 8308 return Highcharts.dateFormat('%b %Y', this.value); 8309 }, 8310 style: { 8311 color: cssVar('--color-text'), 8312 }, 8313 }, 8314 tickLength: 7, 8315 lineColor: cssVar('--hc-lineColor-bright'), 8316 tickColor: cssVar('--hc-lineColor-bright'), 8317 }, 8318 yAxis: { 8319 title: false, 8320 labels: { 8321 format: "{value} mm", 8322 style: { 8323 color: cssVar('--color-text'), 8324 } 8325 }, 8326 softMin: -50, 8327 softMax: 50, 8328 allowDecimals: false, 8329 minorTickInterval: 5, 8330 //gridLineColor: '#C0C0C0', 8331 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8332 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8333 tickAmount: 6 8334 }, 8335 plotOptions: { 8336 column: { 8337 borderColor: cssVar('--hc-bar-stroke-color'), 8338 } 8339 }, 8340 tooltip: { 8341 crosshairs: true, 8342 shared: true, 8343 valueSuffix: ' mm',
8344 shape: 'square', 8345 useHTML: true, 8346 zIndex: 50, 8347 /*positioner: function (w,h,p) { 8348 if(p.plotX/this.chart.chartWidth>0.5) 8349 return { x: 65, y: 0 }; 8350 else 8351 return { x: this.chart.chartWidth-w-10, y: 0 }; 8352 },*/ 8353 formatter: function () { 8354 var todayHint= Highcharts.dateFormat('%B %Y', this.x) == Highcharts.dateFormat('%B %Y', new Date()) 8355 ? ' ('+simpleTrans('partialData')+')' 8356 : '';var s = '<span style="font-size:10px">'+Highcharts.dateFormat('%B %Y', this.x)+ todayHint + '</span> '; 8357 $.each(this.points, function () { 8358 var plus = ''; 8359 if (this.y>0) { plus= '+'; } 8360 var anzeigename = this.series.name; 8361 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%B %Y', this.x)); 8362 8363 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8364 '<b>'+plus+Math.round(this.y*10)/10 + '</b> ' + ' mm' + todayHint; 8365 }); 8366 return s; 8367 } 8368 }, 8369 credits: { enabled: false }, 8370 exporting: themedExportConfig, 8371 series: station_kvrr24mondiff_data, 8372 reflow: true 8373 }); 8374 } 8375 8376 8377 if (typeof station_tmp2m_acc_data != 'undefined') { 8378 $('#klimavergleich-chart-tmp2m').highcharts({ 8379 chart: { 8380 height: 320//, 8381 }, 8382 title: {text: ($('#klimavergleich-chart-tmp2m').prev('label').length > 0) ? $('#klimavergleich-chart-tmp2m').prev('label').text()+" "+getDateForTitle(station_tmp2m_acc_data) : 'Chart'}, 8383 legend: { 8384 useHTML: true 8385 }, 8386 xAxis: [{ 8387 type: 'datetime', 8388 dateTimeLabelFormats: { 8389 hour: false, 8390 day: '%b %Y' 8391 }, 8392 labels:{ 8393 useHTML: true, 8394 align: 'center', 8395 formatter: function () { 8396 return Highcharts.dateFormat('%b %Y', this.value); 8397 } 8398 } 8399 },{ 8400 type: 'datetime', 8401 dateTimeLabelFormats: { 8402 hour: '%H:%M', 8403 day: '%e. %b' 8404 }, 8405 labels:{ 8406 useHTML: true, 8407 align: 'center', 8408 formatter: function () { 8409 var date_format; 8410 var day = Highcharts.dateFormat("%e", this.value); 8411 var hour = Highcharts.dateFormat("%H", this.value); 8412 if(hour%24==0) 8413 date_format='%e. %b'; 8414 else 8415 date_format='%H:%M'; 8416 return Highcharts.dateFormat(date_format, this.value); 8417 } 8418 } 8419 }], 8420 yAxis: [{ 8421 title: { 8422 text: 'Grünlandtemperatursumme' 8423 }, 8424 floor: 0, 8425 labels: { 8426 format: "{value}" 8427 }, 8428 opposite: true, 8429 min:0, 8430 softMax: 400, 8431 allowDecimals: false, 8432 minorTickInterval: 1, 8433 //gridLineColor: '#C0C0C0', 8434 tickAmount: 6 8435 },{ 8436 title: { 8437 text: 'Durchschnittstemperatur' 8438 }, 8439 //floor: 0, 8440 labels: { 8441 format: "{value}°C" 8442 }, 8443 softMin:0, 8444 softMax: 20, 8445 allowDecimals: false, 8446 minorTickInterval: 1, 8447 //gridLineColor: '#C0C0C0', 8448 tickAmount: 6 8449 }], 8450 tooltip: { 8451 crosshairs: true, 8452 shared: true, 8453 valueSuffix: '°C',
8454 shape: 'square', 8455 useHTML: true, 8456 zIndex: 50, 8457 /*positioner: function (w,h,p) { 8458 if(p.plotX/this.chart.chartWidth>0.5) 8459 return { x: 65, y: 0 }; 8460 else 8461 return { x: this.chart.chartWidth-w-10, y: 0 }; 8462 },*/ 8463 formatter: function () { 8464 var date_format; 8465 date_format="%A, den %e.%B"; 8466 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 8467 this.points.sort( ordertooltip ); 8468 $.each(this.points, function () { 8469 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 8470 '<b>'+Math.round(this.y*10)/10 + '</b> ' + '°C'; 8471 }); 8472 return s; 8473 } 8474 }, 8475 credits: { enabled: false }, 8476 exporting: { exportConfig }, 8477 series: station_tmp2m_acc_data, 8478 reflow: true 8479 }); 8480 } 8481 8482 if (typeof station_kvtmean_data != 'undefined') { 8483 $('#klimavergleich-chart-single-tmean').highcharts({ 8484 chart: { 8485 height: 400//, 8486 }, 8487 title: {text:($('#klimavergleich-chart-single-tmean').prev('label').length > 0) ? $('#klimavergleich-chart-single-tmean').prev('label').text()+" "+getDateForTitle(station_kvtmean_data) : 'Chart'}, 8488 legend: { 8489 useHTML: true, 8490 itemStyle: { 8491 color: cssVar('--hc-label-textcolor'), 8492 }, 8493 }, 8494 xAxis: { 8495 type: 'datetime', 8496 dateTimeLabelFormats: { 8497 hour: '%H:%M', 8498 day: '%e. %b' 8499 }, 8500 labels:{ 8501 useHTML: true, 8502 align: 'center', 8503 formatter: function () { 8504 var date_format; 8505 var day = Highcharts.dateFormat("%e", this.value); 8506 var hour = Highcharts.dateFormat("%H", this.value); 8507 if(hour%24==0) 8508 date_format='%e. %b'; 8509 else 8510 date_format='%H:%M'; 8511 return Highcharts.dateFormat(date_format, this.value); 8512 }, 8513 style: { 8514 color: cssVar('--color-text'), 8515 }, 8516 }, 8517 tickLength: 7, 8518 lineColor: cssVar('--hc-lineColor-bright'), 8519 tickColor: cssVar('--hc-lineColor-bright'), 8520 }, 8521 yAxis: { 8522 title: false, 8523 //floor: 0, 8524 labels: { 8525 format: "{value}°C", 8526 style: { 8527 color: cssVar('--color-text'), 8528 } 8529 }, 8530 softMin:-20, 8531 softMax: 30, 8532 allowDecimals: false, 8533 minorTickInterval: 1, 8534 tickInterval: 5, 8535 //gridLineColor: '#C0C0C0', 8536 //tickAmount: 6 8537 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8538 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8539 }, 8540 tooltip: { 8541 crosshairs: true, 8542 shared: true, 8543 valueSuffix: '°C', 8544 shape: 'square', 8545 useHTML: true, 8546 zIndex: 50, 8547 /*positioner: function (w,h,p) { 8548 if(p.plotX/this.chart.chartWidth>0.5) 8549 return { x: 65, y: 0 }; 8550 else 8551 return { x: this.chart.chartWidth-w-10, y: 0 }; 8552 },*/ 8553 formatter: function () { 8554 var date_format; 8555 date_format="%A, den %e.%B"; 8556 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 8557 $.each(this.points, function () { 8558 if (this.series.name !== 'arearange' && this.series.name !== 'arearange2' && this.series.name !== 'arearange3') { 8559 var anzeigename = this.series.name; 8560 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%d.
8560%m.%Y', this.x)); 8561 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8562 '<b>'+Math.round(this.y*10)/10 + '</b> ' + '°C'; 8563 } 8564 }); 8565 return s; 8566 } 8567 }, 8568 credits: { enabled: false }, 8569 exporting: themedExportConfig, 8570 series: station_kvtmean_data, 8571 reflow: true 8572 }); 8573 } 8574 8575 if (typeof station_kvmon_data != 'undefined') { 8576 $('#klimavergleich-chart-single-tmean-month').highcharts({ 8577 chart: { 8578 height: 400//, 8579 }, 8580 title: { 8581 text: ($('#klimavergleich-chart-single-tmean-month').prev('label').length > 0) ? $('#klimavergleich-chart-single-tmean-month').prev('label').text()+" "+getDateForTitle(station_kvmon_data) : 'Chart' 8582 }, 8583 legend: { 8584 useHTML: true, 8585 itemStyle: { 8586 color: cssVar('--hc-label-textcolor'), 8587 }, 8588 }, 8589 xAxis: { 8590 type: 'datetime', 8591 dateTimeLabelFormats: { 8592 hour: '%H:%M', 8593 day: '%e. %b' 8594 }, 8595 labels:{ 8596 useHTML: true, 8597 align: 'center', 8598 formatter: function () { 8599 return Highcharts.dateFormat("%b %Y", this.value); 8600 }, 8601 style: { 8602 color: cssVar('--color-text'), 8603 }, 8604 }, 8605 tickLength: 7, 8606 lineColor: cssVar('--hc-lineColor-bright'), 8607 tickColor: cssVar('--hc-lineColor-bright'), 8608 }, 8609 yAxis: { 8610 title: false, 8611 //floor: 0, 8612 labels: { 8613 format: "{value}°C", 8614 style: { 8615 color: cssVar('--color-text'), 8616 } 8617 }, 8618 softMin: 0, 8619 softMax: 30, 8620 allowDecimals: false, 8621 minorTickInterval: 5, 8622 tickInterval: 5, 8623 //gridLineColor: '#C0C0C0', 8624 //tickAmount: 6 8625 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8626 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8627 }, 8628 plotOptions: { 8629 column: { 8630 borderColor: cssVar('--hc-bar-stroke-color'), 8631 } 8632 }, 8633 tooltip: { 8634 crosshairs: true, 8635 shared: true, 8636 valueSuffix: '°C', 8637 shape: 'square', 8638 useHTML: true, 8639 zIndex: 50, 8640 /*positioner: function (w,h,p) { 8641 if(p.plotX/this.chart.chartWidth>0.5) 8642 return { x: 65, y: 0 }; 8643 else 8644 return { x: this.chart.chartWidth-w-10, y: 0 }; 8645 },*/ 8646 formatter: function () { 8647 var todayHint= Highcharts.dateFormat('%B %Y', this.x) == Highcharts.dateFormat('%B %Y', new Date()) 8648 ? ' ('+simpleTrans('partialData')+')' 8649 : ''; 8650 var s = '<span style="font-size:10px">'+Highcharts.dateFormat("%B %Y", this.x)+ todayHint + '</span> '; 8651 $.each(this.points, function () { 8652 if (this.series.name !== 'arearange') { 8653 var anzeigename = this.series.name; 8654 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%B %Y', this.x)); 8655 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8656 '<b>'+Math.round(this.y*10)/10 + '</b> ' + '°C' + todayHint; 8657 } 8658 }); 8659 return s; 8660 } 8661 }, 8662 credits: { enabled: false }, 8663 exporting: themedExportConfig, 8664 series: station_kvmon_data, 8665 reflow: true 8666 }); 8667 } 8668 8669 if (typeof station_kvmon_data_diff != 'undefined') { 8670 $('#klimavergleich-chart-single-anomaly-month').highcharts({ 8671 chart: { 8672 height: 260//, 8673 }, 8674 title: {text:($('#klimavergleich-chart-single-anomaly-month').prev('label').length > 0) ? $('#klimavergleich-chart-single-anomaly-month').prev('label').text()+" "+getDateForTitle(station_kvmon_data_diff) : 'Chart'}, 8675 legend: { 8676 useHTML: true, 8677 itemStyle: { 8678 color: cssVar('--hc-label-textcolor'), 8679 }, 8680 }, 8681 xAxis: { 8682 type: 'datetime', 8683 dateTimeLabelFormats: { 8684 hour: '%H:%M', 8685 day: '%e. %b' 8686 }, 8687 labels:{ 8688 useHTML: true, 8689 align: 'center', 8690 formatter: function () { 8691 return Highcharts.dateFormat("%b %Y", this.value); 8692 }, 8693 style: { 8694 color: cssVar('--color-text'), 8695 }, 8696 }, 8697 tickLength: 7, 8698 lineColor: cssVar('--hc-lineColor-bright'), 8699 tickColor: cssVar('--hc-lineColor-bright'), 8700 }, 8701 yAxis: { 8702 title: false, 8703 //floor: 0, 8704 labels: { 8705 format: "{value}°C", 8706 style: { 8707 color: cssVar('--color-text'), 8708 }, 8709 }, 8710 softMin: -5, 8711 softMax: 5, 8712 allowDecimals: false, 8713 minorTickInterval: 1, 8714 tickInterval: 5, 8715 //gridLineColor: '#C0C0C0', 8716 //tickAmount: 6 8717 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8718 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8719 }, 8720 plotOptions: { 8721 column: { 8722 borderColor: cssVar('--hc-bar-stroke-color'), 8723 } 8724 }, 8725 tooltip: { 8726 crosshairs: true, 8727 shared: true, 8728 valueSuffix: '°C',
8729 shape: 'square', 8730 useHTML: true, 8731 zIndex: 50, 8732 /*positioner: function (w,h,p) { 8733 if(p.plotX/this.chart.chartWidth>0.5) 8734 return { x: 65, y: 0 }; 8735 else 8736 return { x: this.chart.chartWidth-w-10, y: 0 }; 8737 },*/ 8738 formatter: function () { 8739 var todayHint= Highcharts.dateFormat('%B %Y', this.x) == Highcharts.dateFormat('%B %Y', new Date()) 8740 ? ' ('+simpleTrans('partialData')+')' 8741 : ''; var s = '<span style="font-size:10px">'+Highcharts.dateFormat("%B %Y", this.x)+ todayHint + '</span> '; 8742 $.each(this.points, function () { 8743 if (this.series.name !== 'arearange') { 8744 var plus = ''; 8745 if (this.y>0) { plus= '+'; } 8746 var anzeigename = this.series.name; 8747 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%B %Y', this.x)); 8748 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8749 '<b>'+plus+Math.round(this.y*10)/10 + '</b> ' + '°C' + todayHint; 8750 } 8751 }); 8752 return s; 8753 } 8754 }, 8755 credits: { enabled: false }, 8756 exporting: themedExportConfig, 8757 series: station_kvmon_data_diff, 8758 reflow: true 8759 }); 8760 } 8761 8762 if (typeof station_kvtmax_data != 'undefined') { 8763 $('#klimavergleich-chart-single-tmax').highcharts({ 8764 chart: { 8765 height: 400//, 8766 }, 8767 title: {text:($('#klimavergleich-chart-single-tmax').prev('label').length > 0) ? $('#klimavergleich-chart-single-tmax').prev('label').text()+" "+getDateForTitle(station_kvtmax_data) : 'Chart'}, 8768 legend: { 8769 useHTML: true, 8770 itemStyle: { 8771 color: cssVar('--hc-label-textcolor'), 8772 }, 8773 }, 8774 xAxis: { 8775 type: 'datetime', 8776 dateTimeLabelFormats: { 8777 hour: '%H:%M', 8778 day: '%e. %b' 8779 }, 8780 labels:{ 8781 useHTML: true, 8782 align: 'center', 8783 formatter: function () { 8784 var date_format; 8785 var day = Highcharts.dateFormat("%e", this.value); 8786 var hour = Highcharts.dateFormat("%H", this.value); 8787 if(hour%24==0) 8788 date_format='%e. %b'; 8789 else 8790 date_format='%H:%M'; 8791 return Highcharts.dateFormat(date_format, this.value); 8792 }, 8793 style: { 8794 color: cssVar('--color-text'), 8795 }, 8796 }, 8797 tickLength: 7, 8798 lineColor: cssVar('--hc-lineColor-bright'), 8799 tickColor: cssVar('--hc-lineColor-bright'), 8800 }, 8801 yAxis: { 8802 title: false, 8803 //floor: 0, 8804 labels: { 8805 format: "{value}°C", 8806 style: { 8807 color: cssVar('--color-text'), 8808 } 8809 }, 8810 softMin:-15, 8811 softMax: 35, 8812 allowDecimals: false, 8813 minorTickInterval: 5, 8814 tickInterval: 5, 8815 //gridLineColor: '#C0C0C0', 8816 //tickAmount: 6 8817 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8818 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8819 }, 8820 tooltip: { 8821 crosshairs: true, 8822 shared: true, 8823 valueSuffix: '°C', 8824 shape: 'square', 8825 useHTML: true, 8826 zIndex: 50, 8827 /*positioner: function (w,h,p) { 8828 if(p.plotX/this.chart.chartWidth>0.5) 8829 return { x: 65, y: 0 }; 8830 else 8831 return { x: this.chart.chartWidth-w-10, y: 0 }; 8832 },*/ 8833 formatter: function () { 8834 var date_format; 8835 date_format="%A, den %e.%B"; 8836 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 8837 $.each(this.points, function () { 8838 if (this.series.name !== 'arearange') { 8839 var anzeigename = this.series.name; 8840 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%d.
8840%m.%Y', this.x)); 8841 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8842 '<b>'+Math.round(this.y*10)/10 + '</b> ' + '°C'; 8843 } 8844 }); 8845 return s; 8846 } 8847 }, 8848 credits: { enabled: false }, 8849 exporting: themedExportConfig, 8850 series: station_kvtmax_data, 8851 reflow: true 8852 }); 8853 } 8854 8855 if (typeof station_kvtmin_data != 'undefined') { 8856 $('#klimavergleich-chart-single-tmin').highcharts({ 8857 chart: { 8858 height: 400//, 8859 }, 8860 title: {text:($('#klimavergleich-chart-single-tmin').prev('label').length > 0) ? $('#klimavergleich-chart-single-tmin').prev('label').text()+" "+getDateForTitle(station_kvtmin_data) : 'Chart'}, 8861 legend: { 8862 useHTML: true, 8863 itemStyle: { 8864 color: cssVar('--hc-label-textcolor'), 8865 }, 8866 }, 8867 xAxis: { 8868 type: 'datetime', 8869 dateTimeLabelFormats: { 8870 hour: '%H:%M', 8871 day: '%e. %b' 8872 }, 8873 labels:{ 8874 useHTML: true, 8875 align: 'center', 8876 formatter: function () { 8877 var date_format; 8878 var day = Highcharts.dateFormat("%e", this.value); 8879 var hour = Highcharts.dateFormat("%H", this.value); 8880 if(hour%24==0) 8881 date_format='%e. %b'; 8882 else 8883 date_format='%H:%M'; 8884 return Highcharts.dateFormat(date_format, this.value); 8885 }, 8886 style: { 8887 color: cssVar('--color-text'), 8888 }, 8889 }, 8890 tickLength: 7, 8891 lineColor: cssVar('--hc-lineColor-bright'), 8892 tickColor: cssVar('--hc-lineColor-bright'), 8893 }, 8894 yAxis: { 8895 title: false, 8896 //floor: 0, 8897 labels: { 8898 format: "{value}°C", 8899 style: { 8900 color: cssVar('--color-text'), 8901 } 8902 }, 8903 softMin:-25, 8904 softMax: 25, 8905 allowDecimals: false, 8906 minorTickInterval: 5, 8907 tickInterval: 5, 8908 //gridLineColor: '#C0C0C0', 8909 //tickAmount: 6 8910 gridLineColor: cssVar('--hc-gridLineColor-bright'), 8911 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 8912 }, 8913 tooltip: { 8914 crosshairs: true, 8915 shared: true, 8916 valueSuffix: '°C', 8917 shape: 'square', 8918 useHTML: true, 8919 zIndex: 50, 8920 /*positioner: function (w,h,p) { 8921 if(p.plotX/this.chart.chartWidth>0.5) 8922 return { x: 65, y: 0 }; 8923 else 8924 return { x: this.chart.chartWidth-w-10, y: 0 }; 8925 },*/ 8926 formatter: function () { 8927 var date_format; 8928 date_format="%A, den %e.%B"; 8929 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 8930 $.each(this.points, function () { 8931 if (this.series.name !== 'arearange') { 8932 var anzeigename = this.series.name; 8933 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%d.%m.%Y', this.x)); 8934 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 8935 '<b>'+Math.round(this.y*10)/10 + '</b> ' + '°C'; 8936 } 8937 }); 8938 return s; 8939 } 8940 }, 8941 credits: { enabled: false }, 8942 exporting: themedExportConfig, 8943 series: station_kvtmin_data, 8944 reflow: true 8945 }); 8946 } 8947 8948 if (typeof station_s24h_acc_data != 'undefined') { 8949 $('#klimavergleich-chart-s24h').highcharts({ 8950 chart: { 8951 height: 320//, 8952 }, 8953 title: {text:($('#klimavergleich-chart-s24h').prev('label').length > 0) ? $('#klimavergleich-chart-s24h').prev('label').text()+" "+getDateForTitle(station_s24h_acc_data) : 'Chart'}, 8954 legend: { 8955 useHTML: true 8956 }, 8957 xAxis: [{ 8958 type: 'datetime', 8959 dateTimeLabelFormats: { 8960 hour: false, 8961 day: '%b %Y' 8962 }, 8963 labels:{ 8964 useHTML: true, 8965 align: 'center', 8966 formatter: function () { 8967 return Highcharts.dateFormat('%b %Y', this.value); 8968 } 8969 } 8970 },{ 8971 type: 'datetime', 8972 dateTimeLabelFormats: { 8973 hour: '%H:%M', 8974 day: '%e. %b' 8975 }, 8976 labels:{ 8977 useHTML: true, 8978 align: 'center', 8979 formatter: function () { 8980 var date_format; 8981 var day = Highcharts.dateFormat("%e", this.value); 8982 var hour = Highcharts.dateFormat("%H", this.value); 8983 if(hour%24==0) 8984 date_format='%e. %b'; 8985 else 8986 date_format='%H:%M'; 8987 return Highcharts.dateFormat(date_format, this.value); 8988 } 8989 } 8990 }], 8991 yAxis: [{ 8992 title: { 8993 text: 'Sonnenstunden Monatssumme' 8994 }, 8995 floor: 0, 8996 labels: { 8997 format: "{value}h" 8998 }, 8999 min:0, 9000 softMax: 200, 9001 allowDecimals: false, 9002 minorTickInterval: 1, 9003 //gridLineColor: '#C0C0C0', 9004 tickAmount: 6 9005 },{ 9006 title: { 9007 text: 'Sonnenstunden' 9008 }, 9009 //floor: 0, 9010 labels: { 9011 format: "{value}h" 9012 }, 9013 opposite: true, 9014 floor:0, 9015 min: 0, 9016 softMax: 10, 9017 allowDecimals: false, 9018 minorTickInterval: 1, 9019 //gridLineColor: '#C0C0C0', 9020 tickAmount: 6 9021 }], 9022 tooltip: { 9023 crosshairs: true, 9024 shared: true, 9025 valueSuffix: '°C',
9026 shape: 'square', 9027 useHTML: true, 9028 zIndex: 50, 9029 /*positioner: function (w,h,p) { 9030 if(p.plotX/this.chart.chartWidth>0.5) 9031 return { x: 65, y: 0 }; 9032 else 9033 return { x: this.chart.chartWidth-w-10, y: 0 }; 9034 },*/ 9035 formatter: function () { 9036 var date_format; 9037 date_format="%A, den %e.%B"; 9038 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 9039 this.points.sort( ordertooltip ); 9040 $.each(this.points, function () { 9041 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9042 '<b>'+Math.round(this.y*10)/10 + '</b> ' + 'h'; 9043 }); 9044 return s; 9045 } 9046 }, 9047 credits: { enabled: false }, 9048 exporting: { exportConfig }, 9049 series: station_s24h_acc_data, 9050 reflow: true 9051 }); 9052 } 9053 9054 if (typeof station_kvs24sum_data != 'undefined') { 9055 $('#klimavergleich-chart-single-s24sum').highcharts({ 9056 chart: { 9057 height: 400//, 9058 }, 9059 title: {text:($('#klimavergleich-chart-single-s24sum').prev('label').length > 0) ? $('#klimavergleich-chart-single-s24sum').prev('label').text()+" "+getDateForTitle(station_kvs24sum_data) : 'Chart'}, 9060 legend: { 9061 useHTML: true, 9062 itemStyle: { 9063 color: cssVar('--hc-label-textcolor'), 9064 }, 9065 }, 9066 xAxis: { 9067 type: 'datetime', 9068 dateTimeLabelFormats: { 9069 hour: '%H:%M', 9070 day: '%e. %b' 9071 }, 9072 labels:{ 9073 useHTML: true, 9074 align: 'center', 9075 formatter: function () { 9076 var date_format; 9077 var day = Highcharts.dateFormat("%e", this.value); 9078 var hour = Highcharts.dateFormat("%H", this.value); 9079 if(hour%24==0) 9080 date_format='%e. %b'; 9081 else 9082 date_format='%H:%M'; 9083 return Highcharts.dateFormat(date_format, this.value); 9084 }, 9085 style: { 9086 color: cssVar('--color-text'), 9087 }, 9088 }, 9089 tickLength: 7, 9090 lineColor: cssVar('--hc-lineColor-bright'), 9091 tickColor: cssVar('--hc-lineColor-bright'), 9092 }, 9093 yAxis: { 9094 title: false, 9095 //floor: 0, 9096 labels: { 9097 format: "{value}h", 9098 style: { 9099 color: cssVar('--color-text'), 9100 } 9101 }, 9102 floor:0, 9103 min: 0, 9104 softMax: 200, 9105 allowDecimals: false, 9106 minorTickInterval: 50, 9107 //gridLineColor: '#C0C0C0', 9108 tickAmount: 6, 9109 gridLineColor: cssVar('--hc-gridLineColor-bright'), 9110 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 9111 }, 9112 tooltip: { 9113 crosshairs: true, 9114 shared: true, 9115 valueSuffix: '°C', 9116 shape: 'square', 9117 useHTML: true, 9118 zIndex: 50, 9119 /*positioner: function (w,h,p) { 9120 if(p.plotX/this.chart.chartWidth>0.5) 9121 return { x: 65, y: 0 }; 9122 else 9123 return { x: this.chart.chartWidth-w-10, y: 0 }; 9124 },*/ 9125 formatter: function () { 9126 var date_format; 9127 date_format="%A, den %e.%B"; 9128 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ '</span> '; 9129 $.each(this.points, function () { 9130 if (this.series.name !== 'arearange' && this.series.name !== 'arearange2' && this.series.name !== 'arearange3') { 9131 var anzeigename = this.series.name; 9132 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%d.
9132%m.%Y', this.x)); 9133 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 9134 '<b>'+Math.round(this.y*10)/10 + '</b> ' + ' h'; 9135 } 9136 }); 9137 return s; 9138 } 9139 }, 9140 credits: { enabled: false }, 9141 exporting: themedExportConfig, 9142 series: station_kvs24sum_data, 9143 reflow: true 9144 }); 9145 } 9146 9147 if (typeof station_kvs24mon_data != 'undefined') { 9148 $('#klimavergleich-chart-single-s24mon').highcharts({ 9149 chart: { 9150 height: 400//, 9151 }, 9152 title: {text:($('#klimavergleich-chart-single-s24mon').prev('label').length > 0) ? $('#klimavergleich-chart-single-s24mon').prev('label').text()+" "+getDateForTitle(station_kvs24mon_data) : 'Chart'}, 9153 legend: { 9154 useHTML: true, 9155 itemStyle: { 9156 color: cssVar('--hc-label-textcolor'), 9157 }, 9158 }, 9159 xAxis: { 9160 type: 'datetime', 9161 dateTimeLabelFormats: { 9162 hour: false, 9163 day: '%b %Y' 9164 }, 9165 labels:{ 9166 useHTML: true, 9167 align: 'center', 9168 formatter: function () { 9169 return Highcharts.dateFormat('%b %Y', this.value); 9170 }, 9171 style: { 9172 color: cssVar('--color-text'), 9173 }, 9174 }, 9175 tickLength: 7, 9176 lineColor: cssVar('--hc-lineColor-bright'), 9177 tickColor: cssVar('--hc-lineColor-bright'), 9178 }, 9179 yAxis: { 9180 title: false, 9181 floor: 0, 9182 labels: { 9183 format: "{value}h", 9184 style: { 9185 color: cssVar('--color-text'), 9186 } 9187 }, 9188 min:0, 9189 softMax: 200, 9190 allowDecimals: false, 9191 minorTickInterval: 10, 9192 //gridLineColor: '#C0C0C0', 9193 tickAmount: 6, 9194 gridLineColor: cssVar('--hc-gridLineColor-bright'), 9195 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 9196 }, 9197 plotOptions: { 9198 column: { 9199 borderColor: cssVar('--hc-bar-stroke-color'), 9200 } 9201 }, 9202 tooltip: { 9203 crosshairs: true, 9204 shared: true, 9205 valueSuffix: '°C', 9206 shape: 'square', 9207 useHTML: true, 9208 zIndex: 50, 9209 /*positioner: function (w,h,p) { 9210 if(p.plotX/this.chart.chartWidth>0.5) 9211 return { x: 65, y: 0 }; 9212 else 9213 return { x: this.chart.chartWidth-w-10, y: 0 }; 9214 },*/ 9215 formatter: function () { 9216 var todayHint= Highcharts.dateFormat('%B %Y', this.x) == Highcharts.dateFormat('%B %Y', new Date()) 9217 ? ' ('+simpleTrans('partialData')+')' 9218 : ''; 9219 var s = '<span style="font-size:10px">'+Highcharts.dateFormat('%B %Y', this.x)+ todayHint + '</span> '; 9220 $.each(this.points, function () { 9221 var anzeigename = this.series.name; 9222 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%B %Y', this.x)); 9223 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 9224 '<b>'+Math.round(this.y*10)/10 + '</b> ' + 'h' + todayHint; 9225 }); 9226 return s; 9227 } 9228 }, 9229 credits: { enabled: false }, 9230 exporting: themedExportConfig, 9231 series: station_kvs24mon_data, 9232 reflow: true 9233 }); 9234 } 9235 9236 if (typeof station_kvs24mondiff_data != 'undefined') { 9237 $('#klimavergleich-chart-single-s24mondiff').highcharts({ 9238 chart: { 9239 height: 320//, 9240 }, 9241 title: {text:($('#klimavergleich-chart-single-s24mondiff').prev('label').length > 0) ? $('#klimavergleich-chart-single-s24mondiff').prev('label').text()+" "+getDateForTitle(station_kvs24mondiff_data) : 'Chart'}, 9242 legend: { 9243 useHTML: true, 9244 itemStyle: { 9245 color: cssVar('--hc-label-textcolor'), 9246 }, 9247 }, 9248 xAxis: { 9249 type: 'datetime', 9250 dateTimeLabelFormats: { 9251 hour: false, 9252 day: '%b %Y' 9253 }, 9254 labels:{ 9255 useHTML: true, 9256 align: 'center', 9257 formatter: function () { 9258 return Highcharts.dateFormat('%b %Y', this.value); 9259 }, 9260 style: { 9261 color: cssVar('--color-text'), 9262 }, 9263 }, 9264 tickLength: 7, 9265 lineColor: cssVar('--hc-lineColor-bright'), 9266 tickColor: cssVar('--hc-lineColor-bright'), 9267 }, 9268 yAxis: { 9269 title: false, 9270 labels: { 9271 format: "{value}h", 9272 style: { 9273 color: cssVar('--color-text'), 9274 } 9275 }, 9276 softMin:-20, 9277 softMax: 20, 9278 allowDecimals: false, 9279 minorTickInterval: 5, 9280 //gridLineColor: '#C0C0C0', 9281 tickAmount: 6, 9282 gridLineColor: cssVar('--hc-gridLineColor-bright'), 9283 minorGridLineColor: cssVar('--hc-minorGridLineColor-bright'), 9284 }, 9285 plotOptions: { 9286 column: { 9287 borderColor: cssVar('--hc-bar-stroke-color'), 9288 } 9289 }, 9290 tooltip: { 9291 crosshairs: true, 9292 shared: true, 9293 valueSuffix: '°C',
9294 shape: 'square', 9295 useHTML: true, 9296 zIndex: 50, 9297 /*positioner: function (w,h,p) { 9298 if(p.plotX/this.chart.chartWidth>0.5) 9299 return { x: 65, y: 0 }; 9300 else 9301 return { x: this.chart.chartWidth-w-10, y: 0 }; 9302 },*/ 9303 formatter: function () { 9304 var todayHint= Highcharts.dateFormat('%B %Y', this.x) == Highcharts.dateFormat('%B %Y', new Date()) 9305 ? ' ('+simpleTrans('partialData')+')' 9306 : ''; 9307 var s = '<span style="font-size:10px">'+Highcharts.dateFormat('%B %Y', this.x)+ todayHint + '</span> '; 9308 $.each(this.points, function () { 9309 var plus = ''; 9310 if (this.y>0) { plus = '+'; } 9311 var anzeigename = this.series.name; 9312 anzeigename = anzeigename.replace('aktuell', Highcharts.dateFormat('%B %Y', this.x)); 9313 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ anzeigename + ': ' + 9314 '<b>'+plus+Math.round(this.y*10)/10 + '</b> ' + 'h' + todayHint; 9315 }); 9316 return s; 9317 } 9318 }, 9319 credits: { enabled: false }, 9320 exporting: themedExportConfig, 9321 series: station_kvs24mondiff_data, 9322 reflow: true 9323 }); 9324 } 9325}; 9326 9327 9328var plotVHStationen = function() { 9329 if (typeof vhstation_rr_data != 'undefined' && vhstation_rr_data) { 9330 $('#vh-stationen-chart').highcharts({ 9331 chart: { 9332 height: 360, 9333 events: { 9334 load: function(){ 9335 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9336 drawNightShadows(this,1); 9337 } 9338 }, 9339 redraw: function(){ 9340 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9341 drawNightShadows(this,1); 9342 } 9343 } 9344 } 9345 }, 9346 title: 'false', 9347 legend: { 9348 useHTML: true 9349 }, 9350 xAxis: [{ 9351 type: 'datetime', 9352 dateTimeLabelFormats: { 9353 hour: '%H:%M', 9354 day: '%e. %b' 9355 }, 9356 labels:{ 9357 useHTML: true, 9358 align: 'center', 9359 formatter: function () { 9360 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9361 } 9362 }, 9363 minPadding: 0.025 9364 }], 9365 yAxis: [{ 9366 title: false, 9367 floor: 0, 9368 labels: { 9369 format: "{value} mm" 9370 }, 9371 min:0, 9372 softMax: 5, 9373 allowDecimals: false, 9374 minorTickInterval: 1, 9375 //gridLineColor: '#C0C0C0', 9376 tickAmount: 6 9377 }], 9378 tooltip: { 9379 crosshairs: true, 9380 shared: true, 9381 valueSuffix: ' mm', 9382 shape: 'square', 9383 useHTML: true, 9384 zIndex: 50, 9385 formatter: function () { 9386 var date_format; 9387 date_format="%A, den %e.%B, %H:%M Uhr"; 9388 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9389 this.points.sort( ordertooltip ); 9390 $.each(this.points, function () { 9391 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9392 '<b>'+Math.round(this.y*10)/10 + '</b> ' + ' mm'; 9393 }); 9394 return s; 9395 } 9396 }, 9397 credits: { enabled: false }, 9398 exporting: { enabled: false }, 9399 series: vhstation_rr_data, 9400 reflow: true 9401 }); 9402 } 9403 9404 if (typeof vhstation_tl_data != 'undefined' && vhstation_tl_data) { 9405 $('#vh-stationen-chart').highcharts({ 9406 chart: { 9407 height: 360,//, 9408 events: { 9409 load: function(){ 9410 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9411 drawNightShadows(this,1); 9412 } 9413 }, 9414 redraw: function(){ 9415 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9416 drawNightShadows(this,1); 9417 } 9418 } 9419 } 9420 }, 9421 title: 'false', 9422 legend: { 9423 useHTML: true 9424 }, 9425 xAxis: [{ 9426 type: 'datetime', 9427 dateTimeLabelFormats: { 9428 hour: '%H:%M', 9429 day: '%e. %b' 9430 }, 9431 labels:{ 9432 useHTML: true, 9433 align: 'center', 9434 formatter: function () { 9435 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9436 } 9437 } 9438 }], 9439 yAxis: [{ 9440 title: { 9441 text: 'Temperaturen' 9442 }, 9443 //floor: 0, 9444 labels: { 9445 format: "{value} °C" 9446 }, 9447 softMin:0, 9448 // softMax: 20, 9449 // allowDecimals: false, 9450 // minorTickInterval: 1, 9451 // //gridLineColor: '#C0C0C0', 9452 // tickAmount: 6 9453 minTickInterval: 5, 9454 minorTickInterval: 'auto', 9455 minPadding: 0.12, 9456 maxPadding: 0.12, 9457 minRange: 5 9458 },{ 9459 title: { 9460 text: 'Relative Luftfeuchtigkeit' 9461 }, 9462 //floor: 0, 9463 labels: { 9464 format: "{value}%" 9465 }, 9466 opposite: true, 9467 min:0, 9468 max: 100, 9469 allowDecimals: false, 9470 }], 9471 tooltip: { 9472 crosshairs: true, 9473 shared: true, 9474 valueSuffix: '°C',
9475 shape: 'square', 9476 useHTML: true, 9477 zIndex: 50, 9478 formatter: function () { 9479 var date_format; 9480 date_format="%A, den %e.%B, %H:%M Uhr"; 9481 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9482 this.points.sort( ordertooltip ); 9483 $.each(this.points, function () { 9484 var unit = '°C'; 9485 if (this.series.name == 'Relative Luftfeuchtigkeit') { 9486 unit = '%'; 9487 } 9488 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9489 '<b>'+Math.round(this.y*10)/10 + '</b> ' + unit; 9490 }); 9491 return s; 9492 } 9493 }, 9494 plotOptions: { 9495 area: { 9496 fillColor: { 9497 linearGradient: { 9498 x1: 0, 9499 y1: 0, 9500 x2: 0, 9501 y2: 1 9502 }, 9503 stops: [ 9504 [0, '#d4ebfc'], 9505 [1, '#e5f2fc'] 9506 ] 9507 }, 9508 marker: { 9509 radius: 2 9510 }, 9511 lineWidth: 1, 9512 states: { 9513 hover: { 9514 lineWidth: 1 9515 } 9516 }, 9517 threshold: null 9518 } 9519 }, 9520 credits: { enabled: false }, 9521 exporting: { enabled: false }, 9522 series: vhstation_tl_data, 9523 reflow: true 9524 }); 9525 } 9526 9527 if (typeof vhstation_tl_data2 != 'undefined' && vhstation_tl_data2) { 9528 $('#vh-stationen-chart').highcharts({ 9529 chart: { 9530 height: 360,//, 9531 events: { 9532 load: function(){ 9533 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9534 drawNightShadows(this,1); 9535 } 9536 }, 9537 redraw: function(){ 9538 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9539 drawNightShadows(this,1); 9540 } 9541 } 9542 } 9543 }, 9544 title: 'false', 9545 legend: { 9546 useHTML: true 9547 }, 9548 xAxis: [{ 9549 type: 'datetime', 9550 dateTimeLabelFormats: { 9551 hour: '%H:%M', 9552 day: '%e. %b' 9553 }, 9554 labels:{ 9555 useHTML: true, 9556 align: 'center', 9557 formatter: function () { 9558 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9559 } 9560 } 9561 }], 9562 yAxis: [{ 9563 title: { 9564 text: 'Temperaturen' 9565 }, 9566 //floor: 0, 9567 labels: { 9568 format: "{value} °C" 9569 }, 9570 // softMin:0, 9571 // softMax: 20, 9572 // allowDecimals: false, 9573 // minorTickInterval: 1, 9574 // //gridLineColor: '#C0C0C0', 9575 tickInterval: 10, 9576 minorTickInterval: 'auto', 9577 minPadding: 0.01, 9578 maxPadding: 0.01, 9579 minRange: 5 9580 }], 9581 tooltip: { 9582 crosshairs: true, 9583 shared: true, 9584 valueSuffix: '°C', 9585 shape: 'square', 9586 useHTML: true, 9587 zIndex: 50, 9588 formatter: function () { 9589 var date_format; 9590 date_format="%A, den %e.%B, %H:%M Uhr"; 9591 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9592 this.points.sort( ordertooltip ); 9593 $.each(this.points, function () { 9594 var unit = '°C'; 9595 if (this.series.name == 'Relative Luftfeuchtigkeit') { 9596 unit = '%'; 9597 } 9598 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9599 '<b>'+Math.round(this.y*10)/10 + '</b> ' + unit; 9600 }); 9601 return s; 9602 } 9603 }, 9604 plotOptions: { 9605 area: { 9606 fillColor: { 9607 linearGradient: { 9608 x1: 0, 9609 y1: 0, 9610 x2: 0, 9611 y2: 1 9612 }, 9613 stops: [ 9614 [0, '#d4ebfc'], 9615 [1, '#e5f2fc'] 9616 ] 9617 }, 9618 marker: { 9619 radius: 2 9620 }, 9621 lineWidth: 1, 9622 states: { 9623 hover: { 9624 lineWidth: 1 9625 } 9626 }, 9627 threshold: null 9628 } 9629 }, 9630 credits: { enabled: false }, 9631 exporting: { enabled: false }, 9632 series: vhstation_tl_data2, 9633 reflow: true 9634 }); 9635 } 9636 9637 if (typeof vhstation_wind_data !== 'undefined' && vhstation_wind_data) { 9638 $('#vh-stationen-chart').highcharts({ 9639 chart: { 9640// marginLeft:69, 9641 height: 360, 9642 events: { 9643 load: function(){ 9644 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9645 drawNightShadows(this,1); 9646 } 9647 drawWindArrowsVH(this); 9648 }, 9649 redraw: function(){ 9650 //drawBlocksForWindArrows(this); 9651 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9652 drawNightShadows(this,1); 9653 } 9654 drawWindArrowsVH(this); 9655 } 9656 } 9657 }, 9658 title: 'false', 9659 legend: { 9660 useHTML: true 9661 }, 9662 xAxis: { 9663 type: 'datetime', 9664 offset: 40, 9665 dateTimeLabelFormats: { 9666 hour: '%H:%M', 9667 day: '%e. %b' 9668 }, 9669 labels:{ 9670 useHTML: true, 9671 align: 'center', 9672 formatter: function () { 9673 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9674 } 9675 } 9676 }, 9677 yAxis: { 9678 title: { 9679 text: false 9680 }, 9681 labels: { 9682 format: "{value} "+getVHStationUnit() 9683 }, 9684 min:0, 9685 softMax: getVHStationUnitSoftMax(), 9686 allowDecimals: false, 9687 minorTickInterval: 1, 9688 //gridLineColor: '#C0C0C0', 9689 tickAmount: 5 9690 }, 9691 tooltip: { 9692 crosshairs: true, 9693 shared: true, 9694 valueSuffix: ' '+getVHStationUnit(),
9695 shape: 'square', 9696 useHTML: true, 9697 formatter: function () { 9698 // fix for faulty highcharts tooltip recognition 9699 var date_format; 9700 date_format="%A, den %e.%B, %H:%M Uhr"; 9701 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9702 var c=0; 9703 9704 var sortedPoints = this.points.sort(function(a, b){ 9705 return ((a.y > b.y) ? -1 : ((a.y < b.y) ? 1 : 0)); 9706 }); 9707 9708 $.each(sortedPoints, function () { 9709 c++; 9710 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9711 '<b>'+this.y + '</b> ' + ' '+getVHStationUnit(); 9712 }); 9713 return '<div class="highcharts-tooltip">' + s + '</div>'; 9714 } 9715 }, 9716 credits: { enabled: false }, 9717 exporting: { enabled: false }, 9718 series: vhstation_wind_data, 9719 reflow: true 9720 }); 9721 } 9722 if (typeof vhstation_glrad_data !== 'undefined' && vhstation_glrad_data) { 9723 $('#vh-stationen-chart').highcharts({ 9724 chart: { 9725// marginLeft:69, 9726 height: 360, 9727 events: { 9728 load: function(){ 9729 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9730 drawNightShadows(this,1); 9731 } 9732 }, 9733 redraw: function(){ 9734 //drawBlocksForWindArrows(this); 9735 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9736 drawNightShadows(this,1); 9737 } 9738 } 9739 } 9740 }, 9741 title: 'false', 9742 legend: { 9743 useHTML: true 9744 }, 9745 xAxis: { 9746 type: 'datetime', 9747 dateTimeLabelFormats: { 9748 hour: '%H:%M', 9749 day: '%e. %b' 9750 }, 9751 labels:{ 9752 useHTML: true, 9753 align: 'center', 9754 formatter: function () { 9755 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9756 } 9757 } 9758 }, 9759 yAxis: { 9760 title: { 9761 text: false 9762 }, 9763 labels: { 9764 format: "{value} "+getVHStationUnit() 9765 }, 9766 min:0, 9767 softMax: getVHStationUnitSoftMax(), 9768 allowDecimals: false, 9769 minorTickInterval: 1, 9770 //gridLineColor: '#C0C0C0', 9771 tickAmount: 5 9772 }, 9773 tooltip: { 9774 crosshairs: true, 9775 shared: true, 9776 valueSuffix: ' '+getVHStationUnit(), 9777 shape: 'square', 9778 useHTML: true, 9779 formatter: function () { 9780 // fix for faulty highcharts tooltip recognition 9781 var date_format; 9782 date_format="%A, den %e.%B, %H:%M Uhr"; 9783 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9784 var c=0; 9785 9786 var sortedPoints = this.points.sort(function(a, b){ 9787 return ((a.y > b.y) ? -1 : ((a.y < b.y) ? 1 : 0)); 9788 }); 9789 9790 $.each(sortedPoints, function () { 9791 c++; 9792 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9793 '<b>'+this.y + '</b> ' + ' '+getVHStationUnit(); 9794 }); 9795 return '<div class="highcharts-tooltip">' + s + '</div>'; 9796 } 9797 }, 9798 credits: { enabled: false }, 9799 exporting: { enabled: false }, 9800 series: vhstation_glrad_data, 9801 reflow: true 9802 }); 9803 } 9804 9805 if (typeof vhstation_prs_data !== 'undefined' && vhstation_prs_data) { 9806 $('#vh-stationen-chart').highcharts({ 9807 chart: { 9808// marginLeft:69, 9809 height: 360, 9810 events: { 9811 load: function(){ 9812 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9813 drawNightShadows(this,1); 9814 } 9815 }, 9816 redraw: function(){ 9817 //drawBlocksForWindArrows(this); 9818 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9819 drawNightShadows(this,1); 9820 } 9821 } 9822 } 9823 }, 9824 title: 'false', 9825 legend: { 9826 useHTML: true 9827 }, 9828 xAxis: { 9829 type: 'datetime', 9830 dateTimeLabelFormats: { 9831 hour: '%H:%M', 9832 day: '%e. %b' 9833 }, 9834 labels:{ 9835 useHTML: true, 9836 align: 'center', 9837 formatter: function () { 9838 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9839 } 9840 } 9841 }, 9842 yAxis: { 9843 title: { 9844 text: false 9845 }, 9846 labels: { 9847 format: "{value} "+getVHStationUnit() 9848 }, 9849 tickAmount: 5, 9850 minTickInterval: 5, 9851 minorTickInterval: 'auto' 9852 }, 9853 tooltip: { 9854 crosshairs: true, 9855 shared: true, 9856 valueSuffix: ' '+getVHStationUnit(),
9857 shape: 'square', 9858 useHTML: true, 9859 formatter: function () { 9860 // fix for faulty highcharts tooltip recognition 9861 var date_format; 9862 date_format="%A, den %e.%B, %H:%M Uhr"; 9863 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9864 var c=0; 9865 9866 var sortedPoints = this.points.sort(function(a, b){ 9867 return ((a.y > b.y) ? -1 : ((a.y < b.y) ? 1 : 0)); 9868 }); 9869 9870 $.each(sortedPoints, function () { 9871 c++; 9872 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9873 '<b>'+this.y + '</b> ' + ' '+getVHStationUnit(); 9874 }); 9875 return '<div class="highcharts-tooltip">' + s + '</div>'; 9876 } 9877 }, 9878 credits: { enabled: false }, 9879 exporting: { enabled: false }, 9880 series: vhstation_prs_data, 9881 reflow: true 9882 }); 9883 } 9884 if (typeof vhstation_lwet_data !== 'undefined' && vhstation_lwet_data) { 9885 $('#vh-stationen-chart').highcharts({ 9886 chart: { 9887// marginLeft:69, 9888 height: 360, 9889 events: { 9890 load: function(){ 9891 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9892 drawNightShadows(this,1); 9893 } 9894 }, 9895 redraw: function(){ 9896 //drawBlocksForWindArrows(this); 9897 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 9898 drawNightShadows(this,1); 9899 } 9900 } 9901 } 9902 }, 9903 title: 'false', 9904 legend: { 9905 useHTML: true 9906 }, 9907 xAxis: { 9908 type: 'datetime', 9909 dateTimeLabelFormats: { 9910 hour: '%H:%M', 9911 day: '%e. %b' 9912 }, 9913 labels:{ 9914 useHTML: true, 9915 align: 'center', 9916 formatter: function () { 9917 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 9918 } 9919 } 9920 }, 9921 yAxis: { 9922 title: { 9923 text: false 9924 }, 9925 labels: { 9926 format: "{value} "+getVHStationUnit() 9927 }, 9928 min:0, 9929 max:100, 9930 allowDecimals: false, 9931 minorTickInterval: 1, 9932 //gridLineColor: '#C0C0C0', 9933 tickAmount: 5 9934 }, 9935 tooltip: { 9936 crosshairs: true, 9937 shared: true, 9938 valueSuffix: ' '+getVHStationUnit(), 9939 shape: 'square', 9940 useHTML: true, 9941 formatter: function () { 9942 // fix for faulty highcharts tooltip recognition 9943 var date_format; 9944 date_format="%A, den %e.%B, %H:%M Uhr"; 9945 var s = '<span style="font-size:10px;">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 9946 var c=0; 9947 9948 var sortedPoints = this.points.sort(function(a, b){ 9949 return ((a.y > b.y) ? -1 : ((a.y < b.y) ? 1 : 0)); 9950 }); 9951 9952 $.each(sortedPoints, function () { 9953 c++; 9954 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 9955 '<b>'+this.y + '</b> ' + ' '+getVHStationUnit(); 9956 }); 9957 return '<div class="highcharts-tooltip">' + s + '</div>'; 9958 } 9959 }, 9960 plotOptions: { 9961 area: { 9962 zones: [ 9963 {value: 1, color: '#90b466'}, 9964 {value: 2, color: '#8eb365'}, 9965 {value: 3, color: '#8cb364'}, 9966 {value: 4, color: '#8ab263'}, 9967 {value: 5, color: '#88b263'}, 9968 {value: 6, color: '#86b162'}, 9969 {value: 7, color: '#84b161'}, 9970 {value: 8, color: '#82b060'}, 9971 {value: 9, color: '#80b05f'}, 9972 {value: 10, color: '#7daf5e'}, 9973 {value: 11, color: '#7baf5e'}, 9974 {value: 12, color: '#79ae5d'}, 9975 {value: 13, color: '#77ae5c'}, 9976 {value: 14, color: '#75ad5b'}, 9977 {value: 15, color: '#73ad5a'}, 9978 {value: 16, color: '#71ac59'}, 9979 {value: 17, color: '#6fac58'},
9980 {value: 18, color: '#6dab58'}, 9981 {value: 19, color: '#6bab57'}, 9982 {value: 20, color: '#69aa56'}, 9983 {value: 21, color: '#67a955'}, 9984 {value: 22, color: '#65a954'}, 9985 {value: 23, color: '#63a853'}, 9986 {value: 24, color: '#61a852'}, 9987 {value: 25, color: '#5fa752'}, 9988 {value: 26, color: '#5ca751'}, 9989 {value: 27, color: '#5aa650'}, 9990 {value: 28, color: '#58a64f'}, 9991 {value: 29, color: '#56a54e'}, 9992 {value: 30, color: '#54a54d'}, 9993 {value: 31, color: '#52a44d'}, 9994 {value: 32, color: '#50a44c'}, 9995 {value: 33, color: '#4ea34b'}, 9996 {value: 34, color: '#4ca34a'}, 9997 {value: 35, color: '#4aa249'}, 9998 {value: 36, color: '#48a248'}, 9999 {value: 37, color: '#46a147'}, 10000 {value: 38, color: '#44a147'}, 10001 {value: 39, color: '#42a046'}, 10002 {value: 40, color: '#40a045'}, 10003 {value: 41, color: '#3e9f44'}, 10004 {value: 42, color: '#3c9e43'}, 10005 {value: 43, color: '#399e42'}, 10006 {value: 44, color: '#379d42'}, 10007 {value: 45, color: '#359d41'}, 10008 {value: 46, color: '#339c40'}, 10009 {value: 47, color: '#319c3f'}, 10010 {value: 48, color: '#2f9b3e'}, 10011 {value: 49, color: '#2d9b3d'}, 10012 {value: 50, color: '#2b9a3c'}, 10013 {value: 51, color: '#2a9a3d'}, 10014 {value: 52, color: '#299a3f'}, 10015 {value: 53, color: '#289a41'}, 10016 {value: 54, color: '#279a43'}, 10017 {value: 55, color: '#269b45'}, 10018 {value: 56, color: '#259b47'}, 10019 {value: 57, color: '#249b49'}, 10020 {value: 58, color: '#249b4b'}, 10021 {value: 59, color: '#239b4d'}, 10022 {value: 60, color: '#229b4f'}, 10023 {value: 61, color: '#219b51'}, 10024 {value: 62, color: '#209b53'}, 10025 {value: 63, color: '#1f9c55'}, 10026 {value: 64, color: '#1f9c57'}, 10027 {value: 65, color: '#1e9c59'}, 10028 {value: 66, color: '#1d9c5b'}, 10029 {value: 67, color: '#1c9c5d'}, 10030 {value: 68, color: '#1b9c5f'}, 10031 {value: 69, color: '#1a9c61'}, 10032 {value: 70, color: '#199c63'}, 10033 {value: 71, color: '#199d65'}, 10034 {value: 72, color: '#189d67'}, 10035 {value: 73, color: '#179d69'}, 10036 {value: 74, color: '#169d6b'}, 10037 {value: 75, color: '#159d6d'}, 10038 {value: 76, color: '#149d6e'}, 10039 {value: 77, color: '#149d70'}, 10040 {value: 78, color: '#139d72'}, 10041 {value: 79, color: '#129e74'}, 10042 {value: 80, color: '#119e76'}, 10043 {value: 81, color: '#109e78'}, 10044 {value: 82, color: '#0f9e7a'}, 10045 {value: 83, color: '#0e9e7c'}, 10046 {value: 84, color: '#0e9e7e'},
10047 {value: 85, color: '#0d9e80'}, 10048 {value: 86, color: '#0c9e82'}, 10049 {value: 87, color: '#0b9e84'}, 10050 {value: 88, color: '#0a9f86'}, 10051 {value: 89, color: '#099f88'}, 10052 {value: 90, color: '#089f8a'}, 10053 {value: 91, color: '#089f8c'}, 10054 {value: 92, color: '#079f8e'}, 10055 {value: 93, color: '#069f90'}, 10056 {value: 94, color: '#059f92'}, 10057 {value: 95, color: '#049f94'}, 10058 {value: 96, color: '#03a096'}, 10059 {value: 97, color: '#03a098'}, 10060 {value: 98, color: '#02a09a'}, 10061 {value: 99, color: '#01a09c'}, 10062 {color: '#00a09e'}, 10063 ] 10064 } 10065 }, 10066 credits: { enabled: false }, 10067 exporting: { enabled: false }, 10068 series: vhstation_lwet_data, 10069 reflow: true 10070 }); 10071 } 10072 if (typeof vhstation_soil_data != 'undefined' && vhstation_soil_data) { 10073 $('#vh-stationen-chart').highcharts({ 10074 chart: { 10075 height: 360,//, 10076 events: { 10077 load: function(){ 10078 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 10079 drawNightShadows(this,1); 10080 } 10081 }, 10082 redraw: function(){ 10083 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 10084 drawNightShadows(this,1); 10085 } 10086 } 10087 } 10088 }, 10089 title: 'false', 10090 legend: { 10091 useHTML: true 10092 }, 10093 xAxis: [{ 10094 type: 'datetime', 10095 dateTimeLabelFormats: { 10096 hour: '%H:%M', 10097 day: '%e. %b' 10098 }, 10099 labels:{ 10100 useHTML: true, 10101 align: 'center', 10102 formatter: function () { 10103 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 10104 } 10105 } 10106 }], 10107 yAxis: [{ 10108 title: { 10109 text: 'Feuchtigkeit' 10110 }, 10111 //floor: 0, 10112 labels: { 10113 format: "{value}%" 10114 }, 10115 min: 0, 10116 max: 100, 10117 softMax: 80, 10118 tickAmount: 6, 10119 allowDecimals: false, 10120 },{ 10121 title: { 10122 text: 'Temperatur' 10123 }, 10124 //floor: 0, 10125 labels: { 10126 format: "{value} °C" 10127 }, 10128 opposite: true, 10129 softMin: 0, 10130 softMax: 20, 10131 minRange: 20, 10132 allowDecimals: false, 10133 minorTickInterval: 1, 10134 //gridLineColor: '#C0C0C0', 10135 tickAmount: 6 10136 }], 10137 tooltip: { 10138 crosshairs: true, 10139 shared: true, 10140 valueSuffix: '°C', 10141 shape: 'square', 10142 useHTML: true, 10143 zIndex: 50, 10144 formatter: function () { 10145 var date_format; 10146 date_format="%A, den %e.%B, %H:%M Uhr"; 10147 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 10148 this.points.sort( ordertooltip ); 10149 $.each(this.points, function () { 10150 var digits = 1; 10151 var unit = '%'; 10152 if (typeof this.series.name === 'string' && this.series.name.substring(0,15) === 'Bodentemperatur') { 10153 digits = 1; 10154 unit = '°C'; 10155 } 10156 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 10157 '<b>'+Highcharts.numberFormat(this.y,digits) + '</b> ' + unit; 10158 }); 10159 return s; 10160 } 10161 }, 10162 credits: { enabled: false }, 10163 exporting: { enabled: false }, 10164 series: vhstation_soil_data, 10165 reflow: true 10166 }); 10167 } 10168 if (typeof vhstation_soilba_data != 'undefined' && vhstation_soilba_data) { 10169 $('#vh-stationen-chart').highcharts({ 10170 chart: { 10171 height: 360,//, 10172 events: { 10173 load: function(){ 10174 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 10175 drawNightShadows(this,1); 10176 } 10177 }, 10178 redraw: function(){ 10179 if ($('#btn-vhs-mode-minutes').hasClass('btn-active') || $('#btn-vhs-mode-hour').hasClass('btn-active')) { 10180 drawNightShadows(this,1); 10181 } 10182 } 10183 } 10184 }, 10185 title: 'false', 10186 legend: { 10187 useHTML: true 10188 }, 10189 xAxis: [{ 10190 type: 'datetime', 10191 dateTimeLabelFormats: { 10192 hour: '%H:%M', 10193 day: '%e. %b' 10194 }, 10195 labels:{ 10196 useHTML: true, 10197 align: 'center', 10198 formatter: function () { 10199 return Highcharts.dateFormat(getVHStationDateFormat(this.value), this.value); 10200 } 10201 } 10202 }], 10203 yAxis: [{ 10204 title: { 10205 text: 'Bodensaugspannung' 10206 }, 10207 //floor: 0, 10208 labels: { 10209 format: "{value}hPa" 10210 }, 10211 softMin: -600, 10212 softMax: -100, 10213 tickAmount: 6, 10214 allowDecimals: false, 10215 },{ 10216 title: { 10217 text: 'Temperatur' 10218 }, 10219 //floor: 0, 10220 labels: { 10221 format: "{value} °C" 10222 }, 10223 opposite: true, 10224 softMin: 0, 10225 softMax: 20, 10226 minRange: 20, 10227 allowDecimals: false, 10228 minorTickInterval: 1, 10229 //gridLineColor: '#C0C0C0', 10230 tickAmount: 6 10231 }], 10232 tooltip: { 10233 crosshairs: true, 10234 shared: true, 10235 valueSuffix: '°C',
10236 shape: 'square', 10237 useHTML: true, 10238 zIndex: 50, 10239 formatter: function () { 10240 var date_format; 10241 date_format="%A, den %e.%B, %H:%M Uhr"; 10242 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(getVHStationDateFormat(this.x, true), this.x)+ '</span> '; 10243 this.points.sort( ordertooltip ); 10244 $.each(this.points, function () { 10245 var digits = 1; 10246 var unit = 'hPa'; 10247 if (typeof this.series.name === 'string' && this.series.name.substring(0,15) === 'Bodentemperatur') { 10248 digits = 1; 10249 unit = '°C'; 10250 } 10251 s += '<br/>' + '<span class="hc-legend-color" style="color:' + this.series.color + '">' + 'â' + '</span> '+ this.series.name + ': ' + 10252 '<b>'+Highcharts.numberFormat(this.y,digits) + '</b> ' + unit; 10253 }); 10254 return s; 10255 } 10256 }, 10257 credits: { enabled: false }, 10258 exporting: { enabled: false }, 10259 series: vhstation_soilba_data, 10260 reflow: true 10261 }); 10262 } 10263}; 10264 10265var plotPhaenologie = function() { 10266 if (typeof vh_phaeno_plant_data != 'undefined' && typeof vh_phaeno_chosen_plant != 'undefined') { 10267 var timezone_id_local = typeof timezone_id !== 'undefined' ? timezone_id : null; 10268 Highcharts.setOptions({ 10269 chart: { 10270 style: { 10271 fontFamily: 'Open Sans' 10272 } 10273 }, 10274 global: { 10275 /** 10276 * Use moment-timezone.js to return the timezone offset for individual 10277 * timestamps, used in the X axis labels and the tooltip header. 10278 */ 10279 // getTimezoneOffset: function (timestamp) { 10280 // return -moment.tz(timezone_id).utcOffset(); 10281 // } 10282 timezone: timezone_id_local || $('#real-user-timezone').attr('data-value') || 'UTC' 10283 10284 }, 10285 lang: { 10286 loading: 'Wird geladen...', 10287 months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], 10288 weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], 10289 shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], 10290 } 10291 }); 10292 10293 // Drop-in fix for Highcharts issue #8477 on older Highcharts versions. The 10294 // issue is fixed since Highcharts v6.1.1. 10295 Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotLinePath', function(proceed) { 10296 var path = proceed.apply(this, Array.prototype.slice.call(arguments, 1)); 10297 if (path) { 10298 path.flat = false; 10299 } 10300 return path; 10301 }); 10302 10303 Highcharts.Chart.prototype.firstRender = (function (func){ 10304 return function(){ 10305 func.apply(this, arguments); 10306 $.each(this.axes, function(){ 10307 $.each(this.plotLinesAndBands, function(){ 10308 if(this.label) 10309 this.label.toFront(); 10310 }); 10311 }); 10312 if(this.tooltip && this.tooltip.label) 10313 this.tooltip.label.toFront(); 10314 10315 if(this.seriesGroup && this.seriesGroup.label) 10316 this.seriesGroup.label.toFront(); 10317 } 10318 } (Highcharts.Chart.prototype.firstRender)); 10319 10320 var monthBands = { 10321 zIndex: 3, 10322 borderWidth: 1, 10323 borderColor: '#666666', 10324 color: '#bee0ff29', 10325 label: { 10326 y: 20, 10327 style: { 10328 fontWeight: '700', 10329 color: '#666666' 10330 } 10331 } 10332 } 10333 10334 10335 var groupPadding = 0; 10336 10337 if(vh_phaeno_xaxis_categories.length >= 1) { 10338 groupPadding = 0.35; 10339 } 10340 if(vh_phaeno_xaxis_categories.length >= 2) { 10341 groupPadding = 0.25; 10342 } 10343 if(vh_phaeno_xaxis_categories.length >= 3) { 10344 groupPadding = 0.2; 10345 } 10346 if(vh_phaeno_xaxis_categories.length >= 4) { 10347 groupPadding = 0.1; 10348 } 10349 if(vh_phaeno_xaxis_categories.length >= 5) { 10350 groupPadding = 0; 10351 } 10352 10353 function dateFromDay(day){ 10354 10355 if(day < 0) 10356 day +=1 ; 10357 10358 return moment({year: 1971, month: 0}).dayOfYear(day); 10359 } 10360 10361 var crosshairFormatter = function() { 10362 console.log(this); 10363 } 10364 10365 var tooltipFormatter = function() { 10366 10367 //Extrema 10368 if(typeof this.date != 'undefined' && this.date.length == 8) { 10369 var year = +this.date.substr(0, 4);
10370 var month = +this.date.substr(4, 2) - 1; 10371 var day = +this.date.substr(6, 2); 10372 10373 var date = moment({year: year, month: month, day: day}); 10374 var dateFormat = Highcharts.dateFormat('%e. %b %Y', date); 10375 return '<span style="color:' + this.color + '">\u25CF</span> ' + this.series.name + ': <b>' + dateFormat + '</b><br/>'; 10376 } 10377 10378 //Durchschnitt 10379 if(typeof this.date != 'undefined' && this.date.length == 4) { 10380 var month = +this.date.substr(0, 2) - 1; 10381 var day = +this.date.substr(2, 2); 10382 10383 var date = moment({year: 1971, month: month, day: day}); 10384 var dateFormat = Highcharts.dateFormat('%e. %b', date); 10385 return '<span style="color:' + this.color + '">\u25CF</span> ' + this.series.name + ': <b>' + dateFormat + '</b><br/>'; 10386 } 10387 10388 //Perzentile 10389 if(typeof this.lowDate != 'undefined' && typeof this.highDate != 'undefined' && this.series.options.id.indexOf('percentile') !== -1) { 10390 var lowMonth = +this.lowDate.substr(0, 2) - 1; 10391 var lowDay = +this.lowDate.substr(2, 2); 10392 var lowDate = moment({year: 1971, month: lowMonth, day: lowDay}); 10393 10394 if(this.lowDate == '****') 10395 lowDate = dateFromDay(this.low); 10396 10397 var lowDateFormat = Highcharts.dateFormat('%e. %b', lowDate); 10398 10399 var highMonth = +this.highDate.substr(0, 2) - 1; 10400 var highDay = +this.highDate.substr(2, 2); 10401 var highDate = moment({year: 1971, month: highMonth, day: highDay}); 10402 10403 if(this.highDate == '****') 10404 highDate = dateFromDay(this.high); 10405 10406 var highDateFormat = Highcharts.dateFormat('%e. %b', highDate); 10407 return '<span style="color:' + this.color + '">\u25CF</span> ' + this.series.name + ': <b>' + lowDateFormat + ' - ' + highDateFormat + '</b><br/>'; 10408 10409 } 10410 10411 //Allzeit-Bandbreite 10412 if(typeof this.lowDate != 'undefined' && typeof this.highDate != 'undefined' && this.series.options.id == 'alltime-bandwidth') { 10413 var lowYear = +this.lowDate.substr(0, 4); 10414 var lowMonth = +this.lowDate.substr(4, 2) - 1; 10415 var lowDay = +this.lowDate.substr(6, 2); 10416 var lowDate = moment({year: lowYear, month: lowMonth, day: lowDay}); 10417 10418 if(this.lowDate == '****') 10419 lowDate = dateFromDay(this.low); 10420 10421 var lowDateFormat = Highcharts.dateFormat('%e. %b (%Y)', lowDate); 10422 10423 var highYear = +this.highDate.substr(0, 4); 10424 var highMonth = +this.highDate.substr(4, 2) - 1; 10425 var highDay = +this.highDate.substr(6, 2); 10426 var highDate = moment({year: highYear, month: highMonth, day: highDay}); 10427 10428 if(this.highDate == '****') 10429 highDate = dateFromDay(this.high); 10430 10431 var highDateFormat = Highcharts.dateFormat('%e. %b (%Y)', highDate); 10432 return '<span style="color:' + this.color + '">\u25CF</span> ' + this.series.name + ': <b>' + lowDateFormat + ' - ' + highDateFormat + '</b><br/>'; 10433 10434 } 10435 10436 }; 10437 10438 var legendItemClick = function() { 10439 var hasDataShown = new Array(vh_phaeno_xaxis_categories.length).fill(false); 10440 10441 var clickedSeries = this; 10442 10443 var allHidden = true;
10444 this.chart.legend.getAllItems().forEach(function(series) { 10445 if(series.options.id == clickedSeries.options.id) return; 10446 10447 if(series.visible) 10448 allHidden = false; 10449 10450 // console.log(series.visible); 10451 }) 10452 10453 if(!allHidden) 10454 this.setVisible(!this.visible); 10455 else 10456 this.setVisible(true); 10457 10458 this.chart.series.forEach(function(seriesObj) { 10459 if(!seriesObj.visible) return; 10460 10461 seriesObj.data.forEach(function(point) { 10462 hasDataShown[point.x] = true; 10463 }); 10464 }); 10465 //console.log(hasDataShown); 10466 10467 var breaks = []; 10468 hasDataShown.forEach(function(hasData, index) { 10469 10470 if(!hasData) 10471 breaks.push( {from: index - .5, to: index + .5} ); 10472 10473 }); 10474 10475 //this.chart.xAxis[0].options.breaks = breaks; 10476 //this.chart.redraw(); 10477 this.chart.update({xAxis: [{breaks: breaks}]}); 10478 10479 return false; 10480 } 10481 10482 $('#phaeno-plant-chart').highcharts({ 10483 chart: { 10484 height: 500, 10485 type: 'columnrange', 10486 inverted: true 10487 }, 10488 title: { 10489 text: 'Mittelwertsdiagramm ' + vh_phaeno_chosen_plant.name 10490 }, 10491 legend: { 10492 useHTML: true 10493 }, 10494 plotOptions: { 10495 columnrange: { 10496 grouping: false, 10497 groupPadding: groupPadding, 10498 }, 10499 series: { 10500 softThreshold: true, 10501 threshold: 1, 10502 events: { 10503 legendItemClick: legendItemClick 10504 }, 10505 minPointLength: 5 10506 } 10507 }, 10508 tooltip: { 10509 pointFormatter: tooltipFormatter, 10510 positioner: function(labelWidth, labelHeight, point) { 10511 var x = this.chart.hoverPoint.x; 10512 var alltimeSeries = this.chart.get('alltime-bandwidth'); 10513 10514 var alltimePoint = alltimeSeries.points[x]; 10515 10516 if(point.plotX / this.chart.plotWidth < 0.5) { 10517 10518 var absX = this.chart.plotLeft + this.chart.plotWidth - alltimePoint.plotHigh + this.options.padding + 10; 10519 var absY = this.chart.plotTop + point.plotY; 10520 10521 var labelOffsetX = absX; 10522 var labelOffsetY = absY - labelHeight / 2; 10523 10524 return { x: labelOffsetX, y: labelOffsetY }; 10525 } else { 10526 var absX = this.chart.plotLeft + this.chart.plotWidth - alltimePoint.plotLow - labelWidth - this.options.padding - 10; 10527 var absY = this.chart.plotTop + point.plotY; 10528 10529 var labelOffsetX = absX; 10530 var labelOffsetY = absY - labelHeight / 2; 10531 10532 return { x: labelOffsetX, y: labelOffsetY }; 10533 } 10534 10535 return {x: 0, y: 0}; 10536 } 10537 }, 10538 xAxis: [ 10539 { 10540 type: 'category', 10541 categories: vh_phaeno_xaxis_categories, 10542 height: '90%', 10543 top: '10%', 10544 labels: { 10545 style: { 10546 fontSize: '13px', 10547 fontWeight: '600' 10548 } 10549 }, 10550 title: { 10551 text: 'verfügbare Phasen', 10552 style: {"fontWeight": "700"}, 10553 offset: 10, 10554 align: 'high', 10555 textAlign: 'right', 10556 rotation: 0, 10557 y: -15 10558 }, 10559 min: 0 10560 } 10561 ], 10562 yAxis: [ 10563 { 10564 type: 'linear', 10565 softMin: 1, 10566 max: 365, 10567 endOnTick: false, 10568 startOnTick: false, 10569 tickPixelInterval: 50, 10570 minorTickInterval: 'auto', 10571 tickLength: 10, 10572 tickWidth: 1, 10573 lineWidth: 1, 10574 opposite: true, 10575 title: { 10576 text: 'Tag im Jahr', 10577 style: {"fontWeight": "700"}, 10578 //offset: 14, 10579 align: 'low', 10580 x: 0 10581 }, 10582 labels:{ 10583 style: {"fontWeight": "700"}, 10584 }, 10585 plotBands: [{ 10586 from: -31, 10587 to: -1, 10588 borderWidth: monthBands.borderWidth, 10589 borderColor: monthBands.borderColor, 10590 color: monthBands.color, 10591 zIndex: monthBands.zIndex, 10592 label: { 10593 text: 'Dezember<br>Vorjahr', 10594 y: monthBands.label.y-7, 10595 style: monthBands.label.style 10596 } 10597 },{ 10598 from: 1, 10599 to: 31, 10600 borderWidth: monthBands.borderWidth, 10601 borderColor: monthBands.borderColor, 10602 color: monthBands.color, 10603 zIndex: monthBands.zIndex, 10604 label: { 10605 text: 'Januar', 10606 y: monthBands.label.y, 10607 style: monthBands.label.style 10608 } 10609 }, 10610 { 10611 from: 32, 10612 to: 59, 10613 borderWidth: monthBands.borderWidth, 10614 borderColor: monthBands.borderColor, 10615 color: monthBands.color, 10616 zIndex: monthBands.zIndex, 10617 label: { 10618 text: 'Februar', 10619 y: monthBands.label.y, 10620 style: monthBands.label.style 10621 } 10622 }, 10623 { 10624 from: 60, 10625 to: 90, 10626 borderWidth: monthBands.borderWidth, 10627 borderColor: monthBands.borderColor, 10628 color: monthBands.color, 10629 zIndex: monthBands.zIndex, 10630 label: { 10631 text: 'März', 10632 y: monthBands.label.y, 10633 style: monthBands.label.style 10634 } 10635 }, 10636 { 10637 from: 91, 10638 to: 120, 10639 borderWidth: monthBands.borderWidth, 10640 borderColor: monthBands.borderColor, 10641 color: monthBands.color, 10642 zIndex: monthBands.zIndex, 10643 label: { 10644 text: 'April', 10645 y: monthBands.label.y, 10646 style: monthBands.label.style 10647 } 10648 }, 10649 { 10650 from: 121, 10651 to: 151, 10652 borderWidth: monthBands.borderWidth, 10653 borderColor: monthBands.borderColor, 10654 color: monthBands.color, 10655 zIndex: monthBands.zIndex, 10656 label: { 10657 text: 'Mai', 10658 y: monthBands.label.y, 10659 style: monthBands.label.style 10660 } 10661 }, 10662 { 10663 from: 152, 10664 to: 181, 10665 borderWidth: monthBands.borderWidth, 10666 borderColor: monthBands.borderColor, 10667 color: monthBands.color, 10668 zIndex: monthBands.zIndex, 10669 label: { 10670 text: 'Juni', 10671 y: monthBands.label.y, 10672 style: monthBands.label.style 10673 } 10674 }, 10675 { 10676 from: 182, 10677 to: 212, 10678 borderWidth: monthBands.borderWidth, 10679 borderColor: monthBands.borderColor, 10680 color: monthBands.color, 10681 zIndex: monthBands.zIndex, 10682 label: { 10683 text: 'Juli', 10684 y: monthBands.label.y, 10685 style: monthBands.label.style 10686 } 10687 }, 10688 { 10689 from: 213, 10690 to: 243, 10691 borderWidth: monthBands.borderWidth, 10692 borderColor: monthBands.borderColor, 10693 color: monthBands.color, 10694 zIndex: monthBands.zIndex, 10695 label: { 10696 text: 'August', 10697 y: monthBands.label.y, 10698 style: monthBands.label.style 10699 } 10700 }, 10701 { 10702 from: 244, 10703 to: 273, 10704 borderWidth: monthBands.borderWidth, 10705 borderColor: monthBands.borderColor, 10706 color: monthBands.color, 10707 zIndex: monthBands.zIndex, 10708 label: { 10709 text: 'September', 10710 y: monthBands.label.y, 10711 style: monthBands.label.style 10712 } 10713 }, 10714 { 10715 from: 274, 10716 to: 304, 10717 borderWidth: monthBands.borderWidth, 10718 borderColor: monthBands.borderColor, 10719 color: monthBands.color, 10720 zIndex: monthBands.zIndex, 10721 label: { 10722 text: 'Oktober', 10723 y: monthBands.label.y, 10724 style: monthBands.label.style 10725 } 10726 }, 10727 { 10728 from: 305, 10729 to: 334, 10730 borderWidth: monthBands.borderWidth, 10731 borderColor: monthBands.borderColor, 10732 color: monthBands.color, 10733 zIndex: monthBands.zIndex, 10734 label: { 10735 text: 'November', 10736 y: monthBands.label.y, 10737 style: monthBands.label.style 10738 } 10739 }, 10740 { 10741 from: 335, 10742 to: 365, 10743 borderWidth: monthBands.borderWidth, 10744 borderColor: monthBands.borderColor, 10745 color: monthBands.color, 10746 zIndex: monthBands.zIndex, 10747 label: { 10748 text: 'Dezember', 10749 y: monthBands.label.y, 10750 style: monthBands.label.style 10751 } 10752 } 10753 ], 10754 plotLines: [{ 10755 color: 'rgba(51, 122, 183, 0.8)', 10756 value: moment().dayOfYear(), 10757 width: 2, 10758 zIndex: monthBands.zIndex + 1, 10759 label: { 10760 text: 'Heute ('+Highcharts.dateFormat('%e. %b %Y', moment())+')', 10761 rotation: 0, 10762 verticalAlign: 'bottom', 10763 y: -10, 10764 style: {fontWeight: '700', color: 'rgba(51, 122, 183, 1)' } 10765 } 10766 }] 10767 10768 }, 10769 { 10770 type: 'linear', 10771 linkedTo: 0, 10772 tickPixelInterval: 70, 10773 tickLength: 10, 10774 tickWidth: 1, 10775 lineWidth: 1, 10776 gridLineWidth: 0, 10777 title: { 10778 text: null 10779 }, 10780 labels:{ 10781 autoRotation: false, 10782 padding: 1, 10783 useHTML: true, 10784 align: 'center', 10785 style: {"fontWeight": "700"}, 10786 formatter: function () { 10787 return Highcharts.dateFormat('%e. %b', dateFromDay(this.value)); 10788 } 10789 } 10790 } 10791 ], 10792 credits: { enabled: false }, 10793 exporting: { enabled: false }, 10794 series: vh_phaeno_plant_data, 10795 reflow: true 10796 }); 10797 } 10798 10799}; 10800
10801var phaenologieShowYear = function(year) { 10802 var chart = $('#phaeno-plant-chart').highcharts(); 10803 10804 chart.series.forEach(function(series) { 10805 10806 if(series.options.id.includes('recent-year')) { 10807 series.setVisible(false, false); 10808 series.options.showInLegend = false; 10809 10810 if(series.options.id.includes(year)) { 10811 series.setVisible(true, false); 10812 series.options.showInLegend = true; 10813 } 10814 10815 } 10816 10817 }); 10818 10819 chart.redraw(); 10820 chart.legend.update(); 10821} 10822 10823var plotOverviewWidgetGraph = function() { 10824 10825 var margin; 10826 var timezone_id_local = typeof timezone_id !== 'undefined' ? timezone_id : null; 10827 Highcharts.setOptions({ 10828 global: { 10829 /** 10830 * Use moment-timezone.js to return the timezone offset for individual 10831 * timestamps, used in the X axis labels and the tooltip header. 10832 */ 10833 // getTimezoneOffset: function (timestamp) { 10834 // return -moment.tz(timezone_id).utcOffset(); 10835 // } 10836 timezone: timezone_id_local || $('#real-user-timezone').attr('data-value') || 'UTC' 10837 10838 }, 10839 lang: typeof hc_user_settings_lang !== 'undefined' ? hc_user_settings_lang : { 10840 loading: 'Wird geladen...', 10841 months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], 10842 weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], 10843 shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], 10844 } 10845 }); 10846 10847 var zeroline = 0; 10848 10849 if (typeof hcwidget_overview_data_temp != 'undefined') { 10850 var yaxismax = false; 10851 if (typeof hccompact_tempmax != 'undefined') { 10852 yaxismax = hccompact_tempmax > -2 && hccompact_tempmax < 2 ? true : false; 10853 } 10854 10855 if (typeof hccompact_units != 'undefined') { 10856 if(hccompact_units['temp']=="°F") { 10857 zeroline = 32; 10858 } 10859 else if(hccompact_units['temp']=="K") { 10860 zeroline = 273.15; 10861 } 10862 } 10863 10864 $('#temp_graph').highcharts({ 10865 chart: { 10866 height: 300, 10867 //width: 300, 10868 type: 'line', 10869 events: { 10870 load: function(){ 10871 //drawHourlyLabels(this,'temp'); 10872 drawNightShadows(this,1); 10873 }, 10874 redraw: function(){ 10875 //drawHourlyLabels(this,'temp'); 10876 drawNightShadows(this,1); 10877 } 10878 } 10879 }, 10880 title: 'false', 10881 legend: 'false', 10882 xAxis: { 10883 type: 'datetime', 10884 dateTimeLabelFormats: { 10885 hour: '%H:%M', 10886 day: '%e. %b' 10887 }, 10888 labels:{ 10889 useHTML: true, 10890 align: 'center', 10891 formatter: function () { 10892 var date_format; 10893 var day = Highcharts.dateFormat("%e", this.value); 10894 var hour = Highcharts.dateFormat("%H", this.value); 10895 10896 if(hour%24==0) 10897 date_format='%e. %b'; 10898 else 10899 date_format='%H:%M'; 10900 return Highcharts.dateFormat(date_format, this.value); 10901 } 10902 } 10903 }, 10904 yAxis: [{ 10905 title: { 10906 text: "" 10907 }, 10908 labels: { 10909 format: "{value} "+hccompact_units['temp'], 10910 style: { color: "#000000" } 10911 }, 10912 softMax: 2, 10913 allowDecimals: true, 10914 minorTickInterval: 'auto', 10915 gridLineColor: '#C0C0C0', 10916 opposite:true, 10917 plotLines: [{ 10918 value: zeroline, 10919 width: 2, 10920 color: '#808080', 10921 zIndex: 2 10922 }], 10923 }], 10924 tooltip: { 10925 crosshairs: true, 10926 shared: true, 10927 valueSuffix: ' '+hccompact_units['temp'],
10928 shape: 'square', 10929 useHTML: true, 10930 dateTimeLabelFormats: { 10931 minute:"%A, den %e.%B", 10932 hour:"%A, den %e.%B", 10933 }, 10934 zIndex: 50, 10935 positioner: function (w,h,p) { 10936 if(p.plotX/this.chart.chartWidth>0.5) 10937 return { x: 65, y: 0 }; 10938 else 10939 return { x: this.chart.chartWidth-w-10, y: 0 }; 10940 }, 10941 formatter: function () { 10942 var date_format; 10943 //date_format="%A, den %e.%B, %H:%M GMT+"+chartoffsethours; 10944 date_format="%A, den %e.%B, %H:%M "; 10945 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ 'Uhr</span> '; 10946 this.points.sort( ordertooltip ); 10947 $.each(this.points, function () { 10948 s += '<br/>' + '<span style="color:' + this.series.color + '">' + '</span> '+ this.series.name + ': ' + '<b>'+this.y + '</b> ' + ' '+hccompact_units['temp']; 10949 }); 10950 return s; 10951 } 10952 }, 10953 plotOptions: { 10954 line: { 10955 marker: { 10956 enabled: false 10957 } 10958 } 10959 }, 10960 credits: { enabled: false }, 10961 exporting: { enabled: false }, 10962 series: hcwidget_overview_data_temp, 10963 reflow: true 10964 }); 10965 10966 10967 } 10968 10969 if (typeof hcwidget_overview_data_rain != 'undefined') { 10970 var yaxismax = false; 10971 if (typeof hccompact_tempmax != 'undefined') { 10972 yaxismax = hccompact_tempmax > -2 && hccompact_tempmax < 2 ? true : false; 10973 } 10974 10975 zeroline = 0; 10976 10977 $('#rain_graph').highcharts({ 10978 chart: { 10979 height: 300, 10980 //width: 300, 10981 type: 'column', 10982 events: { 10983 load: function(){ 10984 //drawHourlyLabels(this,'temp'); 10985 drawNightShadows(this,2); 10986 }, 10987 redraw: function(){ 10988 //drawHourlyLabels(this,'temp'); 10989 drawNightShadows(this,2); 10990 } 10991 } 10992 }, 10993 title: 'false', 10994 legend: 'false', 10995 xAxis: { 10996 type: 'datetime', 10997 dateTimeLabelFormats: { 10998 hour: '%H:%M', 10999 day: '%e. %b' 11000 }, 11001 labels:{ 11002 useHTML: true, 11003 align: 'center', 11004 formatter: function () { 11005 var date_format; 11006 var day = Highcharts.dateFormat("%e", this.value); 11007 var hour = Highcharts.dateFormat("%H", this.value); 11008 11009 if(hour%24==0) 11010 date_format='%e. %b'; 11011 else 11012 date_format='%H:%M'; 11013 return Highcharts.dateFormat(date_format, this.value); 11014 } 11015 } 11016 }, 11017 yAxis: [{ 11018 title: { 11019 text: "" 11020 }, 11021 labels: { 11022 format: "{value} "+hccompact_units['rain'], 11023 style: { color: "#000000" } 11024 }, 11025 softMax: hccompact_units['rain']=="mm" ? 5 : 0.4, 11026 allowDecimals: true, 11027 minorTickInterval: 'auto', 11028 gridLineColor: '#C0C0C0', 11029 opposite:true, 11030 plotLines: [{ 11031 value: zeroline, 11032 width: 2, 11033 color: '#808080', 11034 zIndex: 2 11035 }], 11036 }], 11037 tooltip: { 11038 crosshairs: true, 11039 shared: true, 11040 valueSuffix: ' '+hccompact_units['rain'], 11041 shape: 'square', 11042 useHTML: true, 11043 dateTimeLabelFormats: { 11044 minute:"%A, den %e.%B", 11045 hour:"%A, den %e.%B", 11046 }, 11047 zIndex: 50, 11048 positioner: function (w,h,p) { 11049 if(p.plotX/this.chart.chartWidth>0.5) 11050 return { x: 65, y: 0 }; 11051 else 11052 return { x: this.chart.chartWidth-w-10, y: 0 }; 11053 }, 11054 formatter: function () { 11055 var date_format; 11056 //date_format="%A, den %e.%B, %H:%M GMT+"+chartoffsethours; 11057 date_format="%A, den %e.%B, %H:%M "; 11058 var s = '<span style="font-size:10px">'+Highcharts.dateFormat(date_format, this.x)+ 'Uhr</span> '; 11059 this.points.sort( ordertooltip ); 11060 $.each(this.points, function () { 11061 s += '<br/>' + '<span style="color:' + this.series.color + '">' + '</span> '+ this.series.name + ': ' + '<b>'+this.y + '</b> ' + ' '+hccompact_units['rain']; 11062 }); 11063 return s; 11064 } 11065 }, 11066 plotOptions: { 11067 line: { 11068 marker: { 11069 enabled: false 11070 } 11071 }, 11072 series: { 11073 stacking: 'normal' 11074 } 11075 }, 11076 credits: { enabled: false }, 11077 exporting: { enabled: false }, 11078 series: hcwidget_overview_data_rain, 11079 reflow: true 11080 }); 11081 11082 11083 } 11084 11085 11086} 11087
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.