d3 - 单击时触发拖动行为
d3 - drag behaviour triggered when clicking
在我的 svg 容器中,我有一个带有矩形和文本的 <g>
。拖动这个组时,我想让这个组消失,只需要在屏幕上拖一个小矩形来代表这个对象。为此,我使用了一个 <div>
,它在拖动开始时可见。我让我的 svg 组被拖动消失。
可以看到fiddlehere。
并在此处编码:
function dragDiv2End(d) {
console.log('ending');
var a = d3.select(this);
a.attr('x', initial.x).attr('y', initial.y).attr('width', initial.width).attr('height', initial.height);
a.transition().style("opacity",1);
d3.select('#dragid').style('visibility', 'hidden');
}
function dragDiv2Start(d) {
d3.event.sourceEvent.stopPropagation();
console.log('starting');
var a = d3.select(this);
initial = {x: a.attr('x'), y: a.attr('y'), width: a.attr('width'), height: a.attr('height')};
a.attr('x', d3.mouse(this)[0])
.attr('y', d3.mouse(this)[1]) .attr('width', 20)
.attr('height', 20).style("opacity",0);
var b = d3.select('#dragid');
b.style({
left: (parseInt(d3.mouse(this)[0])) + "px",
top: d3.mouse(this)[1] + "px",
border: "1px solid black",
visibility: 'visible'
});
}
function dragDiv2Move(d) {
var b = d3.select(this);
var a = d3.select('#dragid');
a.transition().delay(50).style('opacity', 1);
//console.log(d3.event.x, d3.event.y, a.style("right"));
console.log(d3.mouse(this));
a.style({
left: (parseInt(d3.mouse(this)[0])) + "px",
top: d3.mouse(this)[1] + "px"
});
}
function doClick(d) {
if (d3.event.defaultPrevented) return;
console.log('clicked');
}
var initial = {};
var svg = d3.select('#div2').append('svg').attr('height', 300).attr('width', 300).style('border', 'solid 1px blue');
var g = svg.append('g').on('click', doClick);
g.append('rect').attr('x', 10).attr('y', 10).attr('width', 200).attr('height', 200).style('stroke', 'red').style('fill', 'white');
var text = g.append('text')
text.text('my test').attr('x', 50).attr('y', 50);
var dragDiv = d3.behavior.drag()
.origin(Object)
.on("drag", dragDivMove);
var dragDiv2 = d3.behavior.drag()
.origin(Object)
.on("dragstart", dragDiv2Start)
.on("drag", dragDiv2Move)
.on("dragend", dragDiv2End);
g.call(dragDiv2);
问题始于该组也应收听的单击事件。当发生简单的单击时,我的 svg 对象消失(拖动事件的行为)时,我得到了这种闪烁效果。
我明白为什么会这样,但这是非常不受欢迎的,我正在努力寻找解决这个问题的方法。要查看它的发生,只需单击 and/or 拖动红色矩形。
我尝试阻止事件传播,从拖动到点击效果很好,但反之则不然。
任何建议将不胜感激。
我稍微清理了您的代码并在此 SO 代码片段中使用了 'Tidy' 效果。格式化 synatx..
首先,在您的 Start 和 Move 函数中。我正在创建一个变量对象来保存 d3.mouse(this)
数据。 (即 var currentPosition = {"x" : d3.mouse(this)[0], "y" : d3.mouse(this)[1]};
)。
我正在做的是添加一个阈值并将其与距离相关联。在将 dragStart 方法包装在匿名函数中之后,我调用了它。这允许我获取 this
实例以及 thresholdValue
,并将其绑定到我正在调用的 dragStart。
var dragDiv2 = d3.behavior.drag()
.origin(Object)
.on("dragstart", function(arg) {
console.log("anonymous function - arg: %o", arg);
dragDiv2Start.bind(this.children[0], 5)();
})
.on("drag", dragDiv2Move)
.on("dragend", dragDiv2End);
然而, this
实际上是元素 g
.. 它没有设置任何属性,所以我得到第一个child - 即 rect
-,并将其绑定到 dragStart 方法。
我创建了一个名为 'threshold' 的对象变量,它在 [=58] 中分配了 min.x
、min.y
、max.x
和 max.y
值=]dragStart 函数。我还设置了一个标志 - 称为 IsNeeded
指示 dragMove 函数是否应检查阈值,并有条件地 return 或应用视觉更改.. dragEnd 将简单地 return 如果 IsNeeded
是 'still' 真;
我将你的视觉样式从 dragStart 移动到 dragMove,我当时只 运行 它 threshold.isNeeded
设置为 false
.
示例代码片段
function dragDivMove(d) {
var a = d3.select(this);
var data = {
"event": {
"dx": parseInt(d3.event.dx),
"dy": parseInt(d3.event.dy)
},
select: {
"right": parseInt(a.style("right").replace("px", "")),
"top": parseInt(a.style("top").replace("px", ""))
}
};
console.log(data);
a.style({
"right": (data.select.right - data.event.dx) + "px",
"top": (data.event.dy + data.select.top) + "px"
});
}
function dragDiv2End(d) {
console.log('ending');
var a = d3.select(this);
var b = d3.select('#dragid');
a.attr('x', initial.x)
.attr('y', initial.y)
.attr('width', initial.width)
.attr('height', initial.height);
a.transition().style("opacity", 1);
b.style('visibility', 'hidden');
}
function dragDiv2Start(thresholdValue) {
d3.event.sourceEvent.stopPropagation();
var a = d3.select(this);
console.log('starting - this: %o , d3.select(this): %o, thresholdValue: %o', this, a, thresholdValue);
initial = {
"x": parseInt(a.attr('x').replace("px",0)),
"y": parseInt(a.attr('y').replace("px",0)),
"width": parseInt(a.attr('width').replace("px","")),
"height": parseInt(a.attr('height').replace("px",""))
};
threshold.min = {
"x": initial.x - thresholdValue,
"y": initial.y - thresholdValue
};
threshold.max = {
"x": initial.x + thresholdValue,
"y": initial.y + thresholdValue
};
threshold.isNeeded = true;
var currentPosition = {
"x": d3.mouse(this)[0],
"y": d3.mouse(this)[1]
};
console.log("current: %o, initial: %o, threshold: %o", currentPosition, initial, threshold);
}
function dragDiv2Move(d) {
var a = d3.select('#dragid');
var b = d3.select(this);
var currentPosition = {
"x": d3.mouse(this)[0],
"y": d3.mouse(this)[1]
};
if (threshold.isNeeded) {
if (threshold.min.x < currentPosition.x || threshold.min.y < currentPosition.y || threshold.max.x > currentPosition.x || threshold.max.y > currentPosition.y) {
threshold.isNeeded = false;
b.attr('x', currentPosition.x);
b.attr('y', currentPosition.y);
b.attr('width', 20);
b.attr('height', 20);
b.style("opacity", 0);
a.style({
"left" : currentPosition.x + "px",
"top" : currentPosition.y + "px",
"border" : "1px solid black",
"visibility" : 'visible'
});
} else {
return;
}
}
console.log(currentPosition);
a.transition().delay(50).style('opacity', 1);
a.style({
"left" : currentPosition.x + "px",
"top" : currentPosition.y + "px"
});
}
function doClick(d) {
if (d3.event.defaultPrevented) return;
console.log('clicked');
}
var initial = {},
threshold = {
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 0,
"y": 0
},
"isNeeded": true
};
var svg = d3.select('#div2').append('svg').attr('height', 300).attr('width', 300).style('border', 'solid 1px blue');
var g = svg.append('g').on('click', doClick);
g.append('rect').attr('x', 10).attr('y', 10).attr('width', 200).attr('height', 200).style('stroke', 'red').style('fill', 'white');
var text = g.append('text')
text.text('my test').attr('x', 50).attr('y', 50);
var dragDiv = d3.behavior.drag()
.origin(Object)
.on("drag", dragDivMove);
var dragDiv2 = d3.behavior.drag()
.origin(Object)
.on("dragstart", function() {
dragDiv2Start.bind(this.children[0], 5)();
})
.on("drag", dragDiv2Move)
.on("dragend", dragDiv2End);
g.call(dragDiv2);
//d3.select('#dragid').call(dragDiv);
#dragid {
background-color: lightblue;
position: absolute;
top: 0px;
left: 0px;
width: 5px;
height: 5px;
visibility: hidden
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="dragid">
<span></span>
</div>
<div id="div2"></div>
注意:公式有误。 g > rect
的初始值正在与 dragMove 中鼠标的后续 currentPosition
值进行比较。应该是 currentPosition
dragStart 中鼠标的值将与 dragMove..
中鼠标的后续 currentPosition
值进行比较
无论如何,值得注意的是 dragMove 不会触发,除非您实际按下鼠标键进行拖动。这就是视觉效果不闪烁的原因;即使在当前实现中,isNeeded
计算总是在 dragMove..
中得到满足
在我的 svg 容器中,我有一个带有矩形和文本的 <g>
。拖动这个组时,我想让这个组消失,只需要在屏幕上拖一个小矩形来代表这个对象。为此,我使用了一个 <div>
,它在拖动开始时可见。我让我的 svg 组被拖动消失。
可以看到fiddlehere。 并在此处编码:
function dragDiv2End(d) {
console.log('ending');
var a = d3.select(this);
a.attr('x', initial.x).attr('y', initial.y).attr('width', initial.width).attr('height', initial.height);
a.transition().style("opacity",1);
d3.select('#dragid').style('visibility', 'hidden');
}
function dragDiv2Start(d) {
d3.event.sourceEvent.stopPropagation();
console.log('starting');
var a = d3.select(this);
initial = {x: a.attr('x'), y: a.attr('y'), width: a.attr('width'), height: a.attr('height')};
a.attr('x', d3.mouse(this)[0])
.attr('y', d3.mouse(this)[1]) .attr('width', 20)
.attr('height', 20).style("opacity",0);
var b = d3.select('#dragid');
b.style({
left: (parseInt(d3.mouse(this)[0])) + "px",
top: d3.mouse(this)[1] + "px",
border: "1px solid black",
visibility: 'visible'
});
}
function dragDiv2Move(d) {
var b = d3.select(this);
var a = d3.select('#dragid');
a.transition().delay(50).style('opacity', 1);
//console.log(d3.event.x, d3.event.y, a.style("right"));
console.log(d3.mouse(this));
a.style({
left: (parseInt(d3.mouse(this)[0])) + "px",
top: d3.mouse(this)[1] + "px"
});
}
function doClick(d) {
if (d3.event.defaultPrevented) return;
console.log('clicked');
}
var initial = {};
var svg = d3.select('#div2').append('svg').attr('height', 300).attr('width', 300).style('border', 'solid 1px blue');
var g = svg.append('g').on('click', doClick);
g.append('rect').attr('x', 10).attr('y', 10).attr('width', 200).attr('height', 200).style('stroke', 'red').style('fill', 'white');
var text = g.append('text')
text.text('my test').attr('x', 50).attr('y', 50);
var dragDiv = d3.behavior.drag()
.origin(Object)
.on("drag", dragDivMove);
var dragDiv2 = d3.behavior.drag()
.origin(Object)
.on("dragstart", dragDiv2Start)
.on("drag", dragDiv2Move)
.on("dragend", dragDiv2End);
g.call(dragDiv2);
问题始于该组也应收听的单击事件。当发生简单的单击时,我的 svg 对象消失(拖动事件的行为)时,我得到了这种闪烁效果。
我明白为什么会这样,但这是非常不受欢迎的,我正在努力寻找解决这个问题的方法。要查看它的发生,只需单击 and/or 拖动红色矩形。
我尝试阻止事件传播,从拖动到点击效果很好,但反之则不然。
任何建议将不胜感激。
我稍微清理了您的代码并在此 SO 代码片段中使用了 'Tidy' 效果。格式化 synatx..
首先,在您的 Start 和 Move 函数中。我正在创建一个变量对象来保存 d3.mouse(this)
数据。 (即 var currentPosition = {"x" : d3.mouse(this)[0], "y" : d3.mouse(this)[1]};
)。
我正在做的是添加一个阈值并将其与距离相关联。在将 dragStart 方法包装在匿名函数中之后,我调用了它。这允许我获取 this
实例以及 thresholdValue
,并将其绑定到我正在调用的 dragStart。
var dragDiv2 = d3.behavior.drag()
.origin(Object)
.on("dragstart", function(arg) {
console.log("anonymous function - arg: %o", arg);
dragDiv2Start.bind(this.children[0], 5)();
})
.on("drag", dragDiv2Move)
.on("dragend", dragDiv2End);
然而, this
实际上是元素 g
.. 它没有设置任何属性,所以我得到第一个child - 即 rect
-,并将其绑定到 dragStart 方法。
我创建了一个名为 'threshold' 的对象变量,它在 [=58] 中分配了 min.x
、min.y
、max.x
和 max.y
值=]dragStart 函数。我还设置了一个标志 - 称为 IsNeeded
指示 dragMove 函数是否应检查阈值,并有条件地 return 或应用视觉更改.. dragEnd 将简单地 return 如果 IsNeeded
是 'still' 真;
我将你的视觉样式从 dragStart 移动到 dragMove,我当时只 运行 它 threshold.isNeeded
设置为 false
.
示例代码片段
function dragDivMove(d) {
var a = d3.select(this);
var data = {
"event": {
"dx": parseInt(d3.event.dx),
"dy": parseInt(d3.event.dy)
},
select: {
"right": parseInt(a.style("right").replace("px", "")),
"top": parseInt(a.style("top").replace("px", ""))
}
};
console.log(data);
a.style({
"right": (data.select.right - data.event.dx) + "px",
"top": (data.event.dy + data.select.top) + "px"
});
}
function dragDiv2End(d) {
console.log('ending');
var a = d3.select(this);
var b = d3.select('#dragid');
a.attr('x', initial.x)
.attr('y', initial.y)
.attr('width', initial.width)
.attr('height', initial.height);
a.transition().style("opacity", 1);
b.style('visibility', 'hidden');
}
function dragDiv2Start(thresholdValue) {
d3.event.sourceEvent.stopPropagation();
var a = d3.select(this);
console.log('starting - this: %o , d3.select(this): %o, thresholdValue: %o', this, a, thresholdValue);
initial = {
"x": parseInt(a.attr('x').replace("px",0)),
"y": parseInt(a.attr('y').replace("px",0)),
"width": parseInt(a.attr('width').replace("px","")),
"height": parseInt(a.attr('height').replace("px",""))
};
threshold.min = {
"x": initial.x - thresholdValue,
"y": initial.y - thresholdValue
};
threshold.max = {
"x": initial.x + thresholdValue,
"y": initial.y + thresholdValue
};
threshold.isNeeded = true;
var currentPosition = {
"x": d3.mouse(this)[0],
"y": d3.mouse(this)[1]
};
console.log("current: %o, initial: %o, threshold: %o", currentPosition, initial, threshold);
}
function dragDiv2Move(d) {
var a = d3.select('#dragid');
var b = d3.select(this);
var currentPosition = {
"x": d3.mouse(this)[0],
"y": d3.mouse(this)[1]
};
if (threshold.isNeeded) {
if (threshold.min.x < currentPosition.x || threshold.min.y < currentPosition.y || threshold.max.x > currentPosition.x || threshold.max.y > currentPosition.y) {
threshold.isNeeded = false;
b.attr('x', currentPosition.x);
b.attr('y', currentPosition.y);
b.attr('width', 20);
b.attr('height', 20);
b.style("opacity", 0);
a.style({
"left" : currentPosition.x + "px",
"top" : currentPosition.y + "px",
"border" : "1px solid black",
"visibility" : 'visible'
});
} else {
return;
}
}
console.log(currentPosition);
a.transition().delay(50).style('opacity', 1);
a.style({
"left" : currentPosition.x + "px",
"top" : currentPosition.y + "px"
});
}
function doClick(d) {
if (d3.event.defaultPrevented) return;
console.log('clicked');
}
var initial = {},
threshold = {
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 0,
"y": 0
},
"isNeeded": true
};
var svg = d3.select('#div2').append('svg').attr('height', 300).attr('width', 300).style('border', 'solid 1px blue');
var g = svg.append('g').on('click', doClick);
g.append('rect').attr('x', 10).attr('y', 10).attr('width', 200).attr('height', 200).style('stroke', 'red').style('fill', 'white');
var text = g.append('text')
text.text('my test').attr('x', 50).attr('y', 50);
var dragDiv = d3.behavior.drag()
.origin(Object)
.on("drag", dragDivMove);
var dragDiv2 = d3.behavior.drag()
.origin(Object)
.on("dragstart", function() {
dragDiv2Start.bind(this.children[0], 5)();
})
.on("drag", dragDiv2Move)
.on("dragend", dragDiv2End);
g.call(dragDiv2);
//d3.select('#dragid').call(dragDiv);
#dragid {
background-color: lightblue;
position: absolute;
top: 0px;
left: 0px;
width: 5px;
height: 5px;
visibility: hidden
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="dragid">
<span></span>
</div>
<div id="div2"></div>
注意:公式有误。 g > rect
的初始值正在与 dragMove 中鼠标的后续 currentPosition
值进行比较。应该是 currentPosition
dragStart 中鼠标的值将与 dragMove..
currentPosition
值进行比较
无论如何,值得注意的是 dragMove 不会触发,除非您实际按下鼠标键进行拖动。这就是视觉效果不闪烁的原因;即使在当前实现中,isNeeded
计算总是在 dragMove..