我创建了D3树。拖放功能适用于台式机和笔记本电脑。 D3中是否有拖放功能支持触摸设备?
D3参考站点 - http://bl.ocks.org/robschmuecker/7880033具有相同的触控设备版本,拖放功能无法使用此代码
var nodeEnter = node.enter().append("g").call(dragListener).attr(
"class", "node").attr("transform", function(d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
}).on("mouseenter", nodeMouseover).on("mouseleave", node_onMouseOut)
.on('click', click).attr('id', function(d) {
return d.nodeId;
});
dragListener = d3.behavior.drag()
.on("dragstart", function(d) {
if (d == root) {
return;
}
dragStarted = true;
nodes = tree.nodes(d);
d3.event.sourceEvent.stopPropagation();
// it's important that we suppress the mouseover event on the node being dragged. Otherwise it will absorb the mouseover event and the underlying node will not detect it d3.select(this).attr('pointer-events', 'none');
})
.on("drag", function(d) {
if (d == root) {
return;
}
if (dragStarted) {
domNode = this;
initiateDrag(d, domNode);
}
// get coords of mouseEvent relative to svg container to allow for panning
relCoords = d3.mouse($('svg').get(0));
if (relCoords[0] < panBoundary) {
panTimer = true;
pan(this, 'left');
} else if (relCoords[0] > ($('svg').width() - panBoundary)) {
panTimer = true;
pan(this, 'right');
} else if (relCoords[1] < panBoundary) {
panTimer = true;
pan(this, 'up');
} else if (relCoords[1] > ($('svg').height() - panBoundary)) {
panTimer = true;
pan(this, 'down');
} else {
try {
clearTimeout(panTimer);
} catch (e) {
}
}
d.x0 += d3.event.dy;
d.y0 += d3.event.dx;
var node = d3.select(this);
node.attr("transform", "translate(" + d.y0 + "," + d.x0 + ")");
updateTempConnector();
}).on("dragend", function(d) {
if (d == root) {
return;
}
domNode = this;
if (selectedNode) {
// now remove the element from the parent, and insert it into the new elements children
var index = draggingNode.parent.children.indexOf(draggingNode);
if (index > -1) {
draggingNode.parent.children.splice(index, 1);
}
if (typeof selectedNode.children !== 'undefined' || typeof selectedNode._children !== 'undefined') {
if (typeof selectedNode.children !== 'undefined') {
selectedNode.children.push(draggingNode);
} else {
selectedNode._children.push(draggingNode);
}
} else {
selectedNode.children = [];
selectedNode.children.push(draggingNode);
}
// Make sure that the node being added to is expanded so user can see added node is correctly moved
expand(selectedNode);
sortTree();
endDrag();
} else {
endDrag();
}
});
答案 0 :(得分:2)
Drag
行为支持点击和触摸,但在您给出的示例中,放置的位置由mousover
事件给出:
// phantom node to give us mouseover in a radius around it
nodeEnter.append("circle")
.attr('class', 'ghostCircle')
.attr("r", 30)
.attr("opacity", 0.2) // change this to zero to hide the target area
.style("fill", "red")
.attr('pointer-events', 'mouseover')
.on("mouseover", function(node) {
overCircle(node);
})
.on("mouseout", function(node) {
outCircle(node);
});
此mouseover
事件不会在触控设备上触发。
您可以做的是删除ghostCircles,并在事件&#34;中拖动&#34;,在updateTempConnector()
之前手动执行计算。
我可以提出类似的建议:
var draggedNode = d;
var nodes = d3.selectAll("g.node")
.filter(function (d, i) {
if ((d.id != draggedNode.id) && (!isChildOf(draggedNode, d))) {
return d;
}
return 0;
});
var distances = [];
nodes.each(function (d, i) {
var distanceX = draggedNode.x0 - d.x;
var distanceY = draggedNode.y0 - d.y;
var distance = Math.sqrt( Math.pow(distanceX, 2) + Math.pow(distanceY, 2) );
distances.push({
distance: distance,
distanceV: distanceX, // vertical, <0 when draggedNode is above
distanceH: distanceY, // horizontal, <0 when draggedNode is on the left
d: d
});
});
// sort by shorter distances
distances.sort(function (a, b) {
return a.distance - b.distance;
});
selectedNode = distances[0].d;
这将选择(作为未来父节点)最接近被拖动节点的节点。
答案 1 :(得分:1)
对于http://bl.ocks.org/robschmuecker/7880033示例,我通过执行以下两项操作解决了这个问题:
首先:在你的&#34;拖动&#34;触发updateTempConnector之前的事件添加:
if ('ontouchstart' in window) {
goalView.selectedNode = closestNode(d);
}
第二:然后定义以下函数:
var closestNode = function(d){
var ghostCircleRadius = 30;
var nodes = tree.nodes(goalView.rootNode).reverse();
var minDistance = 100000000; //sufficiently large number
var returnNode = null;
for (var i = 0; i < nodes.length; i++) {
var distance = (nodes[i].x0 - d.x0)*(nodes[i].x0 - d.x0) + (nodes[i].y0 - d.y0)*(nodes[i].y0 - d.y0);
if (distance > 0){
if (distance < minDistance && distance < ghostCircleRadius*ghostCircleRadius) {
minDistance = distance;
returnNode = nodes[i];
}
}
}
return returnNode;
};
这基本上会检查最近的节点,并检查我们的draggingNode是否在nearestNode的鬼圈半径范围内。
答案 2 :(得分:0)
D3 Drag Behavior自动创建事件侦听器以处理元素上的拖动手势。支持鼠标事件和触摸事件。
注意:确保您使用的是最新版本的D3