11

我正在寻找暂时禁用 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()
     }
};

这是一个有效的 jsfiddle 示例。

编辑:

错误行为可以通过以下步骤重现:

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

8 回答 8

11

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

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

jsfiddle

于 2015-04-21T03:29:46.213 回答
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/

但是,当拖动发生时,单击事件仍然会发生,这似乎并不理想,但我还没有能够修复它。

于 2014-03-01T04:11:38.520 回答
3

查看更新的小提琴: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即使您没有更改视图,缩放行为也会继续工作(例如设置)。

于 2013-09-13T15:30:07.983 回答
2

雅巴达巴斗!

好的,问题出在

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();
     }         

现在它可以工作了! 在这里更新了 jsFiddle。

于 2013-09-16T08:22:10.640 回答
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();
        }
     }
}
于 2015-01-28T11:38:17.660 回答
0

我将实现这一点的方式是使用一个全局标志来告诉您是否启用了缩放。然后您只需要检查是否在处理缩放的函数中设置了此标志。如果是,该函数什么也不做。

于 2013-09-13T15:26:45.220 回答
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 + ')');
     }

};
于 2014-01-03T05:56:23.313 回答
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 处理程序是热代码,因此分支很慢

于 2021-03-02T11:43:38.707 回答