代码之家  ›  专栏  ›  技术社区  ›  spring

更新模式:更新每个节点的更改

  •  0
  • spring  · 技术社区  · 6 年前

    我一直想弄清楚如何只更新那些 d3 节点中的数据已更改,但我仍然没有正确的数据。在下面的小测试示例中,我仍然在改变它所显示的一切。

    我这样做是完全错误还是有点错误?

    在本例中,单击形状将形状切换为圆形或方形,并更新“clickcnt”属性。然后重新绘制数据。这是一种工作,但似乎正在重新绘制所有内容。另外,由于某种原因,点击“红色”形状是不起作用的,但它是完全相同的代码。

    任何见解或建议都是最受欢迎的,我一整天都被困在这个问题上。

    var dataArray = [];
    dataArray.push({ "label": 'red', "shape": "circle", "clickCnt": 0, x: 30, y: 100 });
    dataArray.push({ "label": 'orange', "shape": "square", "clickCnt": 0, x: 110, y: 100 });
    dataArray.push({ "label": 'yellow', "shape": "circle", "clickCnt": 0, x: 210, y: 100 });
    dataArray.push({ "label": 'green', "shape": "square", "clickCnt": 0, x: 310, y: 100 });
    dataArray.push({ "label": 'blue', "shape": "circle", "clickCnt": 0, x: 30, y: 200 });
    dataArray.push({ "label": 'indigo', "shape": "square", "clickCnt": 0, x: 110, y: 200 });
    dataArray.push({ "label": 'violet', "shape": "circle", "clickCnt": 0, x: 210, y: 200 });
    dataArray.push({ "label": 'white', "shape": "square", "clickCnt": 0, x: 310, y: 200 });
    
    var width = 400;
    var height = 400;
    
    d3.select("div#svg-container").select("svg").remove();
    var svg = d3.select("#svg-container").append("svg")
        .attr("width", width)
        .attr("height", height);
    
    var content = svg.append("g")
    
    function create(data) {
        var groups = content.selectAll("g")
            .data(data, function (d) {
                return d;
            });
    
        groups.exit().remove();
    
        groups.enter()
            .append("g")
            .attr('transform', function (d, i) {
                return 'translate(' + d.x + ',' + d.y + ')'
            })
            .each(function (d) {
                var e = d3.select(this);
                e.append("text")
                    .classed("small-text", true)
                    .classed("label", true)
                    .text(function (d) {
                        return d.label;
                    })
                    .style("fill", function (d) {
                        return d.label;
                    });
    
                e.append("text")
                    .classed("small-text", true)
                    .classed("clickCnt", true)
                    .attr("y", 20)
                    .text(function (d) {
                        return d.clickCnt;
                    })
                    .style("fill", function (d) {
                        return d.label;
                    })
    
                if (d.shape == "circle") {
                    e.append("circle")
                        .attr("class", "circle")
                        .attr("r", 15)
                        .attr("cx", 10)
                        .attr("cy", -40)
                        .on("click", iconClicked)
                        .style("cursor", "pointer");
    
                } else if (d.shape == "square") {
                    e.append("rect")
                        .attr("class", "square")
                        .attr("width", 30)
                        .attr("height", 30)
                        .attr("x", 0)
                        .attr("y", -55)
                        .on("click", iconClicked)
                        .style("cursor", "pointer");
                }
            });
    }
    
    
    create(dataArray);
    
    function iconClicked(evt) {
        if (evt.shape == "circle") {
            evt.shape = "square"
        } else if (evt.shape == "square") {
            evt.shape = "circle"
        }
        evt.clickCnt++;
    
        document.getElementById('output').innerHTML = "item clicked: " + evt.label + " " + evt.clickCnt;
        
        create(dataArray);
    }
        .circle {
          stroke: red;
          stroke-width: 2px;
          
        }
        .square {
          stroke: blue;
          stroke-width: 2px;
        }
    
        #timeline-background {
          background: slategray;
        }
    
        .label {
          fill: blue;
        }
        .small-text {
          font-size: 16px;
          
        }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    
    <body>
      <label id="output">out</label>
      <div id="timeline-background" style="width: 100%; height: 100%;">
        <div id="svg-container"></div>
      </div>
    </body>
    1 回复  |  直到 6 年前
        1
  •  0
  •   Gerardo Furtado    6 年前

    你的问题是 key function 绑定数据时。

    如果您查看文档,您将看到:

    可以指定一个键函数,通过计算 一串 每个基准和元素的标识符。(强调我的)

    但是,在您的案例中,您不是使用字符串,而是返回整个对象:

    var groups = content.selectAll("g")
        .data(data, function (d) {
            return d;
            //     ^--- this is an object
        });
    

    当然,这行不通。

    因此,我们有你描述的行为:你的 exit 所选内容包含所有组,它们都将被删除。然后,输入选择包含所有元素,它们都会重新绘制。

    让我们看看,单击元素并查看控制台:

    var dataArray = [];
    dataArray.push({ "label": 'red', "shape": "circle", "clickCnt": 0, x: 30, y: 100 });
    dataArray.push({ "label": 'orange', "shape": "square", "clickCnt": 0, x: 110, y: 100 });
    dataArray.push({ "label": 'yellow', "shape": "circle", "clickCnt": 0, x: 210, y: 100 });
    dataArray.push({ "label": 'green', "shape": "square", "clickCnt": 0, x: 310, y: 100 });
    dataArray.push({ "label": 'blue', "shape": "circle", "clickCnt": 0, x: 30, y: 200 });
    dataArray.push({ "label": 'indigo', "shape": "square", "clickCnt": 0, x: 110, y: 200 });
    dataArray.push({ "label": 'violet', "shape": "circle", "clickCnt": 0, x: 210, y: 200 });
    dataArray.push({ "label": 'white', "shape": "square", "clickCnt": 0, x: 310, y: 200 });
    
    var width = 400;
    var height = 400;
    
    d3.select("div#svg-container").select("svg").remove();
    var svg = d3.select("#svg-container").append("svg")
        .attr("width", width)
        .attr("height", height);
    
    var content = svg.append("g")
    
    function create(data) {
        var groups = content.selectAll("g")
            .data(data, function (d) {
                return d;
            });
            
        console.log("The exit selection size is: " + groups.exit().size())
    
        groups.exit().remove();
    
        groups.enter()
            .append("g")
            .attr('transform', function (d, i) {
                return 'translate(' + d.x + ',' + d.y + ')'
            })
            .each(function (d) {
                var e = d3.select(this);
                e.append("text")
                    .classed("small-text", true)
                    .classed("label", true)
                    .text(function (d) {
                        return d.label;
                    })
                    .style("fill", function (d) {
                        return d.label;
                    });
    
                e.append("text")
                    .classed("small-text", true)
                    .classed("clickCnt", true)
                    .attr("y", 20)
                    .text(function (d) {
                        return d.clickCnt;
                    })
                    .style("fill", function (d) {
                        return d.label;
                    })
    
                if (d.shape == "circle") {
                    e.append("circle")
                        .attr("class", "circle")
                        .attr("r", 15)
                        .attr("cx", 10)
                        .attr("cy", -40)
                        .on("click", iconClicked)
                        .style("cursor", "pointer");
    
                } else if (d.shape == "square") {
                    e.append("rect")
                        .attr("class", "square")
                        .attr("width", 30)
                        .attr("height", 30)
                        .attr("x", 0)
                        .attr("y", -55)
                        .on("click", iconClicked)
                        .style("cursor", "pointer");
                }
            });
    }
    
    
    create(dataArray);
    
    function iconClicked(evt) {
        if (evt.shape == "circle") {
            evt.shape = "square"
        } else if (evt.shape == "square") {
            evt.shape = "circle"
        }
        evt.clickCnt++;
    
        document.getElementById('output').innerHTML = "item clicked: " + evt.label + " " + evt.clickCnt;
        
        create(dataArray);
    }
    .as-console-wrapper { max-height: 20% !important;}
    .circle {
          stroke: red;
          stroke-width: 2px;
          
        }
        .square {
          stroke: blue;
          stroke-width: 2px;
        }
    
        #timeline-background {
          background: slategray;
        }
    
        .label {
          fill: blue;
        }
        .small-text {
          font-size: 16px;
          
        }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    
    <body>
      <label id="output">out</label>
      <div id="timeline-background" style="width: 100%; height: 100%;">
        <div id="svg-container"></div>
      </div>
    </body>

    (部分)解 :使用唯一字符串作为返回值,例如 label 属性:

    var groups = content.selectAll("g")
        .data(data, function (d) {
            return d.label;
        });
    

    看看:

    var dataArray = [];
    dataArray.push({ "label": 'red', "shape": "circle", "clickCnt": 0, x: 30, y: 100 });
    dataArray.push({ "label": 'orange', "shape": "square", "clickCnt": 0, x: 110, y: 100 });
    dataArray.push({ "label": 'yellow', "shape": "circle", "clickCnt": 0, x: 210, y: 100 });
    dataArray.push({ "label": 'green', "shape": "square", "clickCnt": 0, x: 310, y: 100 });
    dataArray.push({ "label": 'blue', "shape": "circle", "clickCnt": 0, x: 30, y: 200 });
    dataArray.push({ "label": 'indigo', "shape": "square", "clickCnt": 0, x: 110, y: 200 });
    dataArray.push({ "label": 'violet', "shape": "circle", "clickCnt": 0, x: 210, y: 200 });
    dataArray.push({ "label": 'white', "shape": "square", "clickCnt": 0, x: 310, y: 200 });
    
    var width = 400;
    var height = 400;
    
    d3.select("div#svg-container").select("svg").remove();
    var svg = d3.select("#svg-container").append("svg")
        .attr("width", width)
        .attr("height", height);
    
    var content = svg.append("g")
    
    function create(data) {
        var groups = content.selectAll("g")
            .data(data, function (d) {
                return d.label;
            });
            
        console.log("The exit selection size is: " + groups.exit().size())
    
        groups.exit().remove();
    
        groups.enter()
            .append("g")
            .attr('transform', function (d, i) {
                return 'translate(' + d.x + ',' + d.y + ')'
            })
            .each(function (d) {
                var e = d3.select(this);
                e.append("text")
                    .classed("small-text", true)
                    .classed("label", true)
                    .text(function (d) {
                        return d.label;
                    })
                    .style("fill", function (d) {
                        return d.label;
                    });
    
                e.append("text")
                    .classed("small-text", true)
                    .classed("clickCnt", true)
                    .attr("y", 20)
                    .text(function (d) {
                        return d.clickCnt;
                    })
                    .style("fill", function (d) {
                        return d.label;
                    })
    
                if (d.shape == "circle") {
                    e.append("circle")
                        .attr("class", "circle")
                        .attr("r", 15)
                        .attr("cx", 10)
                        .attr("cy", -40)
                        .on("click", iconClicked)
                        .style("cursor", "pointer");
    
                } else if (d.shape == "square") {
                    e.append("rect")
                        .attr("class", "square")
                        .attr("width", 30)
                        .attr("height", 30)
                        .attr("x", 0)
                        .attr("y", -55)
                        .on("click", iconClicked)
                        .style("cursor", "pointer");
                }
            });
    }
    
    
    create(dataArray);
    
    function iconClicked(evt) {
        if (evt.shape == "circle") {
            evt.shape = "square"
        } else if (evt.shape == "square") {
            evt.shape = "circle"
        }
        evt.clickCnt++;
    
        document.getElementById('output').innerHTML = "item clicked: " + evt.label + " " + evt.clickCnt;
        
        create(dataArray);
    }
    .作为控制台包装最大高度:20%!重要;
    .圆{
    行程:红色;
    行程宽度:2px;
    
    }
    .正方形{
    笔画:蓝色;
    行程宽度:2px;
    }
    
    #时间线背景{
    背景:斯莱特雷;
    }
    
    .标签{
    填充:蓝色;
    }
    .小文本{
    字体大小:16px;
    
    }
    <script src=“https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js”></script>
    
    <正文>
    <label id=“output”>输出</label>
    <div id=“Timeline Background”style=“width:100%;height:100%;”>
    <DIV ID=“SVG容器”></DIV>
    </DIV>
    </body>

    现在,如你所见, 出口 所选内容的大小始终为零。

    然而,我写道 部分 原因:你不再改变元素了!原因是您没有正确的更新选择。由于退出选择不再有元素,因此输入选择的大小也为零。此处不更新任何内容。

    创建这样的更新选择超出了这个答案的范围,我将把这项工作留给您。