2013-09-13 3 views
7

Я ищу возможность временно отключить функции масштабирования, предоставляемые библиотекой d3. Я попытался сохранить пещеру текущие значения масштаба/трансляции, когда масштабирование отключено, и установите значения масштабирования/трансляции, когда масштабирование будет активным снова. К сожалению, это не сработает.Как временно отключить масштабирование в d3.js

Вот пример кода, я создал:

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.

EDIT:

Ложное поведение может быть воспроизведена с помощью следующих шагов:

  1. Click на круге цвет меняется на синий, масштабирование не работает
  2. Используйте колесико мыши в ОДНОМ НАПРАВЛЕНИИ несколько раз, как если бы вы увеличивали масштаб (например, увеличение)
  3. Нажмите снова на круге, цвет chnages красные, увеличение повторно включено
  4. Используйте колесо мыши, круг будет огромным/крошечным

ответ

1

Пути я бы осуществить это с глобальным флагом, который сообщает вам, включено ли масштабирование или нет. Затем вам просто нужно проверить, установлен ли этот флаг в функции, которая обрабатывает масштаб. Если это так, функция ничего не делает.

+0

Но как я должен выполнять, что функция «ничего не делает», но я могу снова включить масштабирование на какой-то момент, и это будет продолжаться с того момента, когда я отключить его? У меня были прыжки/движения в моей визуализации, потому что событие все еще реагирует на колесо мыши/указатель. – karlitos

+0

Вы можете просто сохранить текущее состояние трансфокации/трансляции каждый раз, когда функция что-то делает, а затем возобновить ее с помощью переназначения при повторном подключении зума. –

+0

Вот что я пытался достичь ... Не могли бы вы предоставить более подробную информацию о том, как достичь этого с помощью dr.js? – karlitos

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), даже если вы не изменяете представление.

+0

Благодарим вас за предложение. Проблема в том, что в моем проекте я не назначаю поведение масштабирования из метода on ('click', ...). Функция redrawOnZomm() должна вести себя в соответствии с состоянием (цветом) круга. – karlitos

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.

+2

Это все еще работает только для масштабирования, для перевода все еще есть неустойчивое поведение, если вы перетаскиваете круг во время его отключения, снова включаете его и снова перетаскиваете. – TheONP

1

Я думаю, что более красиво это делать.

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 + ')'); 
    } 

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

Я хотел догнать это, когда нашел решение! Trick - это сброс масштаба и перевод в события масштабирования и масштабирования.

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

Самый простой способ я нашел, чтобы просто отключить все .zoom события на отборе. Вам нужно будет повторно позвонить zoom, чтобы снова включить поведение.

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

jsfiddle

Смежные вопросы