346 lines
8.7 KiB
JavaScript
346 lines
8.7 KiB
JavaScript
/**
|
|
* Gather graph-related functions
|
|
* @param unit: (optional) Graphe unit
|
|
* @param max_value: (optional) Defautl graph max_value
|
|
*/
|
|
var Graph = function(unit, max_value) {
|
|
var api = {};
|
|
|
|
var graph = document.getElementById('graph')
|
|
, graph_vertical_axis = document.getElementById('graph_vertical_axis')
|
|
, graph_values = document.getElementById('graph_values')
|
|
, graph_loading = document.getElementById('graph_loading')
|
|
, now = document.getElementById('now')
|
|
, now_label = document.getElementById('now_label')
|
|
, sum, n_values, mean
|
|
;
|
|
|
|
/**
|
|
* Function used to convert values received from server
|
|
*/
|
|
api.convertValue = function(v){ return v; };
|
|
|
|
api.unit = unit || 'W';
|
|
api.type = 'energy';
|
|
api.rect_width = Config.rect_width;
|
|
api.rect_margin = Config.rect_margin;
|
|
api.autoremove = true;
|
|
api.max_value = max_value || 1e-6;
|
|
|
|
/**
|
|
* Set color class name from height (between 0.0 and 1.0)
|
|
*/
|
|
api.colorize = function(t) {
|
|
return (t > 33.3 ? (t >= 66.7 ? 'red' : 'orange') : 'yellow');
|
|
}
|
|
|
|
/**
|
|
* Round value according to max value
|
|
*/
|
|
api.round = function(v) {
|
|
return Math.round(v * 10) / 10;
|
|
}
|
|
|
|
/**
|
|
* Init graph
|
|
*/
|
|
api.init = function() {
|
|
n_values = 0;
|
|
|
|
var graduations = [0.00, 0.33, 0.66, 1.00]; // Graduation positions (relative)
|
|
graduations.map(function (t) {
|
|
api.addVerticalGraduation(t)
|
|
});
|
|
|
|
return api;
|
|
}
|
|
|
|
/**
|
|
* Set value disaplyed in overview
|
|
* @param power: value to display
|
|
*/
|
|
api.setOverview = function(power) {
|
|
if (power === null) {
|
|
now.innerHTML = ' ';
|
|
return;
|
|
}
|
|
if (api.unit == 'cents/min') power = power / 8 * 60 * 100;
|
|
now.innerHTML = api.round(power) + (api.unit == 'cents/min' ? ' centimes par minute' : api.unit);
|
|
var height = power / api.max_value * 100;
|
|
now.className = 'blurry ' + api.colorize(height);
|
|
};
|
|
|
|
/**
|
|
* Set label under overview field.
|
|
* @pram label: new label
|
|
*/
|
|
api.setOverviewLabel = function(label) {
|
|
now_label.innerHTML = label;
|
|
};
|
|
|
|
|
|
/**
|
|
* Add a new rect to the graph.
|
|
* @param power: Power represented by the rect.
|
|
* @param animated: (optional) Whether the addition of the value must be animated. Default to True
|
|
* @param legend: (optional) Legend to add to the rect
|
|
*/
|
|
api.addRect = function(power, animated, legend) {
|
|
if (animated === undefined) animated = true;
|
|
var defined = true;
|
|
if (power === undefined) {
|
|
defined = false;
|
|
power = 0;
|
|
}
|
|
|
|
if (unit == 'cents/min') {
|
|
power = power / 8 * 60 * 100;
|
|
}
|
|
|
|
if (power > api.max_value) {
|
|
api.scaleVertically(power / api.max_value);
|
|
}
|
|
|
|
var div = document.createElement('a');
|
|
div.setAttribute('href', location.hash); // TODO
|
|
graph_values.appendChild(div);
|
|
|
|
div.className = 'rect';
|
|
if (!defined) div.className += ' undefined';
|
|
if (animated) div.className += ' animated';
|
|
div.className += ' ' + api.type;
|
|
|
|
var info = document.createElement('div');
|
|
div.appendChild(info);
|
|
|
|
info.className = 'rect-info';
|
|
if (defined) info.innerHTML = api.round(power) + api.unit;
|
|
else info.innerHTML = '<em>Pas de donnée</em>';
|
|
if (legend) info.innerHTML += '<br/>' + legend;
|
|
|
|
var color = document.createElement('div');
|
|
div.appendChild(color);
|
|
|
|
var height = api.round(power) / api.max_value * 100;
|
|
var color_class = api.colorize(height);
|
|
|
|
color.className = 'rect-color ' + color_class + '-day';
|
|
color.style.height = height + '%';
|
|
|
|
|
|
++n_values;
|
|
|
|
var max_values = api.getWidth();
|
|
// Le +10 c'est pour prendre de la marge. On ne peut pas mettre
|
|
// simplement 1 sinon ça se voit lorsque plusieurs nouvelles mesures
|
|
// arrivent en même temps.
|
|
if (api.autoremove && n_values > max_values + 10) {
|
|
/*
|
|
graph_values.firstChild.style.width = '0';
|
|
graph_values.firstChild.addEventListener('transitionend', function(){
|
|
graph_values.removeChild(this);
|
|
}, false);
|
|
*/
|
|
graph_values.removeChild(graph_values.firstChild)
|
|
}
|
|
|
|
div.style.width = api.rect_width + 'px';
|
|
|
|
|
|
return api;
|
|
};
|
|
|
|
/**
|
|
* Remove last rect from graph
|
|
* @return api;
|
|
*/
|
|
api.removeRect = function() {
|
|
if (graph_values.lastChild)
|
|
graph_values.removeChild(graph_values.lastChild);
|
|
|
|
return api;
|
|
};
|
|
|
|
/**
|
|
* Add an horizontal graduation line (so a graduation for the vertical axis)
|
|
* @param pos: Relative position at which the graduation is placed
|
|
*/
|
|
api.addVerticalGraduation = function(pos) {
|
|
var height = pos * 100;
|
|
var span = document.createElement('span');
|
|
graph_vertical_axis.appendChild(span);
|
|
|
|
span.style.bottom = height + '%';
|
|
span.setAttribute('cw-graduation-position', pos);
|
|
api.updateVerticalGraduation(span);
|
|
|
|
return api;
|
|
}
|
|
|
|
/**
|
|
* Add an horizontal absolute graduation line
|
|
* @param pos: Absolute position at which the graduation is placed
|
|
*/
|
|
api.addAbsoluteVerticalGraduation = function(pos) {
|
|
if (pos * 1.1 > api.max_value) {
|
|
api.scaleVertically(pos * 1.1 / api.max_value);
|
|
}
|
|
|
|
var height = pos / api.max_value * 100;
|
|
var span = document.createElement('span');
|
|
var hr_id = rand64(5);
|
|
graph_vertical_axis.appendChild(span);
|
|
|
|
span.style.bottom = height + '%';
|
|
span.setAttribute('cw-absolute-graduation-position', pos);
|
|
span.setAttribute('cw-absolute-graduation-hr', hr_id);
|
|
|
|
var hr = document.createElement('hr');
|
|
hr.style.bottom = height + '%';
|
|
hr.id = hr_id;
|
|
hr.className = 'absolute-graduation-hr';
|
|
graph.appendChild(hr);
|
|
|
|
api.updateVerticalGraduation(span);
|
|
|
|
return api;
|
|
}
|
|
|
|
/**
|
|
* Update displayed value of vertical graduation
|
|
* @param graduation: graduation to resize
|
|
*/
|
|
api.updateVerticalGraduation = function(graduation) {
|
|
if (graduation.getAttribute('cw-graduation-position') !== null) {
|
|
var power = api.round(graduation.getAttribute('cw-graduation-position') * api.max_value);
|
|
graduation.innerHTML = power + api.unit;
|
|
}
|
|
if (graduation.getAttribute('cw-absolute-graduation-position') !== null) {
|
|
var pos = graduation.getAttribute('cw-absolute-graduation-position');
|
|
var hr_id = graduation.getAttribute('cw-absolute-graduation-hr');
|
|
var hr = document.getElementById(hr_id);
|
|
hr.style.bottom = graduation.style.bottom = (pos / api.max_value * 100) + '%';
|
|
var power = api.round(pos);
|
|
graduation.innerHTML = power + api.unit;
|
|
}
|
|
return api;
|
|
};
|
|
|
|
/**
|
|
* Change single rect vertical scale without modifying the value it represents.
|
|
* @param rect: rect to resize
|
|
* @param ratio: Value by which multiply the rect vertical scale
|
|
*/
|
|
api.scaleRect = function(rect, ratio) {
|
|
var color = rect.getElementsByClassName('rect-color')[0];
|
|
height = parseInt(color.style.height.slice(0, -1));
|
|
new_height = height / ratio;
|
|
color.style.height = new_height + '%';
|
|
|
|
var color_class = api.colorize(new_height);
|
|
color.className = color.className.replace(/[^ ]*-day/, color_class + '-day');
|
|
return api;
|
|
};
|
|
|
|
/**
|
|
* Change graph vertical scale
|
|
* @param ratio: Value by which multiply the graph vertical scale
|
|
*/
|
|
api.scaleVertically = function(ratio) {
|
|
api.max_value = api.max_value * ratio;
|
|
|
|
var rects = graph_values.children;
|
|
for (var i = 0 ; i < rects.length ; i++) {
|
|
api.scaleRect(rects[i], ratio);
|
|
}
|
|
var graduations = graph_vertical_axis.children;
|
|
for (var i = 0 ; i < graduations.length ; i++) {
|
|
api.updateVerticalGraduation(graduations[i]);
|
|
}
|
|
return api;
|
|
};
|
|
|
|
|
|
/**
|
|
* @return the width of the graph in pixels
|
|
*/
|
|
api.getPixelWidth = function() {
|
|
return graph.clientWidth;
|
|
};
|
|
|
|
/**
|
|
* @return the width of the graph in number of values that can be displayed
|
|
*/
|
|
api.getWidth = function() {
|
|
return Math.floor(api.getPixelWidth() / (api.rect_width + api.rect_margin));
|
|
};
|
|
|
|
/**
|
|
* Clean graph (remove all values)
|
|
*/
|
|
api.clean = function() {
|
|
while (graph_values.firstChild)
|
|
graph_values.removeChild(graph_values.firstChild);
|
|
while (graph_vertical_axis.firstChild)
|
|
graph_vertical_axis.removeChild(graph_vertical_axis.firstChild);
|
|
|
|
var hr;
|
|
while (hr = document.getElementsByClassName('absolute-graduation-hr')[0])
|
|
hr.parentNode.removeChild(hr);
|
|
}
|
|
|
|
/**
|
|
* Hide loading icon
|
|
*/
|
|
api.stopLoading = function() {
|
|
graph_loading.style.visibility = 'hidden';
|
|
}
|
|
|
|
/**
|
|
* Hide loading icon
|
|
*/
|
|
api.startLoading = function() {
|
|
graph_loading.style.visibility = 'visible';
|
|
}
|
|
|
|
|
|
/**
|
|
* Return a human readable legend
|
|
* @param mode: 'now', 'day', 'week', 'month'
|
|
* @param date: view date
|
|
* @param i: index
|
|
* [Static]
|
|
*/
|
|
api.getLegend = function(mode, date, i) {
|
|
switch(mode) {
|
|
case 'now':
|
|
return '';
|
|
|
|
case 'day':
|
|
return i + 'h - ' + (i+1) + 'h';
|
|
|
|
case 'week':
|
|
return dateutils.getStringDay(i);
|
|
|
|
case 'month':
|
|
return i + ' ' + dateutils.getStringMonth(date);
|
|
}
|
|
};
|
|
|
|
return api;
|
|
};
|
|
|
|
|
|
var PriceGraph = function(unit) {
|
|
var api = Graph(unit);
|
|
|
|
api.type = 'price';
|
|
|
|
api.colorize = function(t) {
|
|
return (t > 33.3 ? (t >= 66.7 ? 'dark-blue' : 'blue') : 'light-blue');
|
|
}
|
|
|
|
return api;
|
|
};
|
|
|