javascript - D3 更新数据,html 表中的行数,最后一列中的动画 svgs

标签 javascript html d3.js svg

我正在尝试使用 D3 更新 HTML 表格中的数据。我需要更改多列中的数据,更新行数,并根据每个新数据数组为每行中的 SVG 制作动画。我已经尝试了多次尝试、教程、文档,而且我确信这对于对图书馆更有经验的人来说是一个简单的方法。

我在代码 tbody.selectAll('tr').remove(); 中评论过的一种方法只是删除表中的所有行。但是因为没有起始位置,所以不可能为 SVG 设置动画。

我目前的方法也是错误的,虽然我是 D3 的新手所以我不确定为什么。当新数据进来时,它不会正确替换旧数据,而是根据新长度影响行长度,有时会替换,但通常会附加。单击此 jsfiddle 上的“运行”直到您看到 id 以较小的数字出现(例如“7”)。然后按更新按钮,您会看到新数据不会更新行,而是根据新数组中的数字附加到行。因此,如果下一个数组恰好有 8,那么你会看到一个 8。如果下一个数组有 10,那么你会看到两个十。我敢肯定,一旦这个问题得到修复,它也会修复 SVG 动画。

screenshot of table with three "updates"

这是我正在使用的通用代码。

// create table, etc.
var table = d3.select('.chart').append('table');
var thead = table.append('thead');
var tbody = table.append('tbody');

// append the header row
thead.append('tr')
    .selectAll('th')
    .data(['id','val','svg']).enter()
    .append('th')
    .text(function (col_names) { return col_names; });

function update_table(){

  data = newdata(); // update data to display

  // remove existing rows
  // this basically resets the table element
  // but is not the right way
  //tbody.selectAll('tr').remove();

  // join new data with old elements, if any
  var rows = tbody.selectAll('tr')
        .data(data)
        .enter()
        .append('tr');

  // add first two columns
  rows.append('td').text(function(d) { return d.id; })
  rows.append('td').text(function(d) { return d.val; });  

  // add svg
  var svgcell = rows.append('td')
    .append('svg')
      .attr("width",20)
      .attr("height",20);  
  svgcell.append('circle').transition().duration(500)
    .attr("cx", 10)
    .attr("cy", 10)
    .attr("r", function(d) { return d.val; })
    .style("fill", "red");

   tbody.selectAll('tr').data(data).exit().remove();  
}

最佳答案

对于 D3 代码,您的要求有点不寻常:您想要根据数据更新行,但又不想删除 <td> s 包含圆圈...排除了最简单的解决方案,即定义 key function基于值列的数据绑定(bind)函数:

var rows = tbody.selectAll('tr')
    .data(data, function(d) {
        return d.val
    });

有了这个简单的解决方案,我这里的解决方案有点尴尬。

首先,设置更新选择:

var rows = tbody.selectAll('tr')
    .data(data);

然后输入选择:

var rowsEnter = rows.enter()
    .append('tr');

rowsEnter.append('td')
    .attr("class", "idColumn")
    .text(function(d) {
        return d.id;
    });
rowsEnter.append('td')
    .attr("class", "valColumn")
    .text(function(d) {
        return d.val;
    });

rowsEnter.append('td')
    .append('svg')
    .attr("width", 20)
    .attr("height", 20).append('circle')
    .attr("class", "svgCircle")
    .style("fill", "red");

现在,按类选择所有列,重新绑定(bind)数据(这是我之前提到的尴尬部分),并为圆圈设置过渡:

d3.selectAll(".idColumn").data(data).text(function(d) {
    return d.id;
});
d3.selectAll(".valColumn").data(data).text(function(d) {
    return d.val;
});
d3.selectAll(".svgCircle").data(data).attr("cx", 10)
    .attr("cy", 10).transition().duration(500)
    .attr("r", function(d) {
        return d.val;
    })
    .style("fill", "red");

最后是退出选择:

rows.exit().remove(); 

这是演示:

// D3 update data, number rows in html table, animate svgs in last column
function newdata() {
    var n = [];
    var r = Math.ceil(Math.random() * 20);
    for (var i = 0; i < r; i++) {
        n.push({
            "id": r,
            "val": Math.random() * 10
        });
    }
    return n;
}
var data = newdata(); // generate data array of random length

// create table, etc.
var table = d3.select('.chart').append('table');
var thead = table.append('thead');
var tbody = table.append('tbody');

// append the header row
thead.append('tr')
    .selectAll('th')
    .data(['id', 'val', 'svg']).enter()
    .append('th')
    .text(function(col_names) {
        return col_names;
    });

// update function
function update_table() {
    // update data to display
    data = newdata();

    // remove existing rows
    // this basically resets the table element
    // but is not the right way
    //tbody.selectAll('tr').remove();

    // join new data with old elements, if any
    var rows = tbody.selectAll('tr')
        .data(data);

    var rowsEnter = rows.enter()
        .append('tr');

    rowsEnter.append('td')
        .attr("class", "idColumn")
        .text(function(d) {
            return d.id;
        });
    rowsEnter.append('td')
        .attr("class", "valColumn")
        .text(function(d) {
            return d.val;
        });

    rowsEnter.append('td')
        .append('svg')
        .attr("width", 20)
        .attr("height", 20).append('circle')
        .attr("class", "svgCircle")
        .style("fill", "red");

    d3.selectAll(".idColumn").data(data).text(function(d) {
        return d.id;
    });
    d3.selectAll(".valColumn").data(data).text(function(d) {
        return d.val;
    });
    d3.selectAll(".svgCircle").data(data).attr("cx", 10)
        .attr("cy", 10).transition().duration(500)
        .attr("r", function(d) {
            return d.val;
        })
        .style("fill", "red");

    rows.exit().remove();

}
update_table();

var button = document.getElementById("update");
button.addEventListener("click", function(e) {
    update_table();
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<button id="update">update</button>
<div class="chart"></div>

如果您喜欢 fiddle ,这里就是:https://jsfiddle.net/evzx2x6L/

关于javascript - D3 更新数据,html 表中的行数,最后一列中的动画 svgs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41818638/

相关文章:

javascript execCommand ('delete' ) 不删除 chrome 中的所有选择 div

html - 将文本正确放置在居中图像下方

javascript - 修复 d3.js v4 工具提示位置

javascript - D3 比例 SVG child

html - HTML 中的卢比符号

javascript - d3 v4 TypeScript DefinitelyTyped Angular2 线与 X 轴上的 ScaleTime

javascript - 如何在 nuxt.js 上从子组件获取值到父组件?

javascript - indexOf,向上搜索字符串而不是向下搜索

javascript - 使用 JS 将多选添加到筛选列表

javascript - 在学习 Ajax 之前我需要了解什么?