I have been working on creating an SVG visualization using d3.js (specifically version 3 of d3 in PowerBI) and I am encountering difficulties in aligning my data points and fixed lines with the correct y-axis tick markers.
When there are 8 axis points, the lines are slightly above the markers, as seen here.
However, with only 1 or 2 points, the alignment is way off, as shown here.
I am attempting to dynamically calculate the offset since the number of y-axis ticks varies based on the PowerBI filter I apply.
Currently, my calculation involves taking the height of the SVG, dividing it by the number of ticks, and then halving it to center the alignment. The y-axis is ordinal.
Here is the relevant code snippet:
var margin = {top: 20, right: 250, bottom: 50, left: 50},
width = pbi.width - margin.left - margin.right,
height = pbi.height - margin.top - margin.bottom,
legendleft = pbi.width - margin.right;
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], barPad, barOuterPad);
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom + legendleft)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
y.domain(Data.map(function(d) { return d.reportingyear; }));
var YearSize = new Set(yearArray).size // Gets the number of ticks on the y-axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0, 6)")
.call(d3.svg.axis().scale(y).orient("left"));
// Code to chart the rows
var publishedRow = svg.append("g").attr("id", "publishedgroup").selectAll(null)
.data(rowArray)
.enter();
publishedRow.append("line")
.style("stroke", "grey")
.style("stroke-width", 1)
.style("stroke-dasharray", ("2, 2"))
.attr("x1", function(d) { return 0; })
.attr("y1", function(d) { return y(d.entry)+((pbi.height-margin.top-margin.bottom) / (new Set(yearArray).size) / 2); })
.attr("x2", function(d) { return width; })
.attr("y2", function(d) { return y(d.entry)+((pbi.height-margin.top-margin.bottom) / (new Set(yearArray).size) / 2); });
publishedRow.append("circle")
.attr("cx", function(d) {return x(new Date(d.date))} )
.attr("cy", function(d) {return y(d.year)+((pbi.height-margin.top-margin.bottom) / (new Set(yearArray).size) / 2); })
.attr("r", 7)
.style("fill", function(d, i) { return milestoneMap[d.milestone]; })
});
The .attr
lines in the code dynamically calculate the offset.
I am curious if there is a simpler approach to achieve this alignment or if there are any suggestions on why my current calculation method may not be working effectively.
Thank you for any guidance!