charts/horizontalgroupedbar.mjs (221 lines of code) (raw):

import dataTools from "./shared/dataTools" import ColorScale from "./shared/colorscale" import { numberFormat, mustache, mobileCheck, getURLParams, getLabelFromColumn } from './shared/toolbelt'; import Dropdown from "./shared/dropdown"; import { addDrops } from "./shared/drops" import Tooltip from "./shared/tooltip" import { drawShowMore } from "./shared/showmore" import { addLabel, clickLogging } from './shared/arrows' export default class Groupedbar { constructor(settings) { this.settings = settings this.init() } init() { drawShowMore(this.settings.enableShowMore) if (this.settings.tooltip != "") { this.tooltip = new Tooltip(this.settings.tooltip) } if (this.settings.dropdown.length > 0) { addDrops() this.dropdown = new Dropdown( "dataPicker", dataTools.getDropdown(this.settings.dropdown, this.settings.keys) ) this.dropdown.on("dropdown-change", (label) => { let data = this.settings.dropdown.find(d => d.label == label) //this.settings.chartlines = [ this.settings.xColumn, ...data.values.split(',') ] if (this.settings.tooltip != "") { //this.tooltip.updateTemplate(data.tooltip) } this.render() }) } this.render() } render() { let { modules, height, width, isMobile, colors, datum, title, subtitle, source, marginleft, margintop, marginbottom, marginright, maxHeight, footnote, dateFormat, tooltip, xAxisLabel, yAxisLabel, periodDateFormat, data, keys, userkey, labels, lines, periods, type, enableShowMore, aria, colorScheme, dropdown, groupBy, columns } = this.settings d3.select("#graphicContainer svg").remove(); const chartKey = d3.select("#chartKey") chartKey.html("") const groupKey = data.map(d => d[groupBy]) datum = [] let columnsKey = JSON.parse(JSON.stringify(keys)) columnsKey = columnsKey.filter(d => d != groupBy) data.map(d => columnsKey.map(key => (+d[key]))).forEach(ob => datum.push(...ob)) isMobile = mobileCheck() width = document.querySelector("#graphicContainer").getBoundingClientRect().width height = (columnsKey.length * maxHeight) * groupKey.length width = width - marginleft - marginright height = height - margintop - marginbottom const svg = d3.select("#graphicContainer").append("svg") .attr("width", width + marginleft + marginright) .attr("height", height + margintop + marginbottom) .attr("id", "svg") .attr("overflow", "hidden"); const y0 = d3.scaleBand() .domain(groupKey) .rangeRound([margintop, height - marginbottom]) .paddingInner(0.1) const y1 = d3.scaleBand() .domain(columnsKey) .rangeRound([y0.bandwidth(), 15]) .padding(0.05) const x = d3.scaleLinear() .domain([0, d3.max(datum)]) .rangeRound([ marginleft, ( width + marginleft ) - marginright ]) colors = new ColorScale() const keyColor = dataTools.getKeysColors({ keys: columnsKey, userKey: userkey, option: { colorScheme : colorScheme } }) columnsKey.forEach((key, i) => { if (key != groupBy) { const keyDiv = chartKey .append("div") .attr("class", "keyDiv") keyDiv .append("span") .attr("class", "keyCircle") .style("background-color", () => colors.get(key)) keyDiv .append("span") .attr("class", "keyText") .text(getLabelFromColumn(columns, key)) } }) const xAxis = g => g .attr("transform", `translate(0,${0 + margintop})`) .attr("class", "axisgroup") .call(d3.axisTop(x).tickSizeOuter(0)) .call(d3.axisTop(x) .ticks(3) .tickFormat((d) => { return numberFormat(d) }) .tickSize(-height, 0, 0) .tickPadding(10)) const yAxis = g => g .attr("transform", `translate(${marginleft},0)`) .call(d3.axisLeft(y0)) const bars = svg.append("g") .selectAll("g") .data(data) .enter() .append("g") .attr("transform", d => `translate(0,${y0(d[[groupBy]])})`) bars.selectAll("rect") .data(d => { return columnsKey.filter(key => d[key] !== null).map(key => ({key, value: d[key], ...d})) }) .enter() .append("rect") .attr("class", "barPart") .attr("x", d => x(0)) .attr("y", d => y1(d.key)) .attr("height", y1.bandwidth()) .attr("width", d => x(d.value) - x(0)) .attr("fill", d => colors.get(d.key)) bars.selectAll("text") .data(d => columnsKey.filter(key => d[key] !== null).map(key => ({key, value: d[key]}))) .enter() .append("text") .attr("text-anchor", d => (x(d.value) - x(0) < 100) ? "start" : "end" ) .attr("x", d => (x(d.value) - x(0) < 100) ? x(d.value) + 10 : x(d.value) - 10) .attr("y", d => y1(d.key) + ( y1.bandwidth() - 7 ) ) .attr("fill", d => (x(d.value) - x(0) < 100) ? "black" : "white") .attr("font-weight","600") .text((d) => numberFormat(d.value)); bars.each(function(d, i) { const group = d3.select(this); const totalWidth = columnsKey .filter(key => d[key] !== null) .reduce((acc, key) => acc + x(d[key]) - x(0), 0); group.append("text") .attr("class", "group-label") .attr("x", (d) => x(0)) .attr("y", (d) => { const minY = Math.min(...columnsKey.filter(key => d[key] !== null).map(key => y1(key))); return minY - 10; }) .attr("text-anchor", "start") .attr("fill", "#767676") .text((d) => groupKey[i]); }); /* bars.selectAll("line") .data(d => columnsKey.map(key => ({key, value: d[key]}))) .enter() .append("line") .style("stroke", "#767676") .style("stroke-width", 1) .attr("x1", d => x(0)) .attr("y1", y0(0)) .attr("x2", d => x(0)) .attr("y2", d => y1(d.key) + ( y1.bandwidth() + 2 ) ) \*/ svg.append("g") .call(xAxis); //svg.append("g") //.call(yAxis); d3.selectAll('.axisgroup') .moveToBack() d3.selectAll('.domain') .remove() if (labels.length > 0) { const clickLoggingOn = getURLParams("labelling") ? true : false; console.log("clickLoggingOn", clickLoggingOn); // Move this to wrangle later once we re-factor the labelling stuff if (typeof labels[0].coords === 'string') { labels.forEach(function(d) { d.coords = JSON.parse(d.coords) d.sweepFlag = +d.sweepFlag d.largeArcFlag = +d.largeArcFlag d.radius = +d.radius }) } console.log("annotations", labels) labels.forEach((config) => { addLabel(svg, config, width + marginleft + marginright, height + margintop + marginbottom, { "left": marginleft, "right": marginright, "top": margintop, "bottom": marginbottom }, clickLoggingOn) }) } } }