If you look at the example in full page (ignore the crazy line, that is not relevant), you will see that on load the last tick of the X axis is 'fudged' in by 10 by altering the transition attribute.
However, when you click the 'Update' button to run an update and transition of the XAxis data, the data is replaced and the 'fudged' position of the last tick is lost, despite the 'fudging' being re-applied in the customXAxis function that gets fired on the update.
I suspect this is something to do with the transition lifecycle??
Is it possible to make the positioning changes required to child elements (such as .remove() on certain elements prior to the transition of a parent?
var update = document.getElementById("update");
update.addEventListener(
"click",
function() {
updateFunc();
},
false
);
var data = [
{
date: 1,
amount: 58.13
},
{
date: 30,
amount: 53.98
},
{
date: 27,
amount: 67.0
},
{
date: 26,
amount: 89.7
},
{
date: 25,
amount: 99.0
},
{
date: 24,
amount: 130.28
},
{
date: 23,
amount: 166.7
},
{
date: 20,
amount: 234.98
},
{
date: 19,
amount: 345.44
},
{
date: 18,
amount: 443.34
},
{
date: 17,
amount: 543.7
},
{
date: 16,
amount: 580.13
},
{
date: 13,
amount: 605.23
},
{
date: 12,
amount: 622.77
},
{
date: 11,
amount: 626.2
},
{
date: 10,
amount: 628.44
},
{
date: 9,
amount: 636.23
},
{
date: 5,
amount: 633.68
},
{
date: 4,
amount: 624.31
},
{
date: 3,
amount: 629.32
},
{
date: 2,
amount: 618.63
},
{
date: 30,
amount: 599.55
},
{
date: 29,
amount: 609.86
},
{
date: 28,
amount: 617.62
},
{
date: 27,
amount: 614.48
},
{
date: 26,
amount: 606.98
}
];
// set the dimensions and margins of the graph
var margin = { top: 20, right: 20, bottom: 30, left: 50 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var valueline = d3
.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.amount);
});
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3
.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
// format the data
data.forEach(function(d) {
d.date = +d.date;
d.amount = +d.amount;
});
// Scale the range of the data
x.domain(
d3.extent(data, function(d) {
return d.date;
})
);
y.domain([
0,
d3.max(data, function(d) {
return d.amount;
})
]);
// Add the valueline path.
svg.append("path").data([data]).attr("class", "line").attr("d", valueline);
// Add the X Axis
svg
.append("g")
.attr("transform", "translate(0," + height + ")")
.classed("XAxis", true)
.call(customXAxis);
function customXAxis(g) {
g.call(d3.axisBottom(x));
var firstTicksTransform = svg
.selectAll(".XAxis .tick:first-of-type")
.attr("transform");
var translate = firstTicksTransform
.substring(
firstTicksTransform.indexOf("(") + 1,
firstTicksTransform.indexOf(")")
)
.split(",");
svg
.selectAll("XAxis .tick:first-of-type")
.attr("transform", "translate(" + (parseFloat(translate[0]) + 10) + ", 0)");
var lastTicksTransform = svg.selectAll(".XAxis .tick:last-of-type").attr("transform");
var translateLast = lastTicksTransform
.substring(
lastTicksTransform.indexOf("(") + 1,
lastTicksTransform.indexOf(")")
)
.split(",");
svg
.selectAll(".XAxis .tick:last-of-type")
.attr(
"transform",
"translate(" + (parseFloat(translateLast[0]) - 10) + ", 0)"
);
}
// Add the Y Axis
svg.append("g").classed("YAxis", true).call(d3.axisLeft(y));
var updateFunc = function() {
var svg = d3.select("body svg").transition();
data.forEach(function(d) {
d.date = d.date + 5;
d.amount = +d.amount;
});
x.domain(
d3.extent(data, function(d) {
return d.date;
})
);
svg.select(".XAxis").duration(750).call(customXAxis);
};
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<button id="update">Update</button>