chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
var domainwidth = width - margin.left - margin.right,
domainheight = height - margin.top - margin.bottom;
var x = d3.scaleLinear()
.domain([1,6])
.range([0, domainwidth]);
var y = d3.scaleLinear()
.domain([1,6])
.range([domainheight, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.top + "," + margin.top + ")");
g.append("rect")
.attr("width", width - margin.left - margin.right)
.attr("height", height - margin.top - margin.bottom)
.attr("fill", "#F6F6F6");
g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + y.range()[0] / 2 + ")");
g.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + x.range()[1] / 2 + ", 0)");
var br = g.append("svg")
.attr('class', 'seg')
.attr("x", x(3.5))
.attr("y", y(3.5))
br.append("rect")
.attr("width", x(6) - x(3.5))
.attr("height", y(3.5))
.attr("fill", "lightblue")
.attr("opacity", 0.5);
var bl = g.append("svg")
.attr('class', 'seg')
.attr("x", x(1))
.attr("y", y(3.5))
bl.append("rect")
.attr("width", x(6) - x(3.5))
.attr("height", y(3.5))
.attr("fill", "lightblue")
.attr("opacity", 0.5);
var tl = g.append("svg")
.attr('class', 'seg')
.attr("x", x(1))
.attr("y", y(6))
tl.append("rect")
.attr("width", x(6) - x(3.5))
.attr("height", y(3.5))
.attr("fill", "lightblue")
.attr("opacity", 0.5);
var tr = g.append("svg")
.attr('class', 'seg')
.attr("x", x(3.5))
.attr("y", y(6))
tr.append("rect")
.attr("class", "pos")
.attr("width", x(6) - x(3.5))
.attr("height", y(3.5))
.attr("fill", "lightblue")
.attr("opacity", 0.5);
///Legend ////
var segwidth = tr.select(".pos").attr("width")
tr.selectAll("mydots")
.data(["income","expenditure","staff_cost","counselling_cost"])
.enter()
.append("circle")
.attr("cx",segwidth/1.5)
.attr("cy", function(d,i){ return 75 + i*20}) // 100 is where the first dot appears. 25 is the distance between dots
.attr("r", 5)
.style("fill", function(d){ return color(d)})
// Add one dot in the legend for each name.
tr.selectAll("mylabels")
.data(["income","expenditure","staff_cost","counselling_cost"])
.enter()
.append("text")
.attr("x", (segwidth/1.5)+10)
.attr("y", function(d,i){ return 75 + i*20}) // 100 is where the first dot appears. 25 is the distance between dots
// .style("fill", function(d){ return color(d)})
.text(function(d){ return d})
.attr("text-anchor", "left")
.style("alignment-baseline", "middle")
.attr("font-family" , "sans-serif")
.attr("font-size" , "12px")
.attr("fill" , "black")
const t = svg.transition()
.duration(750);
// tl.selectAll("mydots")
// .data(["counselling","staff_cost"])
// .enter()
// .append("circle")
// .attr("cx",(segwidth/1.5))
// .attr("cy", function(d,i){ return 60 + i*15}) // 100 is where the first dot appears. 25 is the distance between dots
// .attr("r", 5)
// .style("fill", function(d){ return colorTL(d)})
/// Add one dot in the legend for each name.
//tl.selectAll("mylabels")
// .data(["based on cost of service","based on staff cost"])
//.enter()
// .append("text")
// .attr("x", (segwidth/1.5) +10)
// .attr("y", function(d,i){ return 60 + i*15}) // 100 is where the first dot appears. 25 is the distance between dots
/// .style("fill", function(d){ return color(d)})
// .text(function(d){ return d})
// .attr("text-anchor", "left")
// .style("alignment-baseline", "middle")
// .attr("font-family" , "sans-serif")
// .attr("font-size" , "12px")
// .attr("fill" , "black")
////TEXT FIELDS
tl.append("text")
.attr("class", "testing")
.attr("x", width/4)
.attr("y", margin.top + 5)
.attr("dy", "1em")
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.text("Counselling Unit cost (£) based on total expenditure");
tl.selectAll("text")
.each(function(d, i) { wrap_text_nchar(d3.select(this), 35) });
tr.append("text")
.attr("class", "testing")
.attr("x", width/3)
.attr("y", margin.top + 7)
.attr("dy", "1em")
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.text("Charity financials compared with JDI ");
tr.selectAll("text")
.each(function(d, i) { wrap_text_nchar(d3.select(this), 50) });
br.append("text")
.attr("class", "testing")
.attr("x", width/3)
.attr("y", margin.top + 5)
.attr("dy", "1em")
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.text("Charity Counselling unit cost(£) by Year");
br.selectAll("text")
.each(function(d, i) { wrap_text_nchar(d3.select(this), 28) });
//Chart TOP LEFT ////////////////////
tl.append("g").call(g => drawGuidelines(g, data.map(d => d.shortname),
d => d3.line()([[xScaleTL(d) + hx, margin.top],[xScaleTL(d) + hx, (height/2) - margin.bottom]]))
);
tl.append("g")
.selectAll(".bar")
.data(data)
.join("rect")
.attr('class', function (d) {return d.shortname + 'staff_HC' + ' bar'}) // d => d.shortname
.attr('id', function (d) {return (d.shortname + 'tl')})
.attr('id2', "staff_HC")
.attr('x', d => xScaleTL(d.shortname))
.attr('y', function (d,i) {if(d.unit_cost === 0) {i = d.unit_max} else {i = d.unit_cost} return yScaleTL(i)})
.attr('width', xScaleTL.bandwidth())
.attr('height', function (d,i) {if(d.unit_cost === 0) {i = d.unit_max} else {i = d.unit_cost} return yScaleTL(0) - yScaleTL(i)})
.style('fill', function (d) {return colorTL(d.algorithm)})
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.append('title')
.text(function(d){return d.charity;});
tl.append("g").selectAll(".desc")
.data(data)
.join("text")
.attr('class',"desc")
.text(function (d) {return d.missed})
.attr('x', d => xScaleTL(d.shortname) + xScaleTL.bandwidth()/1.5)
.attr('y', function (d) {return yScaleTL(d.unit_cost) - 5})
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle");
const gtl = tl.append("g")
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2) - margin.bottom })`)
.call(xAxisTL);
gtl.transition(t)
.call(xAxisTL)
.selectAll("text")
.attr("class", "legend-text")
.attr("y", 0)
.attr("x", 9)
.attr('fill', 'navy')
.attr("transform", "rotate(90)")
.attr("text-anchor", "start");
tl.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "yellow")
.attr("stroke-width", 2.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
//.attr('marker-start', 'url(#dot)')
.attr("d", lineTL);
tl.append('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left },0)`)
.call( yAxisTL)
//Chart TOP LEFT ////////////////////END
//GENERAL////////////
const tr1 = tr.append("g")
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2) - margin.bottom })`)
.call( xAxisTR )
const tr2 = tr.append('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
.call( yAxisTR )
const br1 = br.append("g")
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2) - margin.bottom })`)
.call( xAxisBR )
const br2 = br.append('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
.call( yAxisBR )
const tl1 = tl.append("g")
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2) - margin.bottom })`)
// .call( xAxisTL )
const tl2 = tl.append('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
// .call( yAxisTL )
const bl1 = bl.append("g")
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2) - margin.bottom })`)
// .call( xAxisBL )
const bl2 = bl.append('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
// .call( yAxisBL )
//////GENERAL END/////////////
/// Chart BOTTOM LEFT///////////
bl.append("g").call(g => drawGuidelines(g, data.map(d => d.shortname),
d => d3.line()([[xScaleBL(d) + hx, margin.top],[xScaleBL(d) + hx, (height/2) - margin.bottom]]))
);
const bar = bl.append("g")
//.attr('class', "stacky")
.selectAll('g')
.data(stacked)
.join("g")
.style('fill', (d,i) => color(d.key))
.selectAll("rect")
.data(d => d)
.join("rect")
.attr('x', function (d) { return xScaleBL(d.data.shortname) + xScaleBL.bandwidth()/3})
.attr('class', function (d) { return d.data.shortname + d.key})
.attr('id', function (d) { return d.data.shortname + d.key})
.attr('id2', function (d) { return d.key})
.attr('y', d => yScaleBL(d[1]))
.attr('height', d => yScaleBL(d[0]) - yScaleBL(d[1]))
.attr('width', xScaleBL.bandwidth()/3)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.append('title')
.text(function(d){return d.data.charity;});
const gbl = bl.append("g")
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2.2) - margin.bottom })`)
.call(xAxisBL);
gbl.transition(t)
.call(xAxisBL)
.selectAll("text")
.attr("class", "legend-text")
.attr("y", 0)
.attr("x", 9)
.attr('fill', 'navy')
.attr("transform", "rotate(90)")
.attr("text-anchor", "start");
// bl.append("path")
// .datum(data)
// .attr("fill", "none")
// .attr("stroke", "yellow")
// .attr("stroke-width", 2.5)
// .attr("stroke-linejoin", "round")
// .attr("stroke-linecap", "round")
// .attr("d", lineBL);
bl.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "yellow")
.attr("stroke-width", 2.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
//.attr('marker-start', 'url(#dot)')
.attr("d", lineBL2);
bl.append('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left },0)`)
.call( yAxisBL)
bl.append('g')
.attr('class', 'y-axis')
.style('fill', 'yellow')
.attr("font-family" , "sans-serif")
.style("shape-rendering", "crispEdges")
.attr("font-size" , "12px")
// .attr("stroke" , "yellow")
// .attr("stroke-width", 0.5)
.attr('transform', `translate(${(width/2) - margin.left-margin.right},0)`)
.call( yAxisBL2)
/////setup
xScaleTR.domain(["JDI","TIC"])
var datas = dynamic.filter(function(e) { return e.shortname === "JDI" || e.shortname === "TIC" })
yScaleTR.domain([0,d3.max(datas, d => d.param)])
tr.append('g')
.attr('class', 'bars')
.selectAll('rect')
.data(datas)
.join('rect')
.attr('class', 'bar')
.attr("id", d => d.shortname)
.attr('x', d => xScaleTR(d.shortname) + xBars(d.category))
.attr('y', function(d) {return yScaleTR(d.param)})
.attr('width', xBars.bandwidth())
.attr('height', function (d,i) { return yScaleTR(0) - yScaleTR(d.param)})
.style('fill', function(d) { return color(d.category) })
tr1.call(xAxisTR)
.transition()
.duration(1000)
.ease(d3.easeLinear);
tr2.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
.call( yAxisTR )
.transition()
.duration(1000)
.ease(d3.easeLinear);
//bottom left
//bottom right
// xScaleBR.domain(order)
//xScaleBR.domain(arr)
var fiveYr_filt = fiveYr.filter(function(e) { return "TIC" })
yScaleBR.domain([0,d3.max(fiveYr_filt, d => d.param)])
br.append('g')
.attr('class', 'bars')
.selectAll('rect')
.data(fiveYr_filt)
.join('rect')
.attr('class', 'bar')
.attr('x', d => xScaleBR(d.category) + xScaleBR.bandwidth()/4)
.attr('y', function(d) {return yScaleBR(d.param)})
.attr('width', xBars.bandwidth())
.attr('height', function (d,i) { return yScaleBR(0) - yScaleBR(d.param)})
.style('fill', function(d) {if(d.category === "income") { return "red"} else if(d.category === "expenditure") { return "blue"} else if (d.category === "staff_cost") {return "yellow"} else {return "orange"} })
br1.call(xAxisBR)
.transition()
.duration(1000)
.ease(d3.easeLinear);
br2.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
.call( yAxisBR )
.transition()
.duration(1000)
.ease(d3.easeLinear);
br.append("text")
.attr("class", "selection")
.attr("x", width/3)
.attr("y", margin.top + 50)
.attr("dy", "1em")
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.text("Teens in Crisis");
/////setup
////BOTTON LEFT END/////////////////
function mouseout(event, d) {
var sel = d3.select(this).attr("id")
var sel2 = d3.select(this).attr("id2")
var act = tl.selectAll("." + sel)
if(sel === "tl") {
act.style("fill", colorTL(d.algorithm)) } else { //'#7472c0'
act.style("fill", colorTL(d.data.algorithm))} //'#7472c0'
if(sel2 === "staff_HC") {
var act2 = bl.selectAll("." + sel)
act2.style("fill", '#00ff40') }
}
function mouseover (event, d) {
br.selectAll(".selection").remove()
if(d.shortname == undefined) {d.shortname = d.data.shortname}
if(d.charity == undefined) {d.charity = d.data.charity}
br.append("text")
.attr("class", "selection")
.attr("x", width/3)
.attr("y", margin.top + 50)
.attr("dy", "1em")
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.text(d.charity);
var sel1 = d3.select(this).attr("id")
// console.log(sel1)
var sel2 = d3.select(this).attr("id2")
// console.log(sel2)
// if(sel2 === "tl") {
var act = d3.selectAll("." + sel1)
act.style("fill", "yellow") //}
var arr = ["JDI"]
if (!arr.includes(d.shortname)){arr.push(d.shortname);}
xScaleTR.domain(order)
xScaleTR.domain(arr)
var datas = dynamic.filter(function(e) { return e.shortname === "JDI" || e.shortname === d.shortname })
tr.selectAll(".bars").remove()
yScaleTR.domain([0,d3.max(datas, d => d.param)])
tr.append('g')
.attr('class', 'bars')
.selectAll('rect')
.data(datas)
.join('rect')
.attr('class', 'bar')
.attr("id", d => d.shortname)
.attr('x', d => xScaleTR(d.shortname) + xBars(d.category))
.attr('y', function(d) {return yScaleTR(d.param)})
.attr('width', xBars.bandwidth())
.attr('height', function (d,i) { return yScaleTR(0) - yScaleTR(d.param)})
.style('fill', function(d) { return color(d.category) })
tr1.call(xAxisTR)
.transition()
.duration(1000)
.ease(d3.easeLinear);
tr2.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
.call( yAxisTR )
.transition()
.duration(1000)
.ease(d3.easeLinear);
//bottom left
//bottom right
// xScaleBR.domain(order)
//xScaleBR.domain(arr)
var fiveYr_filt = fiveYr.filter(function(e) { return e.shortname === d.shortname })
br.selectAll(".bars").remove()
yScaleBR.domain([0,d3.max(fiveYr_filt, d => d.param)])
br.append('g')
.attr('class', 'bars')
.selectAll('rect')
.data(fiveYr_filt)
.join('rect')
.attr('class', 'bar')
.attr('x', d => xScaleBR(d.category) + xScaleBR.bandwidth()/4)
.attr('y', function(d) {return yScaleBR(d.param)})
.attr('width', xBars.bandwidth())
.attr('height', function (d,i) { return yScaleBR(0) - yScaleBR(d.param)})
.style('fill', function(d) {if(d.category === "income") { return "red"} else if(d.category === "expenditure") { return "blue"} else if (d.category === "staff_cost") {return "yellow"} else {return "orange"} })
br1.call(xAxisBR)
.transition()
.duration(1000)
.ease(d3.easeLinear);
br2.attr('class', 'y-axis')
.attr('transform', `translate(${ margin.left},0)`)
.call( yAxisBR )
.transition()
.duration(1000)
.ease(d3.easeLinear);
}
return Object.assign(svg.node(), {
update(order2) {
bl.append("text")
.attr("class", "testing")
.attr("x", width/2.95)
.attr("y", margin.top * 3)
.attr("dy", "1em")
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.text("Staff (green) - Volunteers (blue) Sessions/Yr (right axis)");
bl.selectAll("text")
.each(function(d, i) { wrap_text_nchar(d3.select(this), 25) });
const t = svg.transition()
.duration(1000);
var dataf = data.filter(function(e) {if(order2==="All"){return e } else { return e.service === order2}})
if(order2 === "All") { xScaleTL.domain([...new Set ((data.sort((a, b) => d3.descending(a.unit_cost, b.unit_cost) )).map(d => d.shortname))]);} else if (order2 === "CYW"){xScaleTL.domain([...new Set ((data.sort((a, b) => d3.descending(a.service, b.service)||d3.descending(a.unit_cost, b.unit_cost) )).map(d => d.shortname))])} else if (order2 === "C") {xScaleTL.domain([...new Set ((data.sort((a, b) => d3.ascending(a.service, b.service)||d3.descending(a.unit_cost, b.unit_cost) )).map(d => d.shortname))])}
gtl
.attr('class', 'x-axis')
.attr('transform', `translate(0,${ (height/2) - margin.bottom })`)
.call(xAxisTL);
gtl.transition(t)
.call(xAxisTL)
.selectAll("text")
.attr("class", "legend-text")
.attr("y", 0)
.attr("x", 9)
.attr('fill', 'navy')
.attr("transform", "rotate(90)")
.attr("text-anchor", "start");
const tx = tl.transition()
.duration(1000)
.ease(d3.easeBounce);
var bars = tl.selectAll(".bar").data(dataf, function(d) { return d.id; })
.join(enter => enter.append("rect")
.attr('class', function (d) {return d.shortname + 'staff_HC' + ' bar'}) // d => d.shortname
.attr('id', function (d) {return (d.shortname + 'tl')})
.attr('id2', "staff_HC")
.attr('x', d => xScaleTL(d.shortname))
.attr('y', function (d,i) {if(d.unit_cost === 0) {i = d.unit_max} else {i = d.unit_cost} return yScaleTL(i)})
.attr('width', xScaleTL.bandwidth())
.attr('height', function (d,i) {if(d.unit_cost === 0) {i = d.unit_max} else {i = d.unit_cost} return yScaleTL(0) - yScaleTL(i)})
.style('fill', function (d) {return colorTL(d.algorithm)})
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.append('title')
.text(function(d){return d.charity;})
.call(enter => enter.transition(tx)),
update => update
.call(update => update.transition(tx))
.attr('class', function (d) {return d.shortname + 'staff_HC' + ' bar'}) // d => d.shortname
.attr('id', function (d) {return (d.shortname + 'tl')})
.attr('id2', "staff_HC")
.attr('x', d => xScaleTL(d.shortname))
.attr('y', function (d,i) {if(d.unit_cost === 0) {i = d.unit_max} else {i = d.unit_cost} return yScaleTL(i)})
.attr('width', xScaleTL.bandwidth())
.attr('height', function (d,i) {if(d.unit_cost === 0) {i = d.unit_max} else {i = d.unit_cost} return yScaleTL(0) - yScaleTL(i)})
.style('fill', function (d) {return colorTL(d.algorithm)})
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.append('title')
.text(function(d){return d.charity;}),
exit => exit
.call(exit => exit.transition(tx)
.remove()));
// ));
var text = tl.selectAll(".desc").data(dataf)
.join(enter => enter.append("text")
.text(function (d) {return }) //d.missed}
.attr('x', d => xScaleTL(d.shortname) + xScaleTL.bandwidth()/1.5)
.attr('y', function (d) {return yScaleTL(d.unit_cost) - 5})
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.attr('class','desc')
.call(enter => enter.transition(t)),
update => update
.call(update => update.transition(t))
.text(function (d) {return })
.attr('x', d => xScaleTL(d.shortname) + xScaleTL.bandwidth()/1.5)
.attr('y', function (d) {return yScaleTL(d.unit_cost) - 5})
.attr("font-family" , "sans-serif")
.attr("font-size" , "14px")
.attr("fill" , "black")
.attr("text-anchor", "middle")
.attr('class','desc'),
exit => exit
.call(exit => exit.transition(t)
.remove()));
tl.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "yellow")
.attr("stroke-width", 2.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
//.attr('marker-start', 'url(#dot)')
.attr("d", lineTL);
}
})
}