203 lines
4.7 KiB
JavaScript
203 lines
4.7 KiB
JavaScript
"use strict";
|
|
|
|
import Emel from 'emel';
|
|
import forkawesome_emel from './forkawesome_emel.mjs';
|
|
// import ChartStackedBarSet from './charts/ChartStackedBarSet.mjs';
|
|
import Plotly from 'plotly.js-dist';
|
|
|
|
import AbstractUIItem from './AbstractUIItem.mjs';
|
|
|
|
import find_in_obj from '../misc/find_in_obj.mjs';
|
|
|
|
class UIGauge extends AbstractUIItem {
|
|
#chart_data = [];
|
|
#chart = null;
|
|
|
|
constructor(el, def) {
|
|
super(el, def);
|
|
|
|
this.emel = new Emel().emel;
|
|
this.el.replaceChildren(this.emel(`h3{?}+div[class="container-gauge"]`, {
|
|
placeholders: [ this.def.name ]
|
|
}));
|
|
|
|
this.el_gauge = this.el.querySelector(".container-gauge");
|
|
|
|
}
|
|
|
|
render() {
|
|
// Refuse to render an empty chart
|
|
if(this.#chart_data.length === 0) return;
|
|
|
|
const data = {
|
|
x: [], // Labels
|
|
y: [], // Data numbers
|
|
type: "bar",
|
|
marker: {
|
|
color: "hsla(178, 61%, 59%, 0.75)" // --tech-d, taken from the CSS
|
|
}
|
|
};
|
|
|
|
for (const itemdef of this.#chart_data) {
|
|
let label_this = itemdef.label;
|
|
for (let i = 2; data.x.includes(label_this); i++)
|
|
label_this = `${itemdef.label} (${i})`;
|
|
data.x.push(label_this);
|
|
data.y.push(itemdef.data_item);
|
|
}
|
|
|
|
data.text = data.y.map(value => this.def.gauge_unit ? `${value} ${this.def.gauge_unit}` : value);
|
|
|
|
console.log(`def ${this.def.name} plotly definition`, data);
|
|
|
|
const layout = {
|
|
// title: this.def.name // We already have a title, but if we didn't we'd add one like this
|
|
paper_bgcolor: window.getComputedStyle(this.el_gauge, null).backgroundColor,
|
|
plot_bgcolor: "transparent",
|
|
modebar: { bgcolor: "transparent" },
|
|
font: {
|
|
color: "white"
|
|
},
|
|
margin: {
|
|
b: 80, l: 40, r: 40, t: 40
|
|
}
|
|
}
|
|
|
|
if(this.#chart === null) {
|
|
console.log(`def ${this.def.name} plotly NEW`);
|
|
this.#chart = Plotly.newPlot(
|
|
this.el_gauge,
|
|
[data], layout,
|
|
{ responsive: true }
|
|
);
|
|
}
|
|
else {
|
|
console.log(`def ${this.def.name} plotly REACT`);
|
|
this.#chart = Plotly.react(
|
|
this.el_gauge,
|
|
[data], layout,
|
|
{ responsive: true }
|
|
);
|
|
}
|
|
}
|
|
|
|
#__insert_item(label, data_item) {
|
|
const comparer = new Intl.Collator(navigator.language);
|
|
|
|
for(let i in this.#chart_data) {
|
|
const comp_name = comparer.compare(
|
|
label.toLowerCase(),
|
|
this.#chart_data[i].label.toLowerCase()
|
|
);
|
|
|
|
if(comp_name < 0) { // Insert immediately before this index
|
|
this.#chart_data.splice(i, 0, {
|
|
label,
|
|
data_item
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
// Didn't manage to find a good sopt, put it on the end
|
|
this.#chart_data.push({ label, data_item });
|
|
}
|
|
|
|
clear() {
|
|
super.clear();
|
|
this.el_gauge.replaceChildren();
|
|
this.chart = null;
|
|
this.#chart_data = [];
|
|
}
|
|
|
|
append(peer, table) {
|
|
super.append(peer, table);
|
|
|
|
let label = peer.name; //`${peer.name}\n${peer.id.slice(0, 7)}`; // Plotly doesn't support multiline labels :-/
|
|
let data_item = null;
|
|
switch(typeof this.def.content) {
|
|
case "function":
|
|
data_item = this.def.content(table);
|
|
break;
|
|
case "string":
|
|
data_item = find_in_obj(table, this.def.content);
|
|
break;
|
|
default:
|
|
console.warn(`Warning: Unknown UIGauge content type '${typeof this.def.content}' for def with name '${this.def.name}'.`);
|
|
this.el.querySelector(".container-gauge").replaceChildren(
|
|
this.emel(`div[class="message-error"]>${forkawesome_emel("exclamation-circle")}+{Oops! An error occurred while rendering this chart. Check the developer tools for more information.}`)
|
|
)
|
|
return false;
|
|
}
|
|
|
|
if(data_item == null) {
|
|
console.warn(`Warning: Got null when evaluating value for UIGauge.`);
|
|
return false;
|
|
}
|
|
if(typeof data_item !== "number") {
|
|
console.warn(`Warning: Got '${typeof data_item}' when evaluating value for UIGauge.`);
|
|
return false;
|
|
}
|
|
|
|
this.#__insert_item(label, data_item);
|
|
console.log(`def ${this.def.name} | chart_data`, this.#chart_data);
|
|
this.render();
|
|
}
|
|
}
|
|
|
|
export default UIGauge;
|
|
|
|
/*
|
|
var options = {
|
|
series: [{
|
|
name: 'Net Profit',
|
|
data: [44, 55, 57, 56, 61, 58, 63, 60, 66]
|
|
}, {
|
|
name: 'Revenue',
|
|
data: [76, 85, 101, 98, 87, 105, 91, 114, 94]
|
|
}, {
|
|
name: 'Free Cash Flow',
|
|
data: [35, 41, 36, 26, 45, 48, 52, 53, 41]
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 350
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: false,
|
|
columnWidth: '55%',
|
|
endingShape: 'rounded'
|
|
},
|
|
},
|
|
dataLabels: {
|
|
enabled: false
|
|
},
|
|
stroke: {
|
|
show: true,
|
|
width: 2,
|
|
colors: ['transparent']
|
|
},
|
|
xaxis: {
|
|
categories: ['Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct'],
|
|
},
|
|
yaxis: {
|
|
title: {
|
|
text: '$ (thousands)'
|
|
}
|
|
},
|
|
fill: {
|
|
opacity: 1
|
|
},
|
|
tooltip: {
|
|
y: {
|
|
formatter: function(val) {
|
|
return "$ " + val + " thousands"
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var chart = new ApexCharts(document.querySelector("#chart"), options);
|
|
chart.render();
|
|
*/
|