D3.js v7.4.0 drag的on事件回调仅单参数 如何实现SVG圆形拖拽
问题根源
D3-drag事件回调的第二个参数d,是挂载在对应DOM元素上的绑定数据(datum),并非事件默认携带的属性。你的代码没有给圆形元素绑定初始坐标类的datum,所以拿到undefined,不属于API和文档描述不符的情况。
另外你当前仅绑定了start事件,只会在鼠标按下的瞬间触发一次,无法实现拖拽过程中元素实时跟随鼠标的效果。
可直接运行的实现方案
方案1:对齐官方示例逻辑(绑定datum)
先给元素绑定初始坐标作为datum,拖拽过程中直接更新datum值、同步到DOM属性即可,是官方推荐的写法:
this.player = this.container .append("circle") // 绑定初始坐标数据到元素 .datum({ x: 1000, y: 1000 }) .attr("cx", d => d.x) .attr("cy", d => d.y) .attr("r", 20) .attr("fill", "pink") .call( d3.drag<SVGCircleElement, { x: number; y: number }>() .on("start", function () { // 拖拽开始时可按需添加抬升层级、修改高亮样式等逻辑 d3.select(this).raise(); }) .on("drag", function (event, d) { // 拖拽时实时更新绑定数据,同步修改元素坐标 d3.select(this) .attr("cx", d.x = event.x) .attr("cy", d.y = event.y); }) .on("end", function () { // 拖拽结束回调,可按需添加落位、校验等逻辑 }) );
方案2:不绑定datum,通过偏移量计算
如果不想额外维护datum,可以在拖拽开始时记录鼠标位置和元素当前坐标的偏移量,拖拽过程中计算新坐标:
// 缓存拖拽偏移值 const offset = { dx: 0, dy: 0 }; this.player = this.container .append("circle") .attr("cx", 1000) .attr("cy", 1000) .attr("r", 20) .attr("fill", "pink") .call( d3.drag<SVGCircleElement, unknown>() .on("start", function (event) { const el = d3.select(this); const cx = Number(el.attr("cx")); const cy = Number(el.attr("cy")); // 记录按下瞬间的坐标差值 offset.dx = cx - event.x; offset.dy = cy - event.y; el.raise(); }) .on("drag", function (event) { // 实时计算新坐标 d3.select(this) .attr("cx", event.x + offset.dx) .attr("cy", event.y + offset.dy); }) );
避坑提示
- 事件回调不要用箭头函数,否则
this不会指向当前触发事件的DOM元素,会导致选不到目标元素。 - 不要直接用原生
DragEvent作为d3.drag的泛型参数,d3的drag事件是封装后的自定义事件,自带的event.x/event.y已经做过SVG坐标系转换,直接使用即可。
内容的提问来源于stack exchange,提问作者reactor
相关产品推荐
相关产品推荐

