Hi!
I have been trying to isolate a Firefox scrolling problem when zooming X-axis with D3 that should not trigger a scrolling.
When there are too many D3 objects (about 50000 ‘rect’ in my test case) and using the wheel to zoom the graph, Firefox is “scrolling” the web page while it should not: the graph should only zoom.
Note that this problem occurs only with Firefox, it works fine with Edge/Chrome.
I have done a simple example (packed in a single html file) that triggers the problem for me both in windows and Linux: just try do some quick “scroll” in the graph. Note that you might need to increase the variable “numberOfBoxes” to trigger the problem.
Note that even the following code doesn’t seems to prevent the scrolling!
window.addEventListener(‘wheel’, preventDefault, { passive: false });
Do you know what is happening, is this a firefox bug and if there is a work around to the problem?
<!DOCTYPE html>
<head>
<title>test</title>
<script src="https://d3js.org/d3.v7.js"></script>
<style>
.bar-chart {background-color: #C7D9D9;}
.box {border: 1px solid black;padding: 10px;margin: 10px;}
</style>
</head>
<body>
<svg></svg>
<script>
function createGraph(){
svgWidth = 1000;
svgHeight = 1000;
barWidth = 10;
numberOfTicks = svgHeight/barWidth;
//boxes = [{"row": 10, "start" : 10, "end" : 20}];
numberOfBoxes = 50000;
var boxes = [];
for (var i = 1; i <= numberOfBoxes; i++) {
var row = (i%(numberOfTicks - 2)) + 1;
var start = (i%(svgWidth - 10));
var end = start + 10;
boxes.push({"row": row, "start" : start, "end" : end});
}
var x = d3.scaleLinear().range([0, svgWidth]).domain([0, svgWidth]);
var y = d3.scaleLinear().range([svgHeight, 0]).domain([numberOfTicks, 0]);
var xAxis = d3.axisBottom()
.scale(x)
.ticks(svgWidth/100);
var yAxis =d3.axisLeft()
.scale(y)
.ticks(numberOfTicks);
var svg = d3.select('svg')
.attr("width", svgWidth + 200)
.attr("height", svgHeight+ 200)
.append("g")
.attr("transform" , "translate(100, 100)");//move to the right and down
//Update axes
var gX = svg.append("g")
.attr("class", "axis")
.attr("transform","translate(0, " + svgHeight + ")") //move down
.call(xAxis);
var gY = svg.append("g")
.attr("class" , "axis")
.call(yAxis);
var graphContainer = svg.append("g");
var listenerRect = graphContainer.append("g")
.append("rect")
.attr("class", "view")
.attr("x", 0)
.attr("y", 0)
.attr("width", svgWidth - 1)
.attr("height", svgHeight - 1)
.style('opacity', 0.04);
var rectangles = graphContainer.append("g")
.selectAll("rect")
.data(boxes)
.enter().append("svg:rect")
.attr("class" , "bar") //css
.attr("x", function(d) { return x(d.start); })
.attr("y", function(d) { return y(d.row) - barWidth/2; })
.attr("width", function(d) { return x(d.end) - x(d.start)})
.attr("height", barWidth)
.style("opacity", '1')
.style("fill", "yellow")
.style("stroke", "gray")
.style("stroke-width", 2);
function inXPlotGraph(xParam)
{
return Math.max(0, Math.min(svgWidth, xParam));
}
//Define the zoom function
var zoom = d3.zoom()
.on("zoom",
function zoomed(event) {
var newX = event.transform.rescaleX(x);
//Update scale
gX.call(xAxis.scale(newX));
//Update rect
rectangles
.attr("x", function(d) { return inXPlotGraph(newX(d.start)); })
.attr("width", function(d) { return inXPlotGraph(newX(d.end)) - inXPlotGraph(newX(d.start))});
});
graphContainer
.call(zoom);
}
createGraph();
</script>
</body>