// Recent Graphs Script
// Mark Crossley
// 2014-10-07 - Added canvas 'tweak' to Highcharts for the Wind Direction scatter graph.
//
/* global Highcharts */
/* eslint-env browser,jquery */
/* exported changeImage */
'use strict';
var chart;
var gRecordAge = '7';
var gRecordUnit = 'day';
// default graph options
var commonOptions = {
chart: {
renderTo: 'graph_container',
type : 'line'
},
credits : {enabled: false},
rangeSelector: {
buttons: [{
count: 6,
type : 'hour',
text : '6h'
}, {
count: 12,
type : 'hour',
text : '12h'
}, {
count: 1,
type : 'day',
text : '24h'
}, {
count: 2,
type : 'day',
text : '48h'
}],
buttonTheme : {'stroke-width': 1},
inputEnabled: false,
selected : 3
},
xAxis: {
type : 'datetime',
maxPadding : 0.005,
minPadding : 0.005,
dateTimeLabelFormats: {
day : '%e %b',
week : '%e %b %y',
month: '%b %y',
year : '%Y'
}
},
legend : {enabled: true},
plotOptions: {
series: {
cursor: 'pointer',
marker: {
enabled: false,
states : {
hover: {
enabled: true,
radius : 5
}
}
}
},
line: {lineWidth: 2}
},
lang: {
loading: ''
}
};
function clone(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (obj === null || typeof obj !== 'object') {
return obj;
}
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) {
copy[attr] = clone(obj[attr]);
}
}
return copy;
}
throw new Error('Unable to copy obj! Its type isn\'t supported.');
}
var getOrd = function (deg) {
var a = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
return a[Math.floor((deg + 22.5) / 45) % 8] + (deg === 0 ? '|calm' : '');
};
var temperature = function () {
// go fetch the data
$.ajax({
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&temp&dew&apptemp&wchill&heatindex&humidex',
datatype: 'json',
success : function (resp) {
chart.hideLoading();
chart.series[0].setData(resp.temp);
chart.series[1].setData(resp.dew);
chart.series[2].setData(resp.apptemp);
chart.series[3].setData(resp.wchill);
chart.series[4].setData(resp.heatindex);
chart.series[5].setData(resp.humidex);
// chart.rangeSelector.clickButton(1, chart.rangeSelector.buttonOptions[1], true); // If you select the default button in options, the buttons are not displayed if the graph is drawn without any data
}
});
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
options.title = {text: 'Les dernières températures'};
options.subtitle = {text: 'Température (°C)'};
options.chart.alignTicks = false;
options.yAxis = [{
// left y axis
title : {text: 'Dernières Températures (°C)'},
opposite: false,
// tickInterval: 5,
// minorTickInterval: 1,
labels : {
align : 'right',
x : -5,
formatter: function () {
return '' + this.value + '';
}
},
plotBands: [{
// visualize sub-zero
from : -200,
to : 0,
color: 'rgba(68, 170, 213, .1)'
}],
plotLines: [{
// visualize zero
value : 0,
color : 'rgb(0, 0, 180)',
width : 1,
zIndex: 2
}]
}, {
// right y axis
linkedTo: 0,
// gridLineWidth: 0,
opposite: true,
title : {
text: null
},
labels: {
align : 'left',
x : 5,
formatter: function () {
return '' + this.value + '';
}
}
}];
options.tooltip = {
shared : true,
crosshairs : true,
valueSuffix : '°C',
valueDecimals: 1
};
options.series = [{
name : 'Température',
color : 'rgba(255,0,0,0.8)',
zIndex : 99, // Force temperature plot to always be on top
showInNavigator: true
}, {
name : 'Point de rosée',
color: 'green'
}, {
name : 'Ressenti',
color: 'rgba(247,163,92,0.8)'
}, {
name : 'Facteur vent',
visible: false
}, {
name : 'Index de chaleur',
color: '#CC5500'
}, {
name : 'Humidex',
type: 'spline',
visible: false,
data: [],
color: '#F7F051',
}];
// draw the chart
chart = new Highcharts.StockChart(options);
chart.showLoading();
};
var pressure = function () {
// go fetch the data
$.ajax({
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&press',
datatype: 'json',
success : function (resp) {
// var chart = $('#container').highcharts();
chart.hideLoading();
chart.series[0].setData(resp.press);
// chart.rangeSelector.clickButton(1, chart.rangeSelector.buttonOptions[1], true); // If you select the default button in options, the buttons are not displayed if the graph is drawn without any data
}
});
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
options.title = {text: 'Pression atmosphérique'};
options.subtitle = {text: 'Pression (hPa)'};
options.chart.alignTicks = false;
options.yAxis = [{
// left y axis
title : {text: 'Pression (hPa)'},
minRange: 5,
opposite: false,
labels : {
align : 'right',
x : -5,
formatter: function () {
return parseInt(this.value, 10);
}
}
}, {
// right y axis
linkedTo : 0,
gridLineWidth: 0,
opposite : true,
title : {text: null},
minRange : 5,
labels : {
align : 'left',
x : 5,
formatter: function () {
return parseInt(this.value, 10);
}
}
}];
options.tooltip = {
shared : true,
crosshairs : true,
valueSuffix : ' hPa',
valueDecimals: 1,
formatter : function () {
return '' + Highcharts.dateFormat('%a, %b %e, %H:%M', this.x) + '
' +
'' + this.points[0].series.name + ': ' +
' ' + Highcharts.numberFormat(this.y, 1, '.', '') + ' hPa ';
}
};
options.series = [{
name : 'Pression',
showInNavigator: true
}];
// Create the chart
// $('#container').highcharts('StockChart', options);
chart = new Highcharts.StockChart(options);
chart.showLoading();
};
var wind = function () {
// go fetch the data
$.ajax({
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&wspeed&wgust',
datatype: 'json',
success : function (resp) {
chart.hideLoading();
chart.series[0].setData(resp.wspeed);
chart.series[1].setData(resp.wgust);
// chart.rangeSelector.clickButton(1, chart.rangeSelector.buttonOptions[1], true); // If you select the default button in options, the buttons are not displayed if the graph is drawn without any data
}
});
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
options.title = {text: 'Dernier Vent'};
options.subtitle = {text: 'Vitesse du vent (kmh)'};
options.yAxis = [{
// left y axis
title : {text: 'Vitesse du vent (kmh)'},
opposite: false,
labels : {
align : 'right',
x : -5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
}
},
min: 0
}, {
// right y axis
linkedTo : 0,
gridLineWidth: 0,
opposite : true,
title : {text: null},
labels : {
align : 'left',
x : 5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
}
}
}];
options.tooltip = {
shared : true,
crosshairs : true,
valueSuffix: ' kmh'
};
options.series = [{
name : 'Vitesse moy',
step : true,
showInNavigator: false
}, {
name : 'Rafale',
step : true,
color : 'rgba(255,0,0,0.8)',
showInNavigator: true
}];
// draw the chart
chart = new Highcharts.StockChart(options);
chart.showLoading();
};
var windDir = function () {
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
var gustScale = 1.7; // Used to scale up the gust speed 'sausage' so it is more visible
// Use your ( / 45 * 2) for a max possible 'sausage width of 180 degrees
var speed = []; // array to hold the wind speed for the tooltip
options.title = {text: 'Direction du vent et vitesse'};
options.subtitle = {text: 'Un gros trait = vent fort!'};
options.navigator = {
series: {
// Pseudo scatter - line plot without a line!
type : 'line',
color : '#4572A7',
dataGrouping: {
groupPixelWidth: 1,
smoothed : true
},
lineWidth: 0,
marker : {
// enable the marker to simulate a scatter
enabled: true,
radius : 1
}
}
};
options.xAxis = {
type : 'datetime',
maxPadding : 0.005,
minPadding : 0.005,
labels : {align: 'left'},
dateTimeLabelFormats: {
day : '%e %b',
week : '%e %b %y',
month: '%b %y',
year : '%Y'
}
};
options.yAxis = [{
// left y axis
title : {text: null},
opposite: false,
labels : {
align : 'right',
x : -5,
formatter: function () {
return getOrd(this.value);
}
},
min : 0,
max : 360,
// maxPadding: 0.05,
// minPadding: 0.05,
tickInterval : 45,
tickAmount : 9,
minorTickInterval: null,
plotBands : [{
color: '#E8E8FF',
from : 0,
to : 22.5
}, {
color: '#E8E8FF',
from : 67.5,
to : 112.5
}, {
color: '#E8E8FF',
from : 157.5,
to : 202.5
}, {
color: '#E8E8FF',
from : 247.5,
to : 292.5
}, {
color: '#E8E8FF',
from : 337.5,
to : 360
}]
}, {
// right y axis
linkedTo : 0,
gridLineWidth: 0,
opposite : true,
title : {text: null},
labels : {
align : 'left',
x : 5,
formatter: function () {
return getOrd(this.value);
}
},
// maxPadding: 0.05,
// minPadding: 0.05,
tickInterval : 45,
tickAmount : 9,
minorTickInterval: null
}];
options.tooltip = {
enabled: true,
shared : false
};
options.plotOptions = {
series: {
animation: false,
shadow : false,
},
arearange: {
cursor: 'pointer',
marker: {
states: {
hover : {enabled: false},
select: {enabled: false}
}
},
},
scatter: {enableMouseTracking: true}
};
options.series = [{
// Pseudo scatter - line plot without a line!
name : 'Moy. Dir',
type : 'line',
lineWidth: 0,
color : 'rgba(200,20,20,.9)',
marker : {
// Enable marker to simulate scatter
enabled: true,
symbol : 'square',
radius : 2
},
states: {
hover: {lineWidthPlus: 0}
},
data : [],
showInNavigator: true,
zIndex : 10,
tooltip : {
pointFormatter: function () {
return '\u25CF ' +
this.series.name + ': ' + (this.y == 0 ? 'calm' : this.y + ' Degr') + '
';
}
},
threshold : 1,
negativeColor: 'rgba(20,20,20,.25)'
}, {
name : 'Rafale',
type : 'arearange',
color : 'rgba(20,20,150,.2)',
fillOpacity: 0.15,
visible : true,
data : [],
zIndex : 0,
tooltip : {
pointFormatter: function () {
return '\u25CF ' + this.series.name + ': ' +
speed[this.index] + ' kmh
';
}
}
}, {
name : 'Speed2',
type : 'arearange',
color : 'rgba(20,20,150,.2)',
fillOpacity : 0.15,
visible : true,
data : [],
zIndex : 1,
linkedTo : 1,
enableMouseTracking: false
}, {
name : 'Speed3',
type : 'arearange',
color : 'rgba(20,20,150,.2)',
fillOpacity : 0.15,
visible : true,
data : [],
zIndex : 2,
linkedTo : 1,
enableMouseTracking: false
}];
// draw the chart
chart = new Highcharts.StockChart(options);
chart.animation = false;
chart.showLoading();
// go fetch the data
$.ajax({
//url : ../'utils/realtimeLogSql.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&avgbearing&wspeed',
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&avgbearing&wgust',
datatype: 'json',
success : function (resp) {
var vel = [];
var velLo = [];
var velHi = [];
for (var i = 0; i < resp.avgbearing.length; i++) {
vel[i] = [];
velLo[i] = [];
velHi[i] = [];
vel[i][0] = resp.avgbearing[i][0];
velLo[i][0] = resp.avgbearing[i][0];
velHi[i][0] = resp.avgbearing[i][0];
speed[i] = resp.wgust[i][1];
if (resp.avgbearing[i][1] == 0) {
// make the data null if the windspeed is zero - so we get a disconituous plot
vel[i][1] = null;
vel[i][2] = null;
velLo[i][1] = null;
velLo[i][2] = null;
velHi[i][1] = null;
velHi[i][2] = null;
// don't display anything for calm?
//resp.avgbearing[i][1] = null;
//resp.avgbearing[i][2] = null;
} else {
// scale up the gust speed by a factor of 5
//vel[i][1] = resp.avgbearing[i][1] - (resp.wspeed[i][1] * gustScale);
//vel[i][2] = resp.avgbearing[i][1] + (resp.wspeed[i][1] * gustScale);
vel[i][1] = resp.avgbearing[i][1] - (resp.wgust[i][1] * gustScale);
vel[i][2] = resp.avgbearing[i][1] + (resp.wgust[i][1] * gustScale);
if (vel[i][2] > 359) {
// Ooops, sausage over the top - wrap around to the bottom
velLo[i][1] = 0;
velLo[i][2] = vel[i][2] - 360;
// and hide the top
velHi[i][1] = 361;
velHi[i][2] = 361;
} else if (vel[i][2] < 1) {
// Ooops, sausage below the bottom - wrap around to the top
velHi[i][2] = 360;
velHi[i][1] = vel[i][2] + 360;
// and hide the bottom
velLo[i][1] = -1;
velLo[i][2] = -1;
} else {
// all the sausage is visible, hide the top/bottom plots
velLo[i][1] = -1;
velLo[i][2] = -1;
velHi[i][1] = 361;
velHi[i][2] = 361;
}
}
}
chart.hideLoading();
chart.series[0].setData(resp.avgbearing);
chart.series[1].setData(vel);
chart.series[2].setData(velLo);
chart.series[3].setData(velHi);
}
});
};
var humidity = function () {
// go fetch the data
$.ajax({
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&inhum&hum',
datatype: 'json',
success : function (resp) {
chart.hideLoading();
chart.series[0].setData(resp.hum);
chart.series[1].setData(resp.inhum);
// chart.rangeSelector.clickButton(1, chart.rangeSelector.buttonOptions[1], true); // If you select the default button in options, the buttons are not displayed if the graph is drawn without any data
}
});
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
options.title = {text: 'Humidité'};
options.subtitle = {text: 'Relative humidité (%)'};
options.yAxis = [{
// left y axis
min : 0,
max : 100,
title : {text: 'Relative Humidité (%)'},
gridLineWidth: 0,
opposite : false,
labels : {
align : 'right',
x : -5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
}
},
plotBands: [{
from : 0,
to : 20,
color: 'rgba(255, 220, 0, .15)'
}, {
from : 20,
to : 80,
color: 'rgba(20, 255, 20, .1)'
}, {
from : 80,
to : 90,
color: 'rgba(234, 207, 30, .15)'
}, {
from : 90,
to : 100,
color: 'rgba(240, 50, 0, .1)'
}]
}, {
// right y axis
linkedTo : 0,
gridLineWidth: 0,
opposite : true,
title : {text: null},
labels : {
align : 'left',
x : 5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
}
}
}];
options.tooltip = {
shared : true,
valueSuffix: '%'
};
options.series = [{
name : 'Humidité',
color : 'rgba(255,0,0,0.8)',
showInNavigator: true,
}];
// draw the chart
chart = new Highcharts.StockChart(options);
chart.showLoading();
};
var rain = function () {
// go fetch the data
$.ajax({
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&rfall&rrate',
datatype: 'json',
success : function (resp) {
chart.hideLoading();
chart.series[0].setData(resp.rfall);
chart.series[1].setData(resp.rrate);
// chart.rangeSelector.clickButton(1, chart.rangeSelector.buttonOptions[1], true); // If you select the default button in options, the buttons are not displayed if the graph is drawn without any dat
}
});
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
options.title = {text: 'Pluie'};
options.subtitle = {text: 'Pluie (mm) & Intensité (mm/h)'};
options.yAxis = [{
// left y axis
min : 0,
minRange: 2,
title : {
text : 'Intensité (mm/h)',
style: {color: 'rgba(255,100,100,1)'}
},
opposite: false,
labels : {
align : 'right',
x : -5,
formatter: function () {
return Highcharts.numberFormat(this.value, 1);
}
}
}, {
// right y axis
min : 0,
gridLineWidth: 0,
minRange : 2,
opposite : true,
title : {
text : 'Pluie (mm)',
style: {color: 'rgba(100,200,255,1)'}
},
labels: {
align : 'left',
x : 5,
formatter: function () {
return Highcharts.numberFormat(this.value, 1);
}
}
}];
options.tooltip = {
shared : true,
crosshairs : true,
valueDecimals: 1
};
options.series = [{
name : 'Pluie jour',
// data: resp.rfall,
type : 'area',
yAxis : 1,
tooltip : {valueSuffix: ' mm'},
zIndex : 10,
color : 'rgba(100,200,255,0.8)',
fillColor: {
linearGradient: {x1: 0, y1: 0, x2: 0, y2: 1},
stops : [
[0, 'rgba(10,80,255,0.6)'],
[1, 'rgba(10,150,50,0.1)']
]
},
showInNavigator: true
}, {
name : 'Intensité',
// data: resp.rrate,
yAxis : 0,
type : 'line',
zIndex : 5,
tooltip: {valueSuffix: ' mm/h'},
color : 'rgba(255,100,100,0.8)'
}];
// draw the chart
chart = new Highcharts.StockChart(options);
chart.showLoading();
};
var solar = function () {
// go fetch the data
$.ajax({
url : '../utils/realtimeLogSql1.php?recordAge=' + gRecordAge + '&recordUnit=' + gRecordUnit + '&CurrentSolarMax&SolarRad&UV',
datatype: 'json',
success : function (resp) {
var i = 0;
resp.percent = [];
for (; i < resp.SolarRad.length; i++) {
resp.percent[i] = [];
resp.percent[i][0] = resp.SolarRad[i][0];
// ignore values when theoretical < 30, and cap at a maximum of 150%
resp.percent[i][1] = (resp.CurrentSolarMax[i][1] < 30 ?
0 :
Math.round(Math.min(resp.SolarRad[i][1] / resp.CurrentSolarMax[i][1] * 100, 150) * 10) / 10);
}
chart.hideLoading();
chart.series[0].setData(resp.CurrentSolarMax);
chart.series[1].setData(resp.SolarRad);
chart.series[2].setData(resp.UV);
chart.series[3].setData(resp.percent);
chart.series[4].setData(resp.UV_AVG);
// chart.rangeSelector.clickButton(1, chart.rangeSelector.buttonOptions[1], true); // If you select the default button in options, the buttons are not displayed if the graph is drawn without any data
}
});
// whilst we wait for the data, start to draw the chart
// first define the options
var options = clone(commonOptions);
options.title = {text: 'Solaire information'};
options.subtitle = {text: 'UV index & Radiation solaire (W/m\u00B2)'};
options.yAxis = [{
// left y axis - UV Index
title: {
text: 'UV Index'
},
opposite: false,
labels : {
align : 'right',
x : -5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
}
},
showEmpty : false,
min : 0,
minRange : 4,
minPadding: 0
// maxPadding: 0
}, {
// right y axis - Solar Rad W/m2
gridLineWidth: 0,
showEmpty : false,
opposite : true,
title : {text: 'Radiation Solaire (W/m\u00B2)'},
labels : {
align : 'left',
x : 5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0, '.', '');
}
},
min: 0
// max: 1000
}, {
// left y axis #2- Percentage of max
title : {text: 'Solar % of theoretical'},
labels: {
align : 'left',
x : 5,
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
}
},
showEmpty : false,
min : 0,
// minRange: 10,
minPadding: 0,
// max: 100,
// maxPadding: 0,
plotLines : [{
value : 75,
color : '#CC2000',
width : 1,
zIndex: 2
}]
}];
options.tooltip = {
shared : true,
crosshairs: true
};
options.series = [{
name : 'Théorique Max',
// data: resp.CurrentSolarMax,
yAxis : 1,
type : 'area',
color : 'rgba(100,100,255,0.4)',
fillColor: 'rgba(100,100,255,0.25)',
tooltip : {
valueSuffix: ' W/m\u00B2'
},
showInNavigator: true
}, {
name : 'Radiation solaire',
// data: resp.SolarRad,
yAxis : 1,
type : 'area',
color : 'rgba(255,80,10,0.8)',
lineWidth: 1,
fillColor: {
linearGradient: {x1: 0, y1: 0, x2: 0, y2: 1},
stops : [
[0, 'rgba(255,80,10,0.4)'],
[1, 'rgba(150,0,0,0.3)']
]
},
tooltip: {
pointFormatter: function () {
return '\u25CF' +
this.series.name + ': ' + Highcharts.numberFormat(this.y, 0, '.', '') + ' W/m\u00B2
';
}
},
showInNavigator: true
}, {
name : 'UV Index',
// data: resp.UV,
yAxis : 0,
// color: 'rgba(255,0,0,0.8)',
visible: true,
tooltip: {valueDecimals: 1}
}, {
name : 'Solaire %',
// data: resp.percent,
yAxis : 2,
visible: false,
tooltip: {
valueSuffix : '%',
valueDecimals: 1
}
}, {
name : 'UV 10 min moy.',
// data: resp.UV_AVG,
yAxis : 0,
// color: 'rgba(255,0,0,0.8)',
visible: false,
tooltip: {valueDecimals: 1}
}];
// draw the chart
chart = new Highcharts.StockChart(options);
chart.showLoading();
};
window.changeImage = function (im) {
$(im).siblings().removeClass('picked');
$(im).addClass('picked');
switch ($(im).attr('data-id')) {
case 'temp':
temperature();
break;
case 'press':
pressure();
break;
case 'wind':
wind();
break;
case 'wdir':
windDir();
break;
case 'rain':
rain();
break;
case 'hum':
humidity();
break;
case 'solar':
solar();
break;
}
};
$(document).ready(function () {
temperature();
});