I'm trying to get zoom working on some rather simple line charts for a greenhouse project.
This is what I have, it seems like when I mouse over the SVG my mouse events start getting captured, the Y axis gets redrawn like I'm zooming in, my X axis labels disappear, and the lines and dots in the actual plot don't change.
// draw the temperature over time graph
function draw_temp_graph(data) {
const button = d3.selectAll('input[name="units"]');
const isFahrenheit = button.property('checked');
// Creating tooltip div
var div = d3.select("#temp_graph").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Handling data when it's arrived
data.then(function (data) {
data.forEach( (d) => {
d.d_date = new Date(d.time_stamp * 1000);
if (isFahrenheit) {
d.t_temp = (d.temp * (9.0 / 5.0) + 32).toFixed(2);
} else {
d.t_temp = d.temp;
}
});
// set dimensions and margins
var margin = {top: 50, right: 30, bottom: 100, left: 60 },
width = 800 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// Create svg
var svg = d3.select("#temp_graph")
.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 + ")");
// Add Graph title
svg.append("text")
.attr("x", (width / 2 ))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "1.4em")
.style("text-decoration", "underline")
.text("Temperature");
// Add X axis
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.d_date; }))
.range([0, width]);
var xAxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// Add X axis label
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 40) + ") ")
.style("text-anchor", "middle")
.text("Time");
// Add Y axis
minY = d3.min(data, function(d) { return +d.t_temp } );
maxY = d3.max(data, function(d) { return +d.t_temp } );
var y = d3.scaleLinear()
.domain([minY, maxY])
.range([height, 0]);
var yAxis = svg.append("g")
.call(d3.axisLeft(y));
// Add Y axis label
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Degrees");
// Add a line
var line = svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#00a899")
.attr("stroke-width", 1.5)
.attr('id', 'temp_line')
.attr("d", d3.line()
.x(function(d) { return x(d.d_date) })
.y(function(d) { return y(d.t_temp) })
)
// Add dots with tooltips
var dots = svg.selectAll('dot')
.data(data)
.enter().append('circle')
.attr('r', 1.5)
.attr('cx', function(d) { return x(d.d_date); })
.attr('cy', function(d) { return y(d.t_temp); })
.attr('fill', '#00A198')
.on('mouseover', function(event, d) {
div.transition()
.duration(200)
.style('opacity', .9);
div.html(formatTime(d.d_date) + '<br/>' + d.t_temp + '\u00B0')
.style('left', (event.pageX) + 'px')
.style('top', (event.pageY - 28) + 'px');
})
.on('mouseout', function(d) {
div.transition()
.duration(500)
.style('opacity', 0);
})
// Setting a clipPath, this is to "clip" everything outside of a certain area
// var clip = svg.append('defs').append('svg:clipPath')
// .append('svg:rect')
// .attr('width', 800)
// .attr('height', 500)
// .attr('x', 0)
// .attr('y', 0);
// Creating a zoom object
var zoom = d3.zoom()
.scaleExtent([0.5, 20])
.extent([[0, 0], [width, height]])
.on('zoom', updateTemp);
svg
.style('pointer-events', 'all')
.call(zoom);
// function to redraw while zooming
function updateTemp() {
console.log('zoomed')
// get the new scale
var transform = d3.zoomTransform(this);
var newX = transform.rescaleX(x);
var newY = transform.rescaleY(y);
// update the axes
xAxis.call(d3.axisBottom(newX));
yAxis.call(d3.axisLeft(newY));
// update the line
line
.selectAll('path')
.attr('d', d3.line()
.x(function (d) {
return newX(d.d_date);
})
.y(function (d) {
return newY(d.t_temp);
})
)
// update the chart
dots
.selectAll('dot')
.selectAll('circle')
.attr('cx', function (d) {
return newX(d.d_date);
})
.attr('cy', function (d) {
return newY(d.t_temp);
})
}
})
}
in d3 js v 6 you don't need 'pointer-events' you also need to change the update to take in 'event'
//.style('pointer-events', 'all') in d3 js v6 you don't need it anymore
svg.call(zoom);
// function to redraw while zooming
// in d3 js v6 you need to use event in update
function updateTemp(event) {
console.log('zoomed')
// get the new scale
//var transform = d3.zoomTransform(this);
//var newX = transform.rescaleX(x);
//you need use event like this :
var newX = event.transform.rescaleX(x);
//var newY = transform.rescaleY(y);
//you need to use event like this :
var newY = event.transform.rescaleY(y)
// update the axes
xAxis.call(d3.axisBottom(newX));
yAxis.call(d3.axisLeft(newY));
// update the line
line
.selectAll('path')
.attr('d', d3.line()
.x(function (d) {
return newX(d.d_date);
})
.y(function (d) {
return newY(d.t_temp);
})
)
// update the chart
dots
.selectAll('dot')
.selectAll('circle')
.attr('cx', function (d) {
return newX(d.d_date);
})
.attr('cy', function (d) {
return newY(d.t_temp);
})
}