如何暂时禁用d3.js中的缩放

时间:2013-09-13 13:56:24

标签: javascript svg d3.js zoom behavior

我正在寻找暂时禁用d3库提供的缩放功能的可能性。我尝试在停用缩放时保存洞穴当前缩放/平移值,并在再次激活缩放时设置缩放/平移值。不幸的是,这不起作用。

这是我创建的代码示例:

var savedTranslation = null;
var savedScale = null;

var body = d3.select("body");

var svg = body.append("svg");

var svgContainer = svg.append("svg:g");

var circle = svgContainer.append("svg:circle")
    .attr('cx', 100)
    .attr('cy', 100)
    .attr('r',30)
    .attr('fill', 'red');

circle.on('click', clickFn);

function clickFn(){
    if (circle.attr('fill') === 'red'){
        circle.attr('fill','blue')
    }
    else if (circle.attr('fill') === 'blue'){
        circle.attr('fill','red')
    }
}; 

svg.call(zoom = d3.behavior.zoom().on('zoom', redrawOnZoom)).on('dblclick.zoom', null);


 function redrawOnZoom(){
     if (circle.attr('fill') === 'red'){
         if (savedScale !== null){
             zoom.scale(savedScale)
             savedScale = null
         }
         if (savedTranslation !== null){
             zoom.translate(savedTranslation)
             savedTranslation = null
         }
         // the actual "zooming"
         svgContainer.attr('transform', 'translate(' + d3.event.translate + ')' + ' scale(' +         d3.event.scale + ')');
     }
     else {
         // save the current scales
         savedScale = zoom.scale()
         savedTranslation = zoom.translate()
     }
};

这是working jsfiddle example.

编辑:

可以通过以下步骤复制虚假行为:

  1. 点击圆圈,颜色变为蓝色,缩放不起作用
  2. 使用鼠标滚轮在一个方向上几次,就像您要缩放(例如放大)
  3. 一样
  4. 再次点击圆圈,颜色选项为红色,重新启用缩放
  5. 使用鼠标滚轮,圆圈会很大/很小

8 个答案:

答案 0 :(得分:8)

我发现的最简单方法是简单地禁用所选的.zoom个事件。您必须重新调用zoom才能再次启用该行为。

if (zoomEnabled) {
    svg.call(zoom);
} else {
    svg.on('.zoom', null);
}

jsfiddle

答案 1 :(得分:4)

我一直在努力解决同样的问题。而且,我找到了一种解决方案,可以保存缩放和平移,而不会出现您在当前解决方案中看到的跳跃。

主要更改是执行缩放的保存/更新并在“单击”功能中进行翻译。因此,可以使用缩放功能的参考,必须在缩放行为之后设置单击。解决方案看起来像这样。您问题中的相同样板:

var savedTranslation = null;
var savedScale = null;

var body = d3.select("body");

var svg = body.append("svg");

var svgContainer = svg.append("svg:g");

var circle = svgContainer.append("svg:circle")
    .attr('cx', 100)
    .attr('cy', 100)
    .attr('r',30)
    .attr('fill', 'red');

然后是缩放功能,无需管理已保存的比例并翻译:

svg.call(zoom = d3.behavior.zoom().on('zoom', redrawOnZoom)).on('dblclick.zoom', null);

function redrawOnZoom(){
     if (circle.attr('fill') === 'red'){
         // the actual "zooming"
         svgContainer.attr('transform', 'translate(' + zoom.translate() + ')' + ' scale(' + zoom.scale() + ')');
     }
};

最后,附上下面的点击行为,并保存并设置比例和翻译:

circle.on('click', clickFn);

function clickFn(){
    if (circle.attr('fill') === 'red'){
        circle.attr('fill','blue')
         if (savedScale === null){
             savedScale = zoom.scale();
         }
          if (savedTranslation === null){
             savedTranslation = zoom.translate();
         }      
    }
    else if (circle.attr('fill') === 'blue'){
        circle.attr('fill','red')
        if (savedScale !== null){
             zoom.scale(savedScale);
             savedScale = null;
         }
         if (savedTranslation !== null){
             zoom.translate(savedTranslation);
             savedTranslation = null;
         }
    }
}; 

这是一个有效的版本:http://jsfiddle.net/cb3Zm/1/

然而,当发生拖动时仍然会发生点击事件,这看起来并不理想,但我还没能解决它。

答案 2 :(得分:2)

请参阅更新的小提琴:http://jsfiddle.net/prayerslayer/La8PR/1/

我在点击处理程序中重新分配了一个空缩放行为。

function clickFn(){
    if (circle.attr('fill') === 'red'){
        circle.attr('fill','blue');
        svg.call( fake );
    }
    else if (circle.attr('fill') === 'blue'){
        circle.attr('fill','red');
        svg.call( zoom );
    }
}; 

我认为有一个更好的解决方案,因为我可能会引入内存泄漏。

优于全局doZoom标记的优点是您不必保存和检查缩放和转换值,因为缩放行为继续有效(例如设置d3.event.scale)即使您是不改变观点。

答案 3 :(得分:2)

Yabba Dabba Doo!

好的,问题在于

else {
     // save the current scales
     savedScale = zoom.scale()
     savedTranslation = zoom.translate()
 }

一部分。每个事件都会调用这些值,而不仅仅是在圆圈改变颜色后调用一次。所以解决方案是:

else {
     // save the current scales
     if (savedScale === null){
         savedScale = zoom.scale();
     }
      if (savedTranslation === null){
         savedTranslation = zoom.translate();
     }         

现在它的工作原理! Updated jsFiddle here.

答案 4 :(得分:2)

当我找到解决方案时,我想赶上这个! 诀窍是重置比例并在zoomstart和zoomend事件中进行转换。

var zoom = d3.behavior.zoom()
    .scaleExtent([1, 10])
    .on("zoomstart", zoomstart)
    .on("zoomend", zoomend)
    .on("zoom", zoomed);

function zoomed() {
    if (circle.attr('fill') === 'red') {
        if (savedScale !== null){
             zoom.scale(savedScale);
         }
         if (savedTranslation !== null){
            zoom.translate(savedTranslation);
         }
        svgContainer.attr('transform', 'translate(' +   d3.event.translate + ')' + ' scale(' +         d3.event.scale + ')');
    }
}

function zoomend () {
    if (circle.attr('fill') === 'red') {
        if (savedScale !== null){
             zoom.scale(savedScale);
             savedScale = null;
         }
         if (savedTranslation !== null){
            zoom.translate(savedTranslation);
             savedTranslation = null;
         }
     }
}

function zoomstart (d) {
    if (circle.attr('fill') === 'red'){
         if (savedScale !== null){
             zoom.scale(savedScale)
         }
         if (savedTranslation !== null){
             zoom.translate(savedTranslation)
         }
     } else {
        if (savedScale === null) {
            savedScale = zoom.scale();
        }
        if (savedTranslation === null) {
            savedTranslation = zoom.translate();
        }
     }
}

答案 5 :(得分:1)

我实现此方法的方法是使用全局标志来告诉您是否启用了缩放。然后,您只需要检查是否在处理缩放的函数中设置了此标志。如果是,则该功能不执行任何操作。

答案 6 :(得分:0)

我觉得以这种方式做得更漂亮。

function clickFn(){
    if (circle.attr('fill') === 'red'){
        circle.attr('fill','blue');
        savedScale = zoom.scale();
        savedTranslation = zoom.translate();
    }
    else if (circle.attr('fill') === 'blue'){
         circle.attr('fill','red');
         zoom.scale(savedScale);
         zoom.translate(savedTranslation);
    }
}; 

svg.call(zoom = d3.behavior.zoom().on('zoom', redrawOnZoom)).on('dblclick.zoom', null);


 function redrawOnZoom(){
     if (circle.attr('fill') === 'red'){
         // the actual "zooming"
        svgContainer.attr('transform', 'translate(' + d3.event.translate + ')' + ' scale(' +         d3.event.scale + ')');
     }

};

答案 7 :(得分:0)

https://github.com/d3/d3-zoom/issues/156

const svg = d3.select(svgElement);
const zoom = d3.zoom();

function startZoomPan() {
  svg.call(zoom); // attach the zoom listeners
}

function stopZoomPan() {
  svg.on('.zoom', null); // remove the zoom listeners
}

mousemove 处理程序是热代码,所以在那里分支很慢