Add helper class to manage a set of stacked bars
It also automatically generates and manages the legend.
This commit is contained in:
parent
0f37853aba
commit
6b2aab3391
2 changed files with 55 additions and 7 deletions
|
@ -15,28 +15,30 @@ class ChartStackedBar {
|
|||
* @type {Object[]}
|
||||
*/
|
||||
this.categories = [
|
||||
// { colour: "hsl(46, 80%, 50%)", weight: 4 }
|
||||
// { name: "Some category name", colour: "hsl(46, 80%, 50%)", weight: 4 }
|
||||
// ....
|
||||
];
|
||||
|
||||
this.auto_render = true;
|
||||
|
||||
|
||||
this.#svg = SVG().size("100%", "100%");
|
||||
this.svg = SVG().size("100%", "100%");
|
||||
|
||||
this.sym_bar = Symbol();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new category to the bar.
|
||||
* @param {string} name A display name for the category.
|
||||
* @param {string} colour The colour to assign to the category.
|
||||
* @param {number} weight The weighting value to assign to the category.
|
||||
* @returns {Symbol} A unique id for the new category.
|
||||
*/
|
||||
category_add(colour, weight) {
|
||||
category_add(name, colour, weight) {
|
||||
const id = Symbol();
|
||||
this.categories.push({
|
||||
id,
|
||||
name,
|
||||
colour,
|
||||
weight,
|
||||
[this.sym_bar]: null
|
||||
|
@ -61,7 +63,7 @@ class ChartStackedBar {
|
|||
for(const cat of this.categories) {
|
||||
const percent_this = this.#weight_percent(cat.weight);
|
||||
if(cat[this.sym_bar] === null) {
|
||||
cat[this.sym_bar] = this.#svg.rect("100%", "10%")
|
||||
cat[this.sym_bar] = this.svg.rect("100%", "10%")
|
||||
.fill(cat.colour)
|
||||
}
|
||||
cat[this.sym_bar].height = `${percent_this}%`;
|
||||
|
|
46
src/static/js/ui/charts/ChartStackedBarSet.mjs
Normal file
46
src/static/js/ui/charts/ChartStackedBarSet.mjs
Normal file
|
@ -0,0 +1,46 @@
|
|||
"use strict";
|
||||
|
||||
import Emel from 'emel';
|
||||
|
||||
class ChartStackedBarSet {
|
||||
constructor() {
|
||||
this.emel = new Emel().emel;
|
||||
|
||||
this.el = this.emel(`div[class="stacked-bar-set"]>div[class=legend]+div[class=bars]`);
|
||||
|
||||
this.bars = [];
|
||||
}
|
||||
|
||||
add_bar(i, bar) {
|
||||
this.bars.splice(i, 0, bar);
|
||||
this.#update_cats();
|
||||
}
|
||||
|
||||
#update_cats() {
|
||||
const el_legend = this.el.querySelector(`.legend`);
|
||||
const els_legend_items = [...el_legend.querySelectorAll(`.legend-item`)];
|
||||
|
||||
// map → flatten → uniq
|
||||
let cats = this.bars.map(bar => bar.categories).flat()
|
||||
.filter((cat, i) => cats.find(scat => cat.name === scat.name) === i);
|
||||
|
||||
for(const cat of cats) {
|
||||
const el_legend_item = els_legend_items.find(el => el.dataset.name === cat.name);
|
||||
if(typeof el_legend_item === "undefined") {
|
||||
// Nope, didn't find it - create it
|
||||
el_legend.appendChild(this.#make_legend_item(cat.colour, cat.name));
|
||||
}
|
||||
else {
|
||||
// Yep, we found it - update the names
|
||||
el_legend_item.querySelector(".legend-item-spot").style.background = cat.colour;
|
||||
el_legend_item.querySelector(".legend-item-text").replaceChildren(document.createTextNode(cat.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#make_legend_item(colour, name) {
|
||||
return this.emel(`span[class="legend-item"]>span[style="background: ${colour};" class="legend-item-spot"]+span[class="legend-item-text"]{${name}}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default ChartStackedBarSet;
|
Loading…
Reference in a new issue