dasf-web
Version:
Web frontend components for the data analytics software framework (DASF)
255 lines (212 loc) • 6.62 kB
text/typescript
import * as d3 from 'd3';
export default class BarChartNegativeValues {
private svg;
private targetElementId: string;
private data: Map<string, number> = new Map();
private paramColors: Map<string, string> = new Map();
private parent;
constructor(targetElementId: string, parent) {
this.targetElementId = targetElementId;
this.parent = parent;
}
public setChart(data: Map<string, number>, paramColors: Map<string, string>) {
this.paramColors = paramColors;
this.data = data;
this.build();
}
//render chart
private build() {
let self = this;
this.svg = d3
.select('#' + this.targetElementId)
.selectAll("*")
.remove();
let keys = Array.from(this.data.keys());
let values = Array.from(this.data.values());
// init the container
let d3Container: HTMLElement | null =
document.getElementById(this.targetElementId);
if (!d3Container) {
throw new Error("no container with id '" + this.targetElementId + "' found.");
}
const margin = 30;
const width = 500 - 2 * margin;
const height = 500 - 2 * margin;
// init the svg canvas
this.svg = d3
.select('#' + this.targetElementId)
.append('svg')
.attr(
'viewBox',
-margin + ' ' + -margin + ' ' + 550 + ' ' + 600
)
.classed('svg-content-responsive', true);
const chart = this.svg.append('g')
.attr('transform', `translate(${margin}, ${margin})`)
//xScale
const x = d3.scaleBand()
.range([0, width])
.domain(keys)
.padding(0.1)
chart.append('g')
.attr('transform', `translate(0, ${height})`)
.call(d3.axisBottom(x));
//yScale
var y0 = Math.abs(d3.min(values));
var y1 = Math.abs(d3.max(values));
var y2;
if(y0 > y1){
y2 = y0;
} else {
y2 = y1;
}
var y = d3.scaleLinear()
.domain([-y2, y2])
.range([height,0])
.nice();
var yAxis = d3.axisLeft()
.scale(y)
chart.append("g")
.attr("class", "x axis")
.call(yAxis);
//arrow
chart.append("svg:defs").append("svg:marker")
.attr("id", "triangle")
.attr("refX", 6)
.attr("refY", 6)
.attr("markerWidth", 30)
.attr("markerHeight", 30)
.attr("markerUnits","userSpaceOnUse")
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 12 6 0 12 3 6")
.style("fill", "white");
//Y-label
chart.append('text')
.attr('x', -(height / 4))
.attr('y', -(margin * 1.3))
.attr('transform', 'rotate(-90)')
.attr('text-anchor', 'start')
.attr("font-family", "sans-serif")
.attr("font-size", "13px")
.attr("fill", "white")
.text('ROI')
chart.append("line")
.attr("x1",-(margin * 1.5))
.attr("y1",(height / 2) - (margin/3))
.attr("x2",-(margin * 1.5))
.attr("y2",(height / 3) - (margin/3))
.attr("fill","white")
.attr("stroke", "white")
.attr("stroke-width",2)
.attr("marker-end","url(#triangle)");
chart.append('text')
.attr('x', -(height - (height / 4)))
.attr('y', -(margin * 1.3))
.attr('transform', 'rotate(-90)')
.attr('text-anchor', 'end')
.attr("font-family", "sans-serif")
.attr("font-size", "13px")
.attr("fill", "white")
.text('non-ROI')
chart.append("line")
.attr("x1",-(margin * 1.5))
.attr("y1",(height / 2) + (margin/3))
.attr("x2",-(margin * 1.5))
.attr("y2",(height / 1.5) + (margin/3))
.attr("fill","white")
.attr("stroke", "white")
.attr("stroke-width",2)
.attr("marker-end","url(#triangle)");
//grid lines
chart.append('g')
.attr('class', 'grid')
.call(d3.axisLeft()
.scale(y)
.tickSize(-width, 0, 0)
.tickFormat(''))
//bars
chart.selectAll()
.data(values)
.enter()
.append('rect')
.attr("class", function(d) { return d < 0 ? "bar negative" : "bar positive"; })
.attr("x", function(d) { return x(keys[values.indexOf(d)])})
.attr("y", function(d) { return y(Math.max(0, d)); })
.attr("height", function(d) { return Math.abs(y(d) - y(0)); })
.attr('width', x.bandwidth())
.attr('name', function(d) { return keys[values.indexOf(d)] })
.attr('stroke', 'white')
.attr('stroke-width', '0')
.style('fill', function(d) {
var param = keys[values.indexOf(d)];
return self.getColor(param);
});
// bar labels
chart.selectAll()
.data(values)
.enter()
.append("text")
.text(function(d) {
var num = d;
var n = num.toFixed(2);
return n;
})
.attr("x", function(d) {
var a = x(keys[values.indexOf(d)]);
return a + 10;
})
.attr("y", function(d) {
var b = y(0);
if( d < 0){
return b - 5;
} else {
return b + 15;
}
})
.attr("id", function(d) { return keys[values.indexOf(d)] })
.attr("font-family", "sans-serif")
.attr("font-size", "13px")
.attr("fill", "white")
.attr('opacity', 0);
//interactivity
chart.selectAll('rect')
.on('mouseenter', handleMouseEnter)
.on('mouseleave', handleMouseLeave)
.on('click', handleMouseClick)
// Create Event Handlers for mouseEnter
function handleMouseEnter(this) { // Add interactivity
//select rect, change opacity
d3.select(this)
.attr('opacity', 0.4)
.attr('stroke-width', '2')
//select text
var name = d3.select(this).attr("name");
d3.select("#" + name)
.attr('opacity', 1);
}
// Create Event Handlers for mouseLeave
function handleMouseLeave(this) { // Add interactivity
//select rect, change opacity
d3.select(this)
.attr('opacity', 1)
.attr('stroke-width', '0')
//select text
var name = d3.select(this).attr("name");
d3.select("#" + name)
.attr('opacity', 0);
}
function handleMouseClick(this) {
var name = d3.select(this).attr("name");
self.parent.showTable(name);
}
}
private getColor(param: string) : string{
var s = this.paramColors.get(param);
if(s != undefined){
return s;
} else {
return 'white';
}
}
}