Javascript 如何暂时禁用d3.js中的缩放功能
我正在寻找暂时禁用d3库提供的缩放功能的可能性。我尝试在禁用缩放时保存当前缩放/平移值,并在再次激活缩放时设置缩放/平移值。不幸的是,这行不通 下面是我创建的一个代码示例:Javascript 如何暂时禁用d3.js中的缩放功能,javascript,svg,d3.js,zooming,behavior,Javascript,Svg,D3.js,Zooming,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 cir
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()
}
};
这是一个
编辑:
可通过以下步骤再现错误行为:
我实现这一点的方法是使用一个全局标志,告诉您是否启用了缩放。然后,您只需检查是否在处理缩放的函数中设置了此标志。如果是,则该函数不执行任何操作。请参阅更新的小提琴: 在这里,我在单击处理程序中重新分配了一个空的缩放行为
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
),因此您不必保存和检查缩放和平移值。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();
}
现在它工作了!
我认为这样做更漂亮
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 + ')');
}
};
我一直在努力解决同样的问题。而且,我找到了一个解决方案,它可以节省缩放和平移,而不会像当前解决方案那样出现跳跃 主要更改是在“单击”功能中执行缩放和平移的保存/更新。为了使缩放功能的引用可用,必须在缩放行为之后设置单击。解决方案如下所示。与您的问题相同的样板文件:
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;
}
}
};
以下是一个工作版本:
但是,当发生拖动时,单击事件仍然会发生,这似乎不太理想,但我还没能解决它。我想在找到解决方案时赶上这个进度! 诀窍是在zoomstart和ZoomMend事件中重置缩放和平移
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();
}
}
}
我发现的最简单的方法是简单地禁用选择上的所有
.zoom
事件。您必须重新调用zoom
以再次启用该行为
if (zoomEnabled) {
svg.call(zoom);
} else {
svg.on('.zoom', null);
}
const svg=d3.select(svgElement);
const zoom=d3.zoom();
函数startZoomPan(){
调用(缩放);//附加缩放侦听器
}
函数stopZoomPan(){
svg.on('.zoom',null);//删除缩放侦听器
}
mousemove处理程序是热代码,因此分支速度很慢谢谢您的建议。问题是,在我的项目中,我没有通过on('click',…)方法指定缩放行为。redrawOnZomm()函数应该根据圆的状态(颜色)进行操作。但是,我应该如何实现该函数“不做任何事情”,但我可以在某个点上重新启用缩放,并从我禁用它的点开始继续?我在可视化过程中出现了跳跃/移动,因为事件仍然会在鼠标滚轮/指针上做出反应。每次函数执行某项操作时,您只需保存缩放/平移的当前状态,然后在重新启用缩放时重新指定即可恢复。这就是我试图实现的。。。请您提供如何使用dr.js实现这一点的更详细信息?您可以在每次执行缩放功能时将
zoom.translate
和zoom.scale
的值保存在全局变量中,但如果禁用了缩放功能,则不会保存。然后,当重新启用缩放时,将这些值分配回缩放行为。这不是我在示例中所做的吗?问题是,缩放始终与鼠标滚轮/指针交互,因此d3.event.scale/translate值也会更改。我的问题是重新启用缩放后如何将这些值设置/还原为保存的值。显然,zoom.scale(savedScale)/zoom.translate(savedtransation)不起作用。这仍然只适用于缩放,对于平移,如果在禁用时拖动圆,重新启用它,然后再次拖动它,仍然会出现跳跃行为。zoomstart和ZoomMend事件已在最新版本之一中重命名为start和end