Javascript 将d3条形图重置为原始数据源时复制轴节点

Javascript 将d3条形图重置为原始数据源时复制轴节点,javascript,d3.js,charts,drag-and-drop,Javascript,D3.js,Charts,Drag And Drop,我有一个交互式d3条形图(条形图是可拖动的),带有一个关联的HTML表,以使我了解正在绘制的底层数据。我有一个重置按钮,它应该在用户玩过之后将图表数据重置为其原始状态。我不明白的是,为什么HTML表正在正确重置,而图表却没有。我想这与我对d3的enter()/update()的误解有关,但这是我所知道的 完整演示位于,但以下是相关代码: d3.json("data/tax_stacked.json", function(error, data) { var mydata = clone(dat

我有一个交互式d3条形图(条形图是可拖动的),带有一个关联的HTML表,以使我了解正在绘制的底层数据。我有一个重置按钮,它应该在用户玩过之后将图表数据重置为其原始状态。我不明白的是,为什么HTML表正在正确重置,而图表却没有。我想这与我对d3的enter()/update()的误解有关,但这是我所知道的

完整演示位于,但以下是相关代码:

d3.json("data/tax_stacked.json", function(error, data) {

var mydata = clone(data);  // Use a copy of the data to store user's preference.
var desc = function (a,b) { return d3.descending(+a.value, +b.value);}
mydata.sort(desc);
x.domain([0, d3.max(mydata, function(d) { return +d.value * 1.1; })]);
y.domain(mydata.map(function(d) { return d.name; }));
var defs = chart.insert("defs",".tax");
drawchart();

d3.select("button").on("click",function () {
    mydata = clone(data);
    mydata.sort(desc);
    drawchart();
});

function drawtable() {
    console.log("drawing table...");
    var columns = ["name", "value"];

    var table = d3.select("#grid");
            table.html("");
    var thead = table.append("thead"),
        tbody = table.append("tbody");

    // append the header row
    thead.append("tr")
        .selectAll("th")
        .data(columns)
        .enter()
        .append("th")
            .text(function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr")
        .data(mydata)
        .enter()
        .append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .text(function(d) { return d.value; }); 
}

function drawchart() {

        var drag = d3.behavior.drag()
        .on("dragstart", function(){
                    var where;
                    d3.select(this).classed({"bar": true, "moved": true});
        })
        .on("drag", function(d){
            where = d3.event.x;
            d3.select(this)
                .attr("width", where);
            d3.select(this.nextSibling)                             // Move the label
                .attr("x", where + 10);

/* Some lines omitted here for brevity */

            d.value = parseInt(x.invert(where));
            drawtable();
        })
        .on("dragend", function(d){
            });


      var taxes = chart.selectAll(".tax")
          .data(mydata)
        .enter()
            .append("g")
            .classed("tax", true);

    // Clipping paths to swap colours when the user's figures exceed original figures (work in progress!)       
        defs.selectAll(".cp")
                .data(mydata)
                .enter()
                .append("clipPath")
          .attr("id", function (d,i) { return "cp" + i; })
          .append("rect")
          .attr("x", function(d) { return x(d.value); })
          .attr("y", function(d) { return y(d.name); })
          .attr("width", function(d) { return width - x(d.value); })
          .attr("height", y.rangeBand());

    // Light blue bars for the original budget figures
      taxes.append("rect")
          .classed("original", true)
          .attr("x", function(d) { return x(0); })
          .attr("y", function(d) { return y(d.name); })
          .attr("width", function(d) { return x(d.value); })
          .attr("height", y.rangeBand())
          .attr("rx",0);

    // Medium blue bars for the user's budget figures
      taxes.append("rect")
          .attr("class", function (d) { return (d.fixed == "y") ? "fixed" : "bar"; })
          .attr("x", function(d) { return x(0); })
          .attr("y", function(d) { return y(d.name)+1; })
          .attr("width", function(d) { return x(d.value); })
          .attr("height", y.rangeBand()-1)
          .attr("rx",0)
          .attr("title", function (d) { return d.value; })
          .attr("clipper", function (d,i) { return "url(#cp" + i + ")"; });
    //      .attr("clip-path", function (d,i) { return "url(#cp" + i + ")"; });

      taxes.append("text")
          .attr("class", "label")
          .attr("x", function(d) { return x(d.value)+10; })
          .attr("y", function(d) { return y(d.name); })
          .attr("dy", "1.6em")
          .text( function (d) { return d.name; });

        var iconptr = taxes.append("g")
            .classed("smooth", true)
            .attr("transform", function (d) {
                    return "translate(" + (x(d.value)+labelpadding+parseInt(this.previousSibling.getBBox().width)) + "," + (y(d.name)+7) + ") scale(0.037,0.037)";
            });

/* Some lines omitted here for brevity */

    // Draw the axes
      chart.append("g")
          .attr("class", "x axis")
          .call(xAxis);

      chart.append("g")
          .attr("class", "y axis")
          .call(yAxis);

        d3.selectAll(".bar").call(drag);
        drawtable();
    }

}))

当前实施中存在几个问题:

  • 每次单击重置按钮时,都会追加两个轴
  • 单击“重置”按钮后,图表不会更新
  • 单击“重置”按钮后,表格更新不起作用
有很多可以说的,但集中在几个要点上,您的图表没有更新,因为正如您所怀疑的,输入/更新选择没有得到正确处理。您在输入选择之外执行所有操作,并且由于您没有键入数据(例如,通过值),也没有添加/删除元素,因此在启动时生成图表后,输入选择中将没有任何内容。我已经修复了这个问题,并在适当的地方发表了评论

我还修复了轴复制,并在用户播放图表并单击重命名的重画按钮后,使其适当刷新。我为什么要重命名按钮?基本上,你正在使用的克隆技术并没有真正起作用。您可以进一步调查,但为了方便起见,我删除了所有关于克隆数据的内容,只对原始数据进行了操作。因此,不,原始数据没有被重新设置,但当用户与图形交互时,以下内容正在工作:

  • 表格更新工作(包括排序)
  • 图表更新工作(包括排序)
  • x轴更新并反映新的数据量级

    // preserve the enter selection in a variable for re-use!!!
    var taxesEnter = taxes
      .enter()
      .append("g")
        .classed("tax", true);
    
完成修复


因此,这并不是要进行您想要的重新设置(再次,调查克隆情况),但它有许多有用的部分可供掌握。在这方面,我希望它对你有用。

万岁!由于对“更新”和enter()有了更好的理解,它现在可以工作了。更新后的提琴如下所示。除了@FernOfTheAndes的帮助外,我发现这很有帮助

d3.json(“data/tax\u stacked.json”),函数(错误,数据){
var mydata=clone(data);//使用数据的副本存储用户的首选项。
var desc=函数(a,b){返回d3.降序(+a.value,+b.value);}
mydata.sort(desc);
x、 域([0,d3.max(mydata,函数(d){return+d.value*1.1;})]);
y、 域(mydata.map(函数(d){returnd.name;}));
var defs=图表追加(“defs”);
//画轴
图表.附加(“g”)
.attr(“类”、“x轴”);
图表.附加(“g”)
.attr(“类”、“y轴”);
图纸();
绘图台();
d3.选择(“按钮”)。在(“单击”)上,功能(){
mydata=克隆(数据);
mydata.sort(desc);
d3.选择全部(“矩形条”)
.data(mydata)//我们在这个级别而不是税务级别重新绑定,因为重置值本身并没有向下传播到。
.attr(“宽度”,函数(d){console.log(x(d.value));返回x(d.value);});
绘图台();
});
函数drawtable(){
//从http://stackoverflow.com/questions/9268645/creating-a-table-linked-to-a-csv-file
变量列=[“名称”,“值”];
var表=d3。选择(“网格”);
表格.html(“”);
var thead=table.append(“thead”),
tbody=table.append(“tbody”);
//追加标题行
附件(“tr”)
.selectAll(“th”)
.数据(列)
.输入()
.附加(“th”)
.text(函数(列){返回列;});
//为数据中的每个对象创建一行
变量行=tbody.selectAll(“tr”)
.数据(mydata)
.输入()
.附加(“tr”);
//在每行中为每列创建一个单元格
变量单元格=行。选择全部(“td”)
.数据(功能(行){
返回columns.map(函数(列){
返回{column:column,value:row[column]};
});
})
.输入()
.附加(“td”)
.text(函数(d){返回d.value;});
}
函数绘图图(){
var drag=d3.behavior.drag()
.on(“dragstart”,函数(){
var何处;
d3.选择(this).classed({“bar”:true,“moved”:true});
})
.开启(“拖动”,功能(d){
式中=d3.event.x;
d3.选择(本)
.attr(“宽度”,其中);
d、 value=”“+parseInt(x.invert(其中));
绘图台();
})
.on(“dragend”,功能(d){
});
var tax=图表。选择全部(“.tax”)
.数据(mydata);
var taxenter=税收。输入()
.附加(“g”)
.分类(“税”,真实);
//原始预算数字的浅蓝色条
taxenter.append(“rect”)
.classed(“原始”,真实)
.attr(“x”,函数(d){返回x(0);})
.attr(“y”,函数(d){返回y(d.name);})
.attr(“宽度”,函数(d){返回x(d.value);})
.attr(“高度”,y.rangeBand())
.attr(“rx”,0);
//用户预算数字的中蓝色条
taxenter.append(“rect”)
.attr(“类”,函数(d){return(d.fixed==“y”)?“fixed”:“bar”})
.attr(“x”,函数(d){返回x(0);})
.attr(“y”,函数(d){返回y(d.name)+1;})
.attr(“宽度”,函数(d){返回x(d.value);})
.attr(“高度”,y.rangeBand()-1)
.attr(“rx”,0)
.attr(“title”,函数(d){返回d.value;});
//画轴
图表。选择全部(“.x”)
.呼叫(xAxis);
图表。选择(“.y”)
.呼叫(yAxis);
//埃纳
d3.json("data/tax_stacked.json", function(error, data) {

var mydata = clone(data);  // Use a copy of the data to store user's preference.
var desc = function (a,b) { return d3.descending(+a.value, +b.value);}
mydata.sort(desc);
x.domain([0, d3.max(mydata, function(d) { return +d.value * 1.1; })]);
y.domain(mydata.map(function(d) { return d.name; }));
var defs = chart.append("defs");

// Draw the axes
chart.append("g")
 .attr("class", "x axis");

chart.append("g")
 .attr("class", "y axis");

drawchart();
drawtable();

d3.select("button").on("click",function () {
    mydata = clone(data);
    mydata.sort(desc);
        d3.selectAll("rect.bar")
        .data(mydata)  // We're rebinding at this level rather than taxes level because the reset value is not propagating down to the <rect class="bar moved"> by itself.
      .attr("width", function(d) { console.log(x(d.value)); return x(d.value); });      
    drawtable();
});

function drawtable() {
// From http://stackoverflow.com/questions/9268645/creating-a-table-linked-to-a-csv-file
    var columns = ["name", "value"];

    var table = d3.select("#grid");
            table.html("");
    var thead = table.append("thead"),
        tbody = table.append("tbody");

    // append the header row
    thead.append("tr")
        .selectAll("th")
        .data(columns)
        .enter()
        .append("th")
            .text(function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr")
        .data(mydata)
        .enter()
        .append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .text(function(d) { return d.value; }); 
}

function drawchart() {

        var drag = d3.behavior.drag()
        .on("dragstart", function(){
                    var where;
                    d3.select(this).classed({"bar": true, "moved": true});
        })
        .on("drag", function(d){
            where = d3.event.x;
            d3.select(this)
                .attr("width", where);
                    d.value = "" + parseInt(x.invert(where));
            drawtable();
        })
        .on("dragend", function(d){
            });

        var taxes = chart.selectAll(".tax")
          .data(mydata);

      var taxenter = taxes.enter()
            .append("g")
            .classed("tax", true);

    // Light blue bars for the original budget figures
      taxenter.append("rect")
          .classed("original", true)
          .attr("x", function(d) { return x(0); })
          .attr("y", function(d) { return y(d.name); })
          .attr("width", function(d) { return x(d.value); })
          .attr("height", y.rangeBand())
          .attr("rx",0);

    // Medium blue bars for the user's budget figures
      taxenter.append("rect")
          .attr("class", function (d) { return (d.fixed == "y") ? "fixed" : "bar"; })
          .attr("x", function(d) { return x(0); })
          .attr("y", function(d) { return y(d.name)+1; })
                .attr("width", function(d) { return x(d.value); })
          .attr("height", y.rangeBand()-1)
          .attr("rx",0)
          .attr("title", function (d) { return d.value; });

    // Draw the axes
      chart.selectAll(".x")
          .call(xAxis);

      chart.select(".y")
          .call(yAxis);

    // Enable dragging

      d3.selectAll(".bar").call(drag);

    }

});