zoukankan      html  css  js  c++  java
  • 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已经绑定过了)

  • 相关阅读:
    2018 ACM 网络选拔赛 徐州赛区
    2018 ACM 网络选拔赛 焦作赛区
    2018 ACM 网络选拔赛 沈阳赛区
    poj 2289 网络流 and 二分查找
    poj 2446 二分图最大匹配
    poj 1469 二分图最大匹配
    poj 3249 拓扑排序 and 动态规划
    poj 3687 拓扑排序
    poj 2585 拓扑排序
    poj 1094 拓扑排序
  • 原文地址:https://www.cnblogs.com/xunhanliu/p/10995687.html
Copyright © 2011-2022 走看看