The task is creating a burn-up chart from Tickets on Trello
We make use of the Trello-API in C#, to get the tickets (Done/Created/etc...) however that is not what I want reviewed, since this has been done mostly before I joined this project. However I am a bit worried about my JavaScript for the d3.js code I created.
Code
<!DOCTYPE html>
<meta charset="utf-8">
<title>d3 burn chart</title>
<div id="charts"></div>
<style>
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 32px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
const burnuplist = [
{ Date: "/Date(1476079569717)/", Total:1, Burn:0 },
{ Date: "/Date(1476684369717)/", Total:23, Burn:2 },
{ Date: "/Date(1477289169717)/", Total:32, Burn:17 },
{ Date: "/Date(1477897569717)/", Total:57, Burn:40 },
{ Date: "/Date(1478502369717)/", Total:74, Burn:56 }
]
var formatTime = d3.timeFormat("%d-%m-%Y");
var drawLine = function(xvalues, yvalues, g, xscale, yscale, options) {
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// line parts
const lineparts = yvalues
.map((y, i, ar) => ({
i : i,
x1: xvalues[i - 1],
x2: xvalues[i],
y1 : ar[i - 1],
y2 : y
}))
.filter(d => d.i > 0);
// line
g.append("g")
.attr("id", options.id)
.selectAll("line")
.data(lineparts)
.enter()
.append("line")
.attr("x1", d => xscale(d.x1))
.attr("x2", d => xscale(d.x2))
.attr("y1", d => yscale(d.y1))
.attr("y2", d => yscale(d.y2))
.attr("stroke", options.color);
if (options.circles) {
g.append("g")
.selectAll("circle")
.data(lineparts)
.enter()
.append("circle")
.attr("r", 5)
.attr("cx", d => xscale(d.x2))
.attr("cy", d => yscale(d.y2))
.attr("fill", options.color)
.on("mouseover", function (d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.y2 + "</br>" + d.x2)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function (d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
}
}
var burnchart = function(xlabels, burnlist, totallist) {
const svg = d3.select('svg'),
margin = {top: 20, right: 40, bottom: 75, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
// x-axis
const x = d3.scalePoint()
.domain(xlabels)
.range([0, width]);
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", "rotate(-65)")
.attr("y", 4)
.attr("x", -10)
.attr("dy", ".35em");
// y-axis
const y = d3.scaleLinear()
.domain([0, 1.05 * Math.max(d3.max(burnlist), d3.max(totallist))])
.range([height, 0])
.nice();
g.append("g")
.call(d3.axisLeft(y));
// total
drawLine(xlabels, totallist, g, x, y,
{
color: "#000000",
circles: true,
id: "totallist"
});
// burn
drawLine(xlabels, burnlist, g, x, y,
{
color: "#3c763d",
circles: true,
id: "burnlist"
});
}
d3.select('#charts')
.selectAll('svg')
.data([burnuplist])
.enter()
.append('svg')
.attr('width', 860)
.attr('height', 480)
.style('margin', '0.5em')
.style('border', 'solid 2px #eef6fc')
.call(burnchart(
burnuplist.map(d => formatTime(new Date(parseInt(d.Date.replace("/Date(", "").replace(")/", ""), 10)))),
burnuplist.map(d => d.Burn),
burnuplist.map(d => d.Total)
)
);
</script>
Result
Questions
- Am I using d3.js correctly?
- I somehow needed to make an array over the Json data
[burnuplist]
- Maybe out of scope, but is there a better way to change how I handle the Date's?
- Any general tips on JavaScript styling?
I don't write much JS, as you can see ;) Any review is welcome.