mirror of
https://github.com/beestat/app.git
synced 2025-06-04 22:27:27 -04:00
Added "More Info" temperature profiles modal with trendline formulas
Fixed for °C Hope all you Canadians and Australians are happy now.
This commit is contained in:
parent
b47debf3cc
commit
887f252e2b
41
js/beestat/math.js
Normal file
41
js/beestat/math.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
beestat.math = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a linear trendline from a set of data.
|
||||||
|
*
|
||||||
|
* @param {Object} data The data; at least two points required.
|
||||||
|
*
|
||||||
|
* @return {Object} The slope and intercept of the trendline.
|
||||||
|
*/
|
||||||
|
beestat.math.get_linear_trendline = function(data) {
|
||||||
|
// Requires at least two points.
|
||||||
|
if (Object.keys(data).length < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum_x = 0;
|
||||||
|
var sum_y = 0;
|
||||||
|
var sum_xy = 0;
|
||||||
|
var sum_x_squared = 0;
|
||||||
|
var n = 0;
|
||||||
|
|
||||||
|
for (var x in data) {
|
||||||
|
x = parseFloat(x);
|
||||||
|
var y = parseFloat(data[x]);
|
||||||
|
|
||||||
|
sum_x += x;
|
||||||
|
sum_y += y;
|
||||||
|
sum_xy += (x * y);
|
||||||
|
sum_x_squared += Math.pow(x, 2);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var slope = ((n * sum_xy) - (sum_x * sum_y)) /
|
||||||
|
((n * sum_x_squared) - (Math.pow(sum_x, 2)));
|
||||||
|
var intercept = ((sum_y) - (slope * sum_x)) / (n);
|
||||||
|
|
||||||
|
return {
|
||||||
|
'slope': slope,
|
||||||
|
'intercept': intercept
|
||||||
|
};
|
||||||
|
};
|
@ -138,7 +138,7 @@ beestat.component.card.temperature_profiles.prototype.get_data_ = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
profile.deltas = deltas_converted;
|
profile.deltas = deltas_converted;
|
||||||
var linear_trendline = this.get_linear_trendline_(profile.deltas);
|
var linear_trendline = beestat.math.get_linear_trendline(profile.deltas);
|
||||||
|
|
||||||
var min_max_keys = Object.keys(profile.deltas);
|
var min_max_keys = Object.keys(profile.deltas);
|
||||||
|
|
||||||
@ -215,49 +215,6 @@ beestat.component.card.temperature_profiles.prototype.get_data_ = function() {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a linear trendline from a set of data.
|
|
||||||
*
|
|
||||||
* IMPORTANT: This exists in the profile already but it's wrong to use it
|
|
||||||
* directly as it's not right for Celsius.
|
|
||||||
*
|
|
||||||
* @param {Object} data The data; at least two points required.
|
|
||||||
*
|
|
||||||
* @return {Object} The slope and intercept of the trendline.
|
|
||||||
*/
|
|
||||||
beestat.component.card.temperature_profiles.prototype.get_linear_trendline_ = function(data) {
|
|
||||||
// Requires at least two points.
|
|
||||||
if (Object.keys(data).length < 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sum_x = 0;
|
|
||||||
var sum_y = 0;
|
|
||||||
var sum_xy = 0;
|
|
||||||
var sum_x_squared = 0;
|
|
||||||
var n = 0;
|
|
||||||
|
|
||||||
for (var x in data) {
|
|
||||||
x = parseFloat(x);
|
|
||||||
var y = parseFloat(data[x]);
|
|
||||||
|
|
||||||
sum_x += x;
|
|
||||||
sum_y += y;
|
|
||||||
sum_xy += (x * y);
|
|
||||||
sum_x_squared += Math.pow(x, 2);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var slope = ((n * sum_xy) - (sum_x * sum_y)) /
|
|
||||||
((n * sum_x_squared) - (Math.pow(sum_x, 2)));
|
|
||||||
var intercept = ((sum_y) - (slope * sum_x)) / (n);
|
|
||||||
|
|
||||||
return {
|
|
||||||
'slope': slope,
|
|
||||||
'intercept': intercept
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the title of the card.
|
* Get the title of the card.
|
||||||
*
|
*
|
||||||
|
@ -29,13 +29,29 @@ beestat.component.modal.temperature_profiles_info.prototype.decorate_contents_ =
|
|||||||
'resist'
|
'resist'
|
||||||
].forEach(function(type) {
|
].forEach(function(type) {
|
||||||
if (thermostat.profile.temperature[type] !== null) {
|
if (thermostat.profile.temperature[type] !== null) {
|
||||||
|
const profile = thermostat.profile.temperature[type];
|
||||||
|
|
||||||
|
// Convert the data to Celsius if necessary
|
||||||
|
const deltas_converted = {};
|
||||||
|
for (let key in profile.deltas) {
|
||||||
|
deltas_converted[beestat.temperature({'temperature': key})] =
|
||||||
|
beestat.temperature({
|
||||||
|
'temperature': (profile.deltas[key]),
|
||||||
|
'delta': true,
|
||||||
|
'round': 3
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.deltas = deltas_converted;
|
||||||
|
const linear_trendline = beestat.math.get_linear_trendline(profile.deltas);
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
'name': beestat.series['indoor_' + type + '_delta'].name,
|
'name': beestat.series['indoor_' + type + '_delta'].name,
|
||||||
'value':
|
'value':
|
||||||
'Slope = ' +
|
'Slope = ' +
|
||||||
thermostat.profile.temperature[type].linear_trendline.slope +
|
linear_trendline.slope.toFixed(4) +
|
||||||
'<br/>Intercept = ' +
|
'<br/>Intercept = ' +
|
||||||
thermostat.profile.temperature[type].linear_trendline.intercept
|
linear_trendline.intercept.toFixed(4) + beestat.setting('units.temperature')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -49,6 +49,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
|
|||||||
echo '<script src="/js/beestat/address.js"></script>' . PHP_EOL;
|
echo '<script src="/js/beestat/address.js"></script>' . PHP_EOL;
|
||||||
echo '<script src="/js/beestat/affiliate.js"></script>' . PHP_EOL;
|
echo '<script src="/js/beestat/affiliate.js"></script>' . PHP_EOL;
|
||||||
echo '<script src="/js/beestat/date.js"></script>' . PHP_EOL;
|
echo '<script src="/js/beestat/date.js"></script>' . PHP_EOL;
|
||||||
|
echo '<script src="/js/beestat/math.js"></script>' . PHP_EOL;
|
||||||
|
|
||||||
// Layer
|
// Layer
|
||||||
echo '<script src="/js/layer.js"></script>' . PHP_EOL;
|
echo '<script src="/js/layer.js"></script>' . PHP_EOL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user