简体   繁体   中英

D3 - Hierarchical data-set, layout works, but can't update data

See Here. https://bl.ocks.org/dooglz/9b4d979d31d3ef10ab4f65c085e43b10

I have a Hierarchical data-set, some nodes have different amount of children, some have none. I want this displayed as a set of nested divs. I have achieved this in the above block, although I'm not sure if I've gone about it the best way. But it is how I want it to look, the layout is fine.

Each node has a .val property, this is displayed at the end of each div's .html(). Some nodes children are a set of identical 'types', I have grouped these together as selections. Again not sure if this was the best way to achieve this.

The problem I have is that if the data changes (values inside the nodes, structure never changes), the data does not change in divs if the layout function is re-run.

I think I've done the nested selections wrong ( https://bost.ocks.org/mike/nest/ ) and broken the chain of data, and I'm not sure how to fix it.

I know I need to add an extra

ComputeUnits.html(....); / SimdUnits.html(....); ... etc

Somewhere but I'm not sure how or where.

Original Code snippet here for longevity:

function hardcoded(){
    let container = d3.select("body");
    let ComputeUnits = container.selectAll(".ComputeUnit")
        .data(data)
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-' + d.id})
        .attr("class",(d)=>{return d.type})
        .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")})
    let Salus = ComputeUnits.selectAll(".SALU")
        .data(function(d) { return d.children.filter(c => c.type == "SALU"); })
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-'+d.id})
        .attr("class",(d)=>{return d.type})
       .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")})
    let SimdUnits = ComputeUnits.selectAll(".SimdUnit")
        .data(function(d) { return d.children.filter(c => c.type == "SimdUnit"); })
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-'+d.id})
        .attr("class",(d)=>{return d.type})
       .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")})
    let SimdLanes = SimdUnits.selectAll(".SimdLane")
        .data(function(d) { return d.children; })
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-'+d.id})
        .attr("class",(d)=>{return d.type})
        .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")})
}

I would have thought that this would work:

    function hardcoded(){
    let container = d3.select("body");
    let ComputeUnits = container.selectAll(".ComputeUnit").data(data);
    ComputeUnits
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-' + d.id})
        .attr("class",(d)=>{return d.type});
    ComputeUnits
        .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")});

    let Salus = ComputeUnits.selectAll(".SALU")
        .data(function(d) { return d.children.filter(c => c.type == "SALU"); });
    Salus
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-'+d.id})
        .attr("class",(d)=>{return d.type});
    Salus
        .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")});

    let SimdUnits = ComputeUnits.selectAll(".SimdUnit")
        .data(function(d) { console.log(1,d); return d.children.filter(c => c.type == "SimdUnit"); });
    SimdUnits
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-'+d.id})
        .attr("class",(d)=>{return d.type});
    SimdUnits
        .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")});

    let SimdLanes = SimdUnits.selectAll(".SimdLane")
        .data(function(d) { console.log(2,d);return d.children; });
    SimdLanes
        .enter().append("div")
        .attr("id", (d)=>{return d.type + '-'+d.id})
        .attr("class",(d)=>{return d.type});
    SimdLanes
        .html((d)=>{return d.type + '-' + d.id+(d.val?("_"+d.val):"")});

but it seems that the when the data updates, all the .enter()'s fire again, but not the update ".html((d)..."

Bonus points: I need this to work as a recursive function, as shown in the block, the hard-coded method is just for clarity.

I think I have found a solution, I was not aware of the new V4 update/merge pattern.

Furthermore, The key was to do: ComputeUnits = ComputeUnits.merge(cuenter)

This seems to work as it should, but it still calls the .enter() on every element, anytime the data chages. But now it does call the Update/merge, so it looks like it works.

function hardcoded() {
    let container = d3.select("body");
    let ComputeUnits = container.selectAll(".ComputeUnit").data(data);

    let cuenter = ComputeUnits
        .enter().append("div")
        .attr("id", (d) => {
            return d.type + '-' + d.id
        })
        .attr("class", (d) => {
            return d.type
        });

    ComputeUnits = ComputeUnits.merge(cuenter)
        .text((d) => {
            console.log("cu update");
            return d.type + '-' + d.id + '-' + d.val;
        });

    let Salus = ComputeUnits.selectAll(".SALU")
        .data(function (d) {return d.children.filter(c => (c.type === "SALU"));
        });

    let saenter = Salus
        .enter().append("div")
        .attr("id", (d) => {
            console.log("salu enter")
            return d.type + '-' + d.id
        })
        .attr("class", (d) => {
            return d.type
        });

    Salus = Salus.merge(saenter)
        .text((d) => {
            console.log("salu update");
            return d.type + '-' + d.id + '-' + d.val;
        });

    let SimdUnits = ComputeUnits.selectAll(".SimdUnit")
        .data(function (d) {
            console.log(1, d);
            return d.children.filter(c => c.type === "SimdUnit");
        });

    let suenter = SimdUnits
        .enter().append("div")
        .attr("id", (d) => {
            return d.type + '-' + d.id
        })
        .attr("class", (d) => {
            return d.type
        });

    SimdUnits = SimdUnits.merge(suenter)
        .text((d) => {
            console.log("simdu update");
            return d.type + '-' + d.id + '-' + d.val;
        });

    let SimdLanes = SimdUnits.selectAll(".SimdLane")
        .data(function (d) {
            return d.children;
        });

    let slenter = SimdLanes
        .enter().append("div")
        .attr("id", (d) => {
            return d.type + '-' + d.id
        })
        .attr("class", (d) => {
            return d.type
        });

    SimdLanes = SimdLanes.merge(slenter)
        .text((d) => {
            console.log("siml update");
            return d.type + '-' + d.id + '-' + d.val;
        });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM