function Meteogram(json, container) {
this.precipitations = [];
this.precipitationsError = [];
this.container = container;
text: 'Light rain showers'
text: 'Heavy rain showers'
lightrainshowersandthunder: {
text: 'Light rain showers and thunder'
text: 'Rain showers and thunder'
heavyrainshowersandthunder: {
text: 'Heavy rain showers and thunder'
text: 'Light sleet showers'
text: 'Heavy sleet showers'
lightsleetshowersandthunder: {
text: 'Light sleet showers and thunder'
sleetshowersandthunder: {
text: 'Sleet showers and thunder'
heavysleetshowersandthunder: {
text: 'Heavy sleet showers and thunder'
text: 'Light snow showers'
text: 'Heavy show showers'
lightsnowshowersandthunder: {
text: 'Light snow showers and thunder'
text: 'Snow showers and thunder'
heavysnowshowersandthunder: {
text: 'Heavy snow showers and thunder'
text: 'Light rain and thunder'
text: 'Heavy rain and thunder'
text: 'Light sleet and thunder'
text: 'Sleet and thunder'
text: 'Heavy sleet and thunder'
text: 'Light snow and thunder'
text: 'Heavy snow and thunder'
Meteogram.prototype.drawWeatherSymbols = function (chart) {
chart.series[0].data.forEach((point, i) => {
if (this.resolution > 36e5 || i % 2 === 0) {
const [symbol, specifier] = this.symbols[i].split('_'),
icon = Meteogram.dictionary[symbol].symbol +
({ day: 'd', night: 'n' }[specifier] || '');
if (Meteogram.dictionary[symbol]) {
'https://cdn.jsdelivr.net/gh/nrkno/yr-weather-symbols' +
`@8.0.1/dist/svg/${icon}.svg`,
point.plotX + chart.plotLeft - 8,
point.plotY + chart.plotTop - 30,
Meteogram.prototype.drawBlocksForWindArrows = function (chart) {
const xAxis = chart.xAxis[0];
let pos = xAxis.min, max = xAxis.max, i = 0;
pos <= max + 36e5; pos += 36e5,
const isLast = pos === max + 36e5,
x = Math.round(xAxis.toPixels(pos)) + (isLast ? 0.5 : -0.5);
const isLong = this.resolution > 36e5 ?
pos % this.resolution === 0 :
'M', x, chart.plotTop + chart.plotHeight + (isLong ? 0 : 28),
'L', x, chart.plotTop + chart.plotHeight + 32,
stroke: chart.options.chart.plotBorderColor,
chart.get('windbarbs').markerGroup.attr({
translateX: chart.get('windbarbs').markerGroup.translateX + 8
Meteogram.prototype.getChartOptions = function () {
renderTo: this.container,
id: 'precipitation-error',
'M', 3.3, 0, 'L', -6.7, 10,
'M', 6.7, 0, 'L', -3.3, 10,
'M', 13.3, 0, 'L', 3.3, 10,
'M', 16.7, 0, 'L', 6.7, 10
text: 'Meteogram for London, England',
text: 'Forecast from <a href="https://yr.no">yr.no</a>',
'<small>{point.x:%A, %b %e, %H:%M} - ' +
'{point.point.to:%H:%M}</small><br>' +
'<b>{point.point.symbolName}</b><br>'
gridLineColor: 'rgba(128, 128, 128, 0.1)',
tickInterval: 24 * 3600 * 1000,
format: '{value:<span style="font-size: 12px; font-weight: ' +
'bold">%a</span> %b %e}',
gridLineColor: 'rgba(128, 128, 128, 0.1)'
color: Highcharts.getOptions().colors[2]
color: Highcharts.getOptions().colors[2]
pointPlacement: 'between'
pointFormat: '<span style="color:{point.color}">\u25CF</span>' +
'{series.name}: <b>{point.y}°C</b><br/>'
data: this.precipitationsError,
color: 'url(#precipitation-error)',
pointFormat: '<span style="color:{point.color}">\u25CF</span>' +
'{series.name}: <b>{point.minvalue} mm - ' +
'{point.maxvalue} mm</b><br/>'
enabled: this.hasPrecipitationError,
data: this.precipitations,
enabled: !this.hasPrecipitationError,
color: Highcharts.getOptions().colors[2],
color: Highcharts.getOptions().colors[1],
Meteogram.prototype.onChartLoad = function (chart) {
this.drawWeatherSymbols(chart);
this.drawBlocksForWindArrows(chart);
Meteogram.prototype.createChart = function () {
this.chart = new Highcharts.Chart(this.getChartOptions(), chart => {
Meteogram.prototype.error = function () {
document.getElementById('loading').innerHTML =
'<i class="fa fa-frown-o"></i> Failed loading data, please try again ' +
Meteogram.prototype.parseYrData = function () {
this.json.properties.timeseries.forEach((node, i) => {
const x = Date.parse(node.time),
nextHours = node.data.next_1_hours || node.data.next_6_hours,
symbolCode = nextHours && nextHours.summary.symbol_code,
to = node.data.next_1_hours ? x + 36e5 : x + 6 * 36e5;
if (to > pointStart + 48 * 36e5) {
this.symbols.push(nextHours.summary.symbol_code);
y: node.data.instant.details.air_temperature,
symbolName: Meteogram.dictionary[
symbolCode.replace(/_(day|night)$/, '')
this.precipitations.push({
y: nextHours.details.precipitation_amount
value: node.data.instant.details.wind_speed,
direction: node.data.instant.details.wind_from_direction
y: node.data.instant.details.air_pressure_at_sea_level
pointStart = (x + to) / 2;
location.hash = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=51.50853&lon=-0.12574&altitude=25';
const url = location.hash.substr(1);
window.meteogram = new Meteogram(json, 'container');
error: Meteogram.prototype.error,
'Content-Type': 'text/plain'