创建一个可拖动的圆展示d3.drag的使用

首先创建svg容器和一个circle元素:

const width = window.innerWidth
const height = window.innerHeight

const svg = d3.select('body')
    .append('svg')
    .attr('width', width)
    .attr('height', height)
    .append('g')
    .attr('transform', `translate(${ width / 2 }, ${ height / 2 })`)

const circle = svg.append('circle')
    .attr('r', 40)
    .attr('fill', 'red')

监听拖动事件需要先使用d3.drag模块创建一个拖动事件,然后绑定到特定的元素上。

const drag = d3.drag()
// 调用 call是手动调用函数并将选择集作为第一个参数
selection.call(drag)
// 或者
drag( selection )

一次拖动事件你可以定义三个阶段的监听函数:

d3.drag()
    .on('start', dragStart) // 拖动开始,触发一次
    .on('drag', draged) // 拖动中,触发多次
    .on('end', dragEnd) // 拖动结束,触发一次

我们通过draged函数设置circle元素的cx,cy属性实现拖动:

const drag = d3.drag()
    .on('start', () => {})
    .on('end', () => {})
    .on('drag', draged)
    
circle.call(drag) // 绑定

function draged() {
    const {
        x,
        y
    } = d3.event
    d3.select(this)
        .attr('cx', x)
        .attr('cy', y)
}

鼠标位置通过d3.event对象访问到,完整的d3.event属性:

{
    "type": "drag", // 分别是三个阶段对应的 start drag end
    "subject": { "x":12.5, "y":-11.5 },
    "identifier": "mouse",
    "active": 1, // start,end为0  drag阶段为1
    "x": -30.5, // 鼠标位置
    "y": -42.5,
    "dx": -6, // 相对于上次drag的x,y坐标变化
    "dy": -6,
    "sourceEvent": MouseEvent(...) // 浏览器原生事件
}

鼠标位置x,y的相对元素可以通过drag.container修改,默认是事件源的父元素:

drag.container(function container() {
  return this.parentNode
})

d3.event.subject则表示拖拽的主体,默认是事件源上绑定的数据,否则为start阶段的x,y坐标,它的作用是利用它在拖动期间访问主体和指针的相对位置,所以它应该是不可变的。

完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script>
        const width = window.innerWidth
        const height = window.innerHeight
        const svg = d3.select('body')
            .append('svg')
            .attr('width', width)
            .attr('height', height)
            .append('g')
            .attr('transform', `translate(${ width / 2 }, ${ height / 2 })`)
            
        svg.attr('stroke', 'red')
        
        const circle = svg.append('circle')
            .attr('r', 40)
            .attr('fill', 'red')
            .call(
                d3.drag()
                    .on('start', () => {})
                    .on('end', () => {})
                    .on('drag', draged)
            )

        function draged() {
            const {
                x,
                y
            } = d3.event
            d3.select(this)
                .attr('cx', x)
                .attr('cy', y)
        }
    </script>
</body>
</html>
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐