javascript 如何暂时禁用 d3.js 中的缩放
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18788188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to temporarily disable the zooming in d3.js
提问by karlitos
I am searching for a possibility to temporarily disable the zooming functionality provided by the d3 library. I tried to save the cave the current scale/translation values when the zooming is deactivated and set the zoom/translate-values when the zooming is active again. Unfortunately this will not work.
我正在寻找暂时禁用 d3 库提供的缩放功能的可能性。我尝试在禁用缩放时保存洞穴当前的比例/平移值,并在再次激活缩放时设置缩放/平移值。不幸的是,这行不通。
Here is a code example I created :
这是我创建的代码示例:
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()
}
};
Here is a working jsfiddle example.
这是一个有效的 jsfiddle 示例。
EDIT:
编辑:
The false behavior can be reproduced by following steps :
可以通过以下步骤重现错误行为:
- Click on the circle, the color changes to blue,zooming is not working
- Use mouse wheel IN ONE DIRECTION several times as if you would be zooming (e.g. zoom in)
- Click again on the circle, the color chnages to red, zoom is re-enabled
- Use mouse wheel, the circle will be huge/tiny
- 点击圆圈,颜色变为蓝色,缩放不起作用
- 在一个方向上多次使用鼠标滚轮,就像您要放大一样(例如放大)
- 再次点击圆圈,颜色变为红色,重新启用缩放
- 使用鼠标滚轮,圆圈会很大/很小
回答by hughes
回答by Zak King
I have been struggling with the same problem. And, I have found a solution that saves zoom and translation without the jumpiness that you see with the current solution.
我一直在努力解决同样的问题。而且,我找到了一种解决方案,可以节省缩放和平移,而不会出现您在当前解决方案中看到的跳跃感。
The main change is to perform the saving/updating of zoom and translate in the "click" function. And so that a reference to the zoom function is available, the click must be set after the zoom behavior. The solution looks like this. The same boilerplate from your problem:
主要的变化是在“点击”功能中执行缩放和翻译的保存/更新。并且为了提供对缩放功能的引用,必须在缩放行为之后设置单击。解决方案如下所示。来自您的问题的相同样板:
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');
Then the zoom function, without managing the saved scale and translate:
然后是缩放功能,无需管理保存的比例和平移:
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() + ')');
}
};
Finally, attach the click behavior below, with the saving and setting of scale and translation:
最后附上下面的点击行为,以及缩放和平移的保存和设置:
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;
}
}
};
Here is a working version: http://jsfiddle.net/cb3Zm/1/.
这是一个工作版本:http: //jsfiddle.net/cb3Zm/1/。
However, the click event still happens when a drag occurs, and that doesn't seem ideal, but I haven't been able to fix it yet.
但是,在发生拖动时仍然会发生单击事件,这似乎并不理想,但我还没有修复它。
回答by Roland Jee
I wanted to catch up on this as I found a solution! Trick is to reset scale and translate in the zoomstart- and zoomend-events as well.
我想赶上这个,因为我找到了解决方案!技巧是在 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();
}
}
}
回答by prayerslayer
See the updated fiddle: http://jsfiddle.net/prayerslayer/La8PR/1/
查看更新的小提琴:http: //jsfiddle.net/prayerslayer/La8PR/1/
There I reassign an empty zoom behavior in the click handler.
在那里,我在点击处理程序中重新分配了一个空的缩放行为。
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 );
}
};
I suppose there is a better solution as mine probably introduces memory leaks.
我想有一个更好的解决方案,因为我的可能会引入内存泄漏。
The advantage over a global doZoom
flag is that you don't have to save and check scale and translation values because the zoom behavior continues to work (e.g. setting d3.event.scale
) even though you're not altering the view.
与全局doZoom
标志相比的优势在于您不必保存和检查比例和平移值,因为d3.event.scale
即使您没有改变视图,缩放行为也会继续工作(例如设置)。
回答by karlitos
Yabba Dabba Doo!
雅巴达巴杜!
Ok, the problem was in the
好的,问题出在
else {
// save the current scales
savedScale = zoom.scale()
savedTranslation = zoom.translate()
}
part. The values were called on every event, not only once after the circle changed its color. So the solution was:
部分。每个事件都会调用这些值,而不仅仅是在圆圈更改颜色后调用一次。所以解决方案是:
else {
// save the current scales
if (savedScale === null){
savedScale = zoom.scale();
}
if (savedTranslation === null){
savedTranslation = zoom.translate();
}
and now IT WORKS ! Updated jsFiddle here.
现在可以了! 在这里更新了 jsFiddle。
回答by Lars Kotthoff
The way I would implement this is with a global flag that tells you whether zooming is enabled or not. Then you simply need to check whether this flag is set in the function that handles the zoom. If it is, the function does nothing.
我实现这一点的方法是使用一个全局标志来告诉您是否启用了缩放。然后您只需检查是否在处理缩放的函数中设置了此标志。如果是,则该函数不执行任何操作。
回答by sadofwind
I think it's more beautiful to do it this way.
我认为这样做更漂亮。
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 + ')');
}
};