Zusammenlegung
- Die sechs Endpunkte getConsData_/getProdData_{month,year,decade}.php sind
ajax/energyHistory.php?series=&range= gewichen, der gemeinsame Aufbau der
Chart-Daten steht in ajax/chartData.php. Die erzeugte SQL wurde gegen alle
sechs Originale abgeglichen.
- Die 13 Raeume der Home-Ansicht stehen nur noch in restricted/rooms.php.
home.php rendert die SVG-Kacheln daraus, homeMQTT.js bekommt dieselbe
Tabelle als JSON (346 -> 222 bzw. 428 -> 197 Zeilen).
- Gemeinsame JS-Helfer in js/solar/common.js; geteilte Bausteine fuer
Wetterkacheln, Chart-Skripte und das Formular der Ladesteuerung.
- Seitenvorlagen sind jetzt .php und werden eingebunden, statt per
file_get_contents zusammengesetzt zu werden.
Fehlerbehebungen
- ?action=weather fuehrte auf eine leere Seite, es gibt jetzt weather.php.
- homeMQTT.js griff auf ein #meteogram zu, das home.php nie hatte, und brach
damit den readystatechange-Handler ab.
- Die Heizungsseite abonnierte weatherStation/#, zeigte die Werte aber nie an.
Ladelast
- Chart.js, MQTT und Meteogramm werden nur noch auf den Seiten geladen, die
sie brauchen; die Seitentabelle dafuer steht in index.php.
- mqtt.js durch die minifizierte Fassung ersetzt (859 -> 359 KB). MQTT.js
5.14.1, byte-identisch mit dem signierten npm-Tarball.
- Rund 3,1 MB ungenutzte Vendor-Reste und AdminLTE-Demobilder entfernt.
- Solar 1796 -> 1240 KB, Home 1796 -> 873 KB, Historie 1796 -> 843 KB.
Speicher im Browser
- Chart.defaults.devicePixelRatio auf 1.5 gedeckelt. Die Zeichenpuffer der
Diagramme waren mit 20-45 MB der groesste Posten der Seite.
- Das Meteogramm-iframe laedt erst beim Hinscrollen.
Realtime-SVG
- Filterbereiche auf das noetige Mass verkleinert und den wirkungslosen
feOffset-Durchgang entfernt: 60 % weniger gerasterte Filterflaeche bei
pixelgleichem Ergebnis.
- Die Fluss-Animation laeuft ueber transform statt stroke-dashoffset, mit
Punkten statt Strichmuster; sie ruht, wo kein Fluss anliegt.
- Der Wertupdate schreibt nur noch bei echter Aenderung und benutzt
textContent statt innerHTML: 9 statt 86 Elemente pro Update, davon keines
mit Filter. describeArc rundet auf volle Grad.
- waterInfo auf scale(0.90) wie die uebrigen Info-Gruppen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
153 lines
4.9 KiB
JavaScript
153 lines
4.9 KiB
JavaScript
tooltipLabel = function (context) {
|
||
let label = context.dataset.label || '';
|
||
if (label) {
|
||
label += ': ';
|
||
}
|
||
if (context.dataset.yAxisID == "y1") {
|
||
label += Math.round(context.parsed.y * 10) / 10 + " " + "%";
|
||
} else {
|
||
if (context.parsed.y !== null) {
|
||
ret = scale(Math.round(context.parsed.y), false);
|
||
label += ret[0] + " " + ret[1] + "Wh";
|
||
}
|
||
}
|
||
return label;
|
||
};
|
||
|
||
tooltipFooter = function (tooltipItems){
|
||
let sum = 0;
|
||
|
||
tooltipItems.forEach(function(tooltipItem) {
|
||
if (tooltipItem.dataset.yAxisID != "y1") {
|
||
sum += tooltipItem.parsed.y;
|
||
}
|
||
});
|
||
ret = scale(Math.round(sum), false);
|
||
sum = ret[0] + " " + ret[1] + "Wh";
|
||
return 'Summe: ' + sum;
|
||
}
|
||
|
||
legendLabels = function(chart){
|
||
const datasets = chart.data.datasets;
|
||
const {
|
||
labels: {
|
||
usePointStyle,
|
||
pointStyle,
|
||
textAlign,
|
||
color
|
||
}
|
||
} = chart.legend.options;
|
||
return chart._getSortedDatasetMetas().map((meta) => {
|
||
const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
|
||
const borderWidth = Chart.helpers.toPadding(style.borderWidth);
|
||
ret = scale(Math.round(arraySum(datasets[meta.index].data)), false);
|
||
ret2 = scale(Math.round(datasets[meta.index].data[datasets[meta.index].data.length-1]), false);
|
||
return {
|
||
text: datasets[meta.index].label + " Σ " + ret[0]+" "+ret[1]+"Wh",//+ " Last: " + ret2[0]+" "+ret2[1]+"W",
|
||
fillStyle: style.backgroundColor,
|
||
fontColor: color,
|
||
hidden: !meta.visible,
|
||
lineCap: style.borderCapStyle,
|
||
lineDash: style.borderDash,
|
||
lineDashOffset: style.borderDashOffset,
|
||
lineJoin: style.borderJoinStyle,
|
||
lineWidth: (borderWidth.width + borderWidth.height) / 4,
|
||
strokeStyle: style.borderColor,
|
||
pointStyle: pointStyle || style.pointStyle,
|
||
rotation: style.rotation,
|
||
textAlign: textAlign || style.textAlign,
|
||
borderRadius: 0, // TODO: v4, default to style.borderRadius
|
||
datasetIndex: meta.index
|
||
};
|
||
}, this);
|
||
}
|
||
Chart.defaults.plugins.tooltip.callbacks.footer = tooltipFooter;
|
||
Chart.defaults.plugins.tooltip.callbacks.label = tooltipLabel;
|
||
Chart.defaults.plugins.legend.labels.generateLabels = legendLabels;
|
||
|
||
var forecastChartSettings = {
|
||
type: 'bar',
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
interaction: {
|
||
intersect: false,
|
||
mode: 'index',
|
||
},
|
||
scales: {
|
||
y: {
|
||
stacked: true,
|
||
display: true,
|
||
min: 0,
|
||
suggestedMax: 1000,
|
||
ticks: {
|
||
callback: value => `${value / 1000} kWh`,
|
||
}
|
||
},
|
||
}
|
||
}
|
||
};
|
||
|
||
var decadeChartSettings = {
|
||
type: 'bar',
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
interaction: {
|
||
intersect: false,
|
||
mode: 'index',
|
||
},
|
||
scales: {
|
||
y: {
|
||
stacked: true,
|
||
display: true,
|
||
min: 0,
|
||
suggestedMax: 1000000,
|
||
ticks: {
|
||
callback: value => `${value / 1000000} MWh`,
|
||
}
|
||
},
|
||
}
|
||
}
|
||
};
|
||
|
||
var chartData = {};
|
||
|
||
const consChart = new Chart(
|
||
document.querySelector('#consumption-chart'),
|
||
Object.assign({}, forecastChartSettings)
|
||
);
|
||
const prodChart = new Chart(
|
||
document.querySelector('#production-chart'),
|
||
Object.assign({}, forecastChartSettings)
|
||
);
|
||
const consChartYear = new Chart(
|
||
document.querySelector('#consumption-chart-year'),
|
||
Object.assign({}, decadeChartSettings)
|
||
);
|
||
const prodChartYear = new Chart(
|
||
document.querySelector('#production-chart-year'),
|
||
Object.assign({}, decadeChartSettings)
|
||
);
|
||
const consChartDecade = new Chart(
|
||
document.querySelector('#consumption-chart-decade'),
|
||
Object.assign({}, decadeChartSettings)
|
||
);
|
||
const prodChartDecade = new Chart(
|
||
document.querySelector('#production-chart-decade'),
|
||
Object.assign({}, decadeChartSettings)
|
||
);
|
||
document.addEventListener('readystatechange', function () {
|
||
if (event.target.readyState === "complete") {
|
||
getData(prodChart, 'ajax/energyHistory.php?series=prod&range=month');
|
||
getData(consChart, 'ajax/energyHistory.php?series=cons&range=month');
|
||
getData(prodChartYear, 'ajax/energyHistory.php?series=prod&range=year');
|
||
getData(consChartYear, 'ajax/energyHistory.php?series=cons&range=year');
|
||
getData(prodChartDecade, 'ajax/energyHistory.php?series=prod&range=decade');
|
||
getData(consChartDecade, 'ajax/energyHistory.php?series=cons&range=decade');
|
||
getStats("Stats-Year","ajax/getStats.php?type=ThisYear");
|
||
getStats("Stats-Lastyear","ajax/getStats.php?type=LastYear");
|
||
getStats("Stats-Prelastyear","ajax/getStats.php?type=PreLastYear");
|
||
}
|
||
});
|