d3代码如何改造成update结构(恰当处理enter和exit)

d3的enter和exit

网上有很多blog讲解。说的还凑合的见:https://blog.csdn.net/nicolecc/article/details/50786661

如何把自己的rude绘图代码,进行精致化(update)

 不多比比,上代码示例:

d3.selectAll('.circle_group').children().remove();
var circle_group = d3.selectAll('.circle_group')
    .data(circleData)
    .enter().append('g')
    .attr('class', 'circle_group brushNode')
    .attr('transform',
        function (d) {
            return 'translate(' + d.x + ',' + d.y + ')';
        })
    .on('click', function (d) {
        if (shiftKey) {
            //标记当前点
            d3.select(this).classed("selected", function (d) {

                d.selected = !d.selected;
                d.previouslySelected = !d.selected;
                return d.selected;
            })

            //阻止事件冒泡
            d3.event.stopPropagation();
        }
    })
    .on("contextmenu", function (node) {
        contextmenu("Rmenu");
    })

circle_group.append('circle')
    .attr('r', function (d) {
        return d.r;
    })
    .style("fill", function (d) {
        return color20(d.index);
    })

;
circle_group.append('text')
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")//在圆圈中加上数据
    .style('fill', function (node) {
        return '#555';
    })
    .attr("y", -7)
    .text(d => d.text);

circle_group.call(d3.drag()
//定义了元素拖拽行为的原点,设置为圆的圆心位置可以避免明显的元素跳动, 与d3v3中的origin方法类似。
    .subject(function () {
        var thisData = d3.select(this);
        return {
            x: thisData.datum().x,
            y: thisData.datum().y
        };
    })
    .on("start", dragstarted)
    .on("drag", dragmove)
    .on("end", dragended));

 很明显,新手图省事都是这么绘图的。就绘图结果来看,如果你不加动画一点问题都没有,只要一加动画过渡动画,所有的图形都是从无到有的过程,而我们想看的是,如果点更新的话,能看到他从哪(位置)更新到哪(位置)。(这里就不加动画过渡了,就一行代码的事.transition().duration(300) )。

改造如下:

    //这部分代码是有则改之,无则添加的功能
const circle_data=d3.selectAll('.circle_group').data(circleData)  //更新部分,如果你数据的数目没变,那circle_data.size()=你数据内容改变的数目,你可以把circle_data考虑成update部分就行,这样编代码准没错
    .attr('transform',             //首次运行的时候,因为没有元素circle_data.size()=0, 所以这个transform不会运行到
        function (d) {
            return 'translate(' + d.x + ',' + d.y + ')';
        });
const circle_enter=circle_data.enter().append('g')  //add 部分,首次运行的时候,circle_enter.size()=全部元素,所以在circle_enter进行所有的初始化设置操作
    .attr('class', 'circle_group brushNode')
    .attr('transform',
        function (d) {
            return 'translate(' + d.x + ',' + d.y + ')';
        });
circle_data.exit().remove();  // 当你删一些数据的时候, .exit().size()>0



circle_enter.on('click', function (d) {
    if (shiftKey) {
        //标记当前点
        d3.select(this).classed("selected", function (d) {

            d.selected = !d.selected;
            d.previouslySelected = !d.selected;
            return d.selected;
        })

        //阻止事件冒泡
        d3.event.stopPropagation();
    }
})
    .on("contextmenu", function (node) {
        contextmenu("Rmenu");
    })

circle_enter.append('circle')     //add
    .attr('r', d=>d.r)
    .style("fill", function (d) {
        return color20(d.index);
    });
circle_data.select('circle')  //update,这里不要append ,因为元素已经在那了(enter().append()过了)。当然首次运行(视图首次显示)的时候,这几句代码是运行不到的。
    .attr('r', d=>d.r)
    .style("fill", function (d) {
        return color20(d.index);
    });

circle_enter.append('text')  //add
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")//在圆圈中加上数据
    .style('fill', function (node) {
        return '#555';
    })
    .attr("y", -7)
    .text(d => d.text);
circle_data.select('text')  //update  不要append 
    .text(d => d.text);

const drag=d3.drag()
//定义了元素拖拽行为的原点,设置为圆的圆心位置可以避免明显的元素跳动, 与d3v3中的origin方法类似。
    .subject(function () {
        var thisData = d3.select(this);
        return {
            x: thisData.datum().x,
            y: thisData.datum().y
        };
    })
    .on("start", dragstarted)
    .on("drag", dragmove)
    .on("end", dragended);
circle_enter.call(drag);
circle_data.call(drag);   //update 注意,这里一定要重新绑定一下,这里涉及到drag的初始化(subject用于初始化drag拖动点的初始位置)

 

敲黑板

1、更新部分的所有与位置有关的事件(比如d3.drag()的初始位置)要重新绑定,否则会出现不可预料的结果。

2、update部分与数据有关的attr,style要重新设置,这时就不用append了。(因为这个元素既然有了,你已经在之前的.enter().append().append(其他元素)添加过了,这里只需要更新一下即可。)。一些固定的attr,style就不用重复设置了(之前enter已经绑定过了)

转载于:https://www.cnblogs.com/xunhanliu/p/10995687.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常好的问题!首先,我要确认您的问题是关于数据可视化工具D3.js的相关知识,是吗? 如果是的话,那么您的问题涉及到以下几个方面: 1. D3选择器与相关方法:D3.js提供了一些选择器与方法,用于选择对应的DOM元素,并对其进行操作。例如,可以使用D3.select()选择单个元素,使用D3.selectAll()选择多个元素,使用D3.append()添加元素等。 2. D3选择集与数据绑定:D3.js中的选择集(Selection)是对DOM元素的封装,可以对其进行数据绑定,实现数据驱动的可视化。可以使用D3.data()方法将数据与选择集绑定,使用D3.enter()方法添加新元素,使用D3.exit()方法删除旧元素。 3. enter-update-exit模型及其应用:这是D3.js中常用的一种数据绑定模式,用于实现数据驱动的可视化。其中,enter表示新数据进入时所需要进行的操作,update表示已有数据更新时所需要进行的操作,exit表示已有数据离开时所需要进行的操作。 4. csv、tsv、json、xml等数据格式:这些是常见的数据格式,D3.js提供了相应的方法用于读取这些格式的数据。例如,可以使用D3.csv()读取csv格式的数据,使用D3.json()读取json格式的数据。 5. D3获取外部数据的方法:D3.js提供了多种方法用于获取外部数据,例如使用D3.csv()、D3.json()、D3.text()等方法。可以通过异步请求获取数据,然后进行数据绑定和可视化。 希望以上回答能够帮助您解决疑惑,如果您有更多的问题,欢迎继续向我提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值