Published
Edited
Oct 25, 2020
2 forks
Insert cell
Insert cell
Insert cell
chart = {
let svg = d3.select(DOM.svg(width + margin.left + margin.top, height + margin.top + margin.bottom))
let barCenter = horzScale.bandwidth() / 2;
let chart = svg.append("g").classed("chart", true).attr("transform", `translate(${margin.left}, ${margin.top})`)
chart.selectAll("rect.bar")
.data(dataset)
.join("rect")
.classed("bar", true)
.attr("x", (d)=>horzScale(d[0]))
.attr("y", (d)=>{
let {Online, Offline} = d[1],
max = Math.max(Online, Offline);
return vertScale(max);
})
.attr("width", horzScale.bandwidth())
.attr("height", (d)=>{
let {Online, Offline} = d[1]
return (height - vertScale(Math.abs(Online - Offline)))
})
.attr("fill", "gray")
var popup = null;
chart.selectAll("circle.online")
.data(dataset)
.join("circle")
.classed("online", true)
.attr("cx", (d)=>(horzScale(d[0])+barCenter))
.attr("cy", (d)=>(vertScale(d[1].Online)))
.attr("r", 7)
.attr("fill", "steelblue")
.style("cursor", "pointer")
.on("mouseover", function(event, d){
let x = horzScale(d[0]) + barCenter,
y = vertScale(d[1].Online)
popup.attr("transform", `translate(${x}, ${y}) rotate(-10)`)
callout(popup, [`${d[0]}(Online)`, revenueFormat(d[1].Online)])
})
.on("mouseout", function(){
popup.style("display", "none")
})
chart.selectAll("circle.offline")
.data(dataset)
.join("circle")
.classed("offline", true)
.attr("cx", (d)=>(horzScale(d[0])+barCenter))
.attr("cy", (d)=>(vertScale(d[1].Offline)))
.attr("r", 7)
.attr("fill", "red")
.style("cursor", "pointer")
.on("mouseover", function(event, d){
let x = horzScale(d[0]) + barCenter,
y = vertScale(d[1].Offline)
popup.attr("transform", `translate(${x}, ${y}) rotate(-10)`)
callout(popup, [`${d[0]}(Offline)`, revenueFormat(d[1].Offline)])
})
.on("mouseout", function(){
popup.style("display", "none")
})
//Add axis
chart.call(horzAxis)
chart.call(vertAxisLeft)
chart.call(vertAxisRight)
popup = chart.append("g").classed("popup", true);
return svg.node();
}
Insert cell
function callout(g, data){
let path = g.selectAll("path")
.data([null])
.join("path")
.attr("fill", "white")
.attr("fill-opacity", 0.8)
.attr("stroke", "black")
.attr("stroke-linejoin", "bevel");
let text = g.style("display", "")
.selectAll("text")
.data([null])
.join("text")
text.selectAll("tspan")
.data(data)
.join("tspan")
.attr("x", 20)
.attr("dy", (d, i)=>i*20)
.text((d)=>d)
text.select("tspan:first-child").style("font-weight", "600")
let {x,y,width,height} = text.node().getBBox();
let endX = width+25,endY = height;
path.attr("d", `M0 0 L10 -20 L${endX} -20 L${endX} ${endY} L10 ${endY} Z`)
}
Insert cell
Insert cell
d3 = require("d3@6")
Insert cell
Insert cell
Insert cell
width = 900
Insert cell
height = 400
Insert cell
margin = ({top:20, right:40, bottom:40, left:40})
Insert cell
horzScale = d3.scaleBand([...dataset.keys()], [0, width]).padding(0.95)
Insert cell
horzAxis = (e)=>e.append("g").classed("x axis", true).call(d3.axisBottom(horzScale)).attr("transform", `translate(0, ${height})`)
Insert cell
vertScale = d3.scaleLinear([0, d3.max(dataset, (d)=>(Math.max(d[1].Online, d[1].Offline)))], [height, 0]).nice()
Insert cell
vertAxisLeft = (e)=>e.append("g").classed("y axis", true).call(d3.axisLeft(vertScale).tickFormat(d3.format("~s"))).select(".domain").remove()
Insert cell
vertAxisRight = (e)=>e.append("g").classed("y axis right", true).call(d3.axisRight(vertScale).tickFormat(d3.format("~s"))).attr("transform", `translate(${width}, 0)`).select(".domain").remove()
Insert cell
revenueFormat = d3.format("$,.2f")
Insert cell
revenueFormat(1243525.48838992)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more