ChartStackedBar: implement, but make it a simple unlabelled bar.
We can put the legend elsewhere, and manage multiple bars with a CSS grid or something.
This commit is contained in:
parent
0e2f68a067
commit
0f37853aba
1 changed files with 61 additions and 19 deletions
|
@ -1,37 +1,79 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import { SVG } from 'svg.js';
|
||||||
|
|
||||||
class ChartStackedBar {
|
class ChartStackedBar {
|
||||||
|
get weight_total() {
|
||||||
|
return this.categories.reduce((cat, acc) => cat.weight + acc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(el) {
|
constructor(el) {
|
||||||
this.el = el;
|
this.el = el;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The category names and their properties.
|
* The categories of this bar.
|
||||||
* @type {Object[]}
|
* @type {Object[]}
|
||||||
*/
|
*/
|
||||||
this.categories = [
|
this.categories = [
|
||||||
// { name: "Some category name", colour: "hsl(46, 80%, 50%)" }
|
// { colour: "hsl(46, 80%, 50%)", weight: 4 }
|
||||||
// ....
|
|
||||||
]
|
|
||||||
/**
|
|
||||||
* Whether to normalise all bars to be the same height or not.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
this.percentage = false;
|
|
||||||
/**
|
|
||||||
* The bars to render.
|
|
||||||
* Additional properties can be specified on the objects passed and
|
|
||||||
* this class will ignore them. It's strongly recommended though that
|
|
||||||
* any additional properties start with an underscore.
|
|
||||||
* @type {Object[]}
|
|
||||||
*/
|
|
||||||
this.bars = [
|
|
||||||
// { name: "bar name 1", values: [ { value: 3, cat: 1 }, .... ] }
|
|
||||||
// ....
|
// ....
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.auto_render = true;
|
||||||
|
|
||||||
|
|
||||||
|
this.#svg = SVG().size("100%", "100%");
|
||||||
|
|
||||||
|
this.sym_bar = Symbol();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new category to the bar.
|
||||||
|
* @param {string} colour The colour to assign to the category.
|
||||||
|
* @param {number} weight The weighting value to assign to the category.
|
||||||
|
*/
|
||||||
|
category_add(colour, weight) {
|
||||||
|
const id = Symbol();
|
||||||
|
this.categories.push({
|
||||||
|
id,
|
||||||
|
colour,
|
||||||
|
weight,
|
||||||
|
[this.sym_bar]: null
|
||||||
|
});
|
||||||
|
if(this.auto_render) this.render();
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
category_remove(id) {
|
||||||
|
for(const i in this.categories) {
|
||||||
|
if(this.categories[i].id === id) {
|
||||||
|
this.categories.splice(i, 1);
|
||||||
|
if(this.auto_render) this.render();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let percent_so_far = 0;
|
||||||
|
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%")
|
||||||
|
.fill(cat.colour)
|
||||||
|
}
|
||||||
|
cat[this.sym_bar].height = `${percent_this}%`;
|
||||||
|
cat[this.sym_bar] = cat[this.sym_bar].fill(cat.colour)
|
||||||
|
.move("0%", `${percent_so_far}%`);
|
||||||
|
|
||||||
|
percent_so_far += percent_this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#weight_percent(weight) {
|
||||||
|
return (weight / this.weight_total) * 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue