最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - D3.js trying to implement sortable SVG table - Stack Overflow

programmeradmin1浏览0评论

As my title states I am trying to implement an interactive table with nice transitions, that's why I choose D3.js in bination with SVG elements.

I managed to implement a sortable table with normal HTML elements (th,tr,td):

/

// create the table header
var thead = d3.select("thead").selectAll("th")
    .data(d3.keys(jsonData[0]))
    .enter().append("th").text(function(d){return d;})
    .on("click", function(d){ return refreshTable(d);});

// fill the table   
// create rows
var tr = d3.select("tbody").selectAll("tr").data(jsonData); 
tr.enter().append("tr");

// create cells
var td = tr.selectAll("td").data(function(d){return d3.values(d);});    
td.enter().append("td")
    .text(function(d) {return d;});

//update?
if(sortOn !== null) {           
        // update rows
        if(sortOn != previousSort){
            tr.sort(function(a,b){return sort(a[sortOn], b[sortOn]);});
            previousSort = sortOn;
        }
        else{
            tr.sort(function(a,b){return sort(b[sortOn], a[sortOn]);});
            previousSort = null;
        }

        //update cells
        td.text(function(d) {return d;});
}

As you can see the table sorts the data correctly when clicking on the header elements. Based on the above table I started to implement the svg version of this table and this is how I got so far:

/

// create the table header  
var header = headerGrp.selectAll("g")
    .data(d3.keys(jsonData[0]))
  .enter().append("g")
    .attr("class", "header")
    .attr("transform", function (d, i){
        return "translate(" + i * fieldWidth + ",0)";
    })
    .on("click", function(d){ return refreshTable(d);});

header.append("rect")
    .attr("width", fieldWidth-1)
    .attr("height", fieldHeight);

header.append("text")
    .attr("x", fieldWidth / 2)
    .attr("y", fieldHeight / 2)
    .attr("dy", ".35em")
    .text(String);

// fill the table   
// select rows
var rows = rowsGrp.selectAll("g.row").data(jsonData);

// create rows  
var rowsEnter = rows.enter().append("svg:g")
    .attr("class","row")
    .attr("transform", function (d, i){
        return "translate(0," + (i+1) * (fieldHeight+1) + ")";
    });

// select cells
var cells = rows.selectAll("g.cell").data(function(d){return d3.values(d);});

// create cells
var cellsEnter = cells.enter().append("svg:g")
    .attr("class", "cell")
    .attr("transform", function (d, i){
        return "translate(" + i * fieldWidth + ",0)";
    });

cellsEnter.append("rect")
    .attr("width", fieldWidth-1)
    .attr("height", fieldHeight);   

cellsEnter.append("text")
    .attr("x", fieldWidth / 2)
    .attr("y", fieldHeight / 2)
    .attr("dy", ".35em")
    .text(String);

//update if not in initialisation
if(sortOn !== null) {
        // update rows
        if(sortOn != previousSort){
            rows.sort(function(a,b){return sort(a[sortOn], b[sortOn]);});           
            previousSort = sortOn;
        }
        else{
            rows.sort(function(a,b){return sort(b[sortOn], a[sortOn]);});
            previousSort = null;
        }
        rows.transition()
            .duration(500)
            .attr("transform", function (d, i){
                return "translate(0," + (i+1) * (fieldHeight+1) + ")";
            });

        //update cells
        rows.selectAll("g.cell").select("text").text(String);
}

The problem Iam currently not able to solve, is that the sorting doesn't quite work. When clicking on the headers something happens, but the rows are not sorted correctly. What seems very strange to me is, that when inspecting the html elements in the browser, the g.row elements are sorted correctly according to the data bound to them.

I don't think there is a problem with my sort function, because Iam using the same one in both tables. My guess is that the newly sorted rows are not feeded with the right cells, but I don't know how to solve this problem.

EDIT: Ok I managed to update the text in the cells to the new sorting order correctly. The corrected code is on jsfiddle and also edited here. But there remains still one problem I just don't understand:

The transition of the rows to their new positions don't match the newly sorted data bound to them. For example when clicking multiple times on "id" you will see what I mean. Is it possible that the paramater "i", which I use to transition to the new positions doesn't represent the newly sorted order? I found this example, which is similar to mine and the transition works correctly:

http:// examples.oreilly/0636920026938/chapter_10/10_delay.html (sorry, cant post more than 2 links yet)

Where is the error in my code?

As my title states I am trying to implement an interactive table with nice transitions, that's why I choose D3.js in bination with SVG elements.

I managed to implement a sortable table with normal HTML elements (th,tr,td):

http://jsfiddle/recek/q6LE6/

// create the table header
var thead = d3.select("thead").selectAll("th")
    .data(d3.keys(jsonData[0]))
    .enter().append("th").text(function(d){return d;})
    .on("click", function(d){ return refreshTable(d);});

// fill the table   
// create rows
var tr = d3.select("tbody").selectAll("tr").data(jsonData); 
tr.enter().append("tr");

// create cells
var td = tr.selectAll("td").data(function(d){return d3.values(d);});    
td.enter().append("td")
    .text(function(d) {return d;});

//update?
if(sortOn !== null) {           
        // update rows
        if(sortOn != previousSort){
            tr.sort(function(a,b){return sort(a[sortOn], b[sortOn]);});
            previousSort = sortOn;
        }
        else{
            tr.sort(function(a,b){return sort(b[sortOn], a[sortOn]);});
            previousSort = null;
        }

        //update cells
        td.text(function(d) {return d;});
}

As you can see the table sorts the data correctly when clicking on the header elements. Based on the above table I started to implement the svg version of this table and this is how I got so far:

http://jsfiddle/recek/v58zT/

// create the table header  
var header = headerGrp.selectAll("g")
    .data(d3.keys(jsonData[0]))
  .enter().append("g")
    .attr("class", "header")
    .attr("transform", function (d, i){
        return "translate(" + i * fieldWidth + ",0)";
    })
    .on("click", function(d){ return refreshTable(d);});

header.append("rect")
    .attr("width", fieldWidth-1)
    .attr("height", fieldHeight);

header.append("text")
    .attr("x", fieldWidth / 2)
    .attr("y", fieldHeight / 2)
    .attr("dy", ".35em")
    .text(String);

// fill the table   
// select rows
var rows = rowsGrp.selectAll("g.row").data(jsonData);

// create rows  
var rowsEnter = rows.enter().append("svg:g")
    .attr("class","row")
    .attr("transform", function (d, i){
        return "translate(0," + (i+1) * (fieldHeight+1) + ")";
    });

// select cells
var cells = rows.selectAll("g.cell").data(function(d){return d3.values(d);});

// create cells
var cellsEnter = cells.enter().append("svg:g")
    .attr("class", "cell")
    .attr("transform", function (d, i){
        return "translate(" + i * fieldWidth + ",0)";
    });

cellsEnter.append("rect")
    .attr("width", fieldWidth-1)
    .attr("height", fieldHeight);   

cellsEnter.append("text")
    .attr("x", fieldWidth / 2)
    .attr("y", fieldHeight / 2)
    .attr("dy", ".35em")
    .text(String);

//update if not in initialisation
if(sortOn !== null) {
        // update rows
        if(sortOn != previousSort){
            rows.sort(function(a,b){return sort(a[sortOn], b[sortOn]);});           
            previousSort = sortOn;
        }
        else{
            rows.sort(function(a,b){return sort(b[sortOn], a[sortOn]);});
            previousSort = null;
        }
        rows.transition()
            .duration(500)
            .attr("transform", function (d, i){
                return "translate(0," + (i+1) * (fieldHeight+1) + ")";
            });

        //update cells
        rows.selectAll("g.cell").select("text").text(String);
}

The problem Iam currently not able to solve, is that the sorting doesn't quite work. When clicking on the headers something happens, but the rows are not sorted correctly. What seems very strange to me is, that when inspecting the html elements in the browser, the g.row elements are sorted correctly according to the data bound to them.

I don't think there is a problem with my sort function, because Iam using the same one in both tables. My guess is that the newly sorted rows are not feeded with the right cells, but I don't know how to solve this problem.

EDIT: Ok I managed to update the text in the cells to the new sorting order correctly. The corrected code is on jsfiddle and also edited here. But there remains still one problem I just don't understand:

The transition of the rows to their new positions don't match the newly sorted data bound to them. For example when clicking multiple times on "id" you will see what I mean. Is it possible that the paramater "i", which I use to transition to the new positions doesn't represent the newly sorted order? I found this example, which is similar to mine and the transition works correctly:

http:// examples.oreilly./0636920026938/chapter_10/10_delay.html (sorry, cant post more than 2 links yet)

Where is the error in my code?

Share Improve this question edited Oct 31, 2017 at 18:15 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked May 21, 2014 at 20:06 RecekRecek 1,38815 silver badges18 bronze badges 2
  • I'm not sure if SVG is a better choice than HTML for a table. For mostly text, HTML is much more convenient. Here is an example of a sortable HTML table with transitions. – Lars Kotthoff Commented May 22, 2014 at 9:42
  • This might be right, but Iam planing on doing some more interaction with the table than just sorting and I think to get nicer animation using svg. But thank you for the example, when Iam getting stuck with the svg methods to often I will reconsider using HTML ;) – Recek Commented May 22, 2014 at 13:02
Add a ment  | 

1 Answer 1

Reset to default 7

Found the solution to my problem on this page:

http://bost.ocks/mike/constancy/

The problem was a missing key function for the data to be correctly bound to the rows.

By changing this line:

var rows = rowsGrp.selectAll("g.row").data(jsonData);

to

var rows = rowsGrp.selectAll("g.row").data(jsonData, 
    function(d){ return d.id; });

and removing the cell update after the transition:

//update cells
rows.selectAll("g.cell").select("text").text(String);

The table sorts and transitions correctly now.

发布评论

评论列表(0)

  1. 暂无评论