简体   繁体   中英

Image flicker when user tries to pan

I am trying to implement panning and zooming feature using d3.js, everything is working fine, but when the user tries to pan on the initial state the image flicker badly.

The recreation of the issue

 let imgHeight = 400, imgWidth = 900, width = 900, height = 450; let zoom = d3.zoom().scaleExtent([1, 8]).on("zoom", zoomed); let svg = d3.select("#canvas").append("svg") .attr("width", width + "px") .attr("height", height + "px"); svg = svg.append("g") .attr("transform", "translate(0,25)") .call(zoom); svg.append("image") .attr("width", imgWidth + "px") .attr("height", imgHeight + "px") .attr("href", "https://www.w3schools.com/howto/img_fjords.jpg"); function zoomed() { svg.attr("transform", d3.event.transform); } let zoomIn = d3.select("#zoom-in"); zoomIn.on("click", function() { zoom.scaleBy(svg.transition().duration(750), 1.3); }) 
 <div id='canvas'> </div> <div id="tools"> <button id="zoom-in"> + </button> </div> <script src="https://d3js.org/d3.v4.min.js"></script> 

You have to call the zoom function on the SVG, not on the <g> element:

var svg = d3.select("#canvas").append("svg")
  .attr("width", width + "px")
  .attr("height", height + "px")
  .call(zoom)

Also, as you already have an initial translate...

svg.append("g")
    .attr("transform", "translate(0,25)");

... you should add this to the svg selection:

.call(zoom.transform, d3.zoomIdentity.translate(0, 25).scale(1));

Otherwise, the image will "jump" 25px up when you start the panning.

Here is your code with those changes:

 var imgHeight = 400, imgWidth = 900, width = 900, height = 450; var zoom = d3.zoom().scaleExtent([1, 8]).on("zoom", zoomed); var svg = d3.select("#canvas").append("svg") .attr("width", width + "px") .attr("height", height + "px") .call(zoom) .call(zoom.transform, d3.zoomIdentity.translate(0, 25).scale(1)); var g = svg.append("g") .attr("transform", "translate(0,25)"); g.append("image") .attr("width", imgWidth + "px") .attr("height", imgHeight + "px") .attr("href", "https://www.w3schools.com/howto/img_fjords.jpg"); function zoomed() { if (g) { g.attr("transform", d3.event.transform); } } var zoomIn = d3.select("#zoom-in"); zoomIn.on("click", function() { zoom.scaleBy(svg.transition().duration(750), 1.3); }) 
 <div id='canvas'> </div> <div id="tools"> <button id="zoom-in"> + </button> </div> <script src="https://d3js.org/d3.v4.min.js"></script> 

You should add another g element after the .call(zoom) :

svg = svg.append("g")
    .attr("transform", "translate(0,25)")
    .append("g")
    .attr('class', 'zoom-target')
    .call(zoom)
    .append("g"); // <== !!!

And change click event handler this way:

zoomIn.on("click", function() {
    zoom.scaleBy(d3.select('.zoom-target').transition().duration(750), 1.3);
})

Check the demo:

 let imgHeight = 400, imgWidth = 900, width = 900, height = 450; let zoom = d3.zoom().scaleExtent([1, 8]).on("zoom", zoomed); let svg = d3.select("#canvas").append("svg") .attr("width", width + "px") .attr("height", height + "px"); svg = svg.append("g") .attr("transform", "translate(0,25)") .append("g") .attr('class', 'zoom-target') .call(zoom) .append("g"); svg.append("image") .attr("width", imgWidth + "px") .attr("height", imgHeight + "px") .attr("href", "https://www.w3schools.com/howto/img_fjords.jpg"); function zoomed() { svg.attr("transform", d3.event.transform); } let zoomIn = d3.select("#zoom-in"); zoomIn.on("click", function() { zoom.scaleBy(d3.select('.zoom-target').transition().duration(750), 1.3); }) 
 <div id='canvas'> </div> <div id="tools"> <button id="zoom-in"> + </button> </div> <script src="https://d3js.org/d3.v4.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM