Capturing/Saving the current state of d3.js Sunburst Chart

独自空忆成欢 提交于 2019-12-10 12:12:30

问题


I am a newbie to d3.js . I am working in d3.js zoomable sunburst chart http://bl.ocks.org/mbostock/4348373. When the user zoom into a particular arc and I need to capture this state of the sunburst diagram . When the user comes back to the sunburst diagram or load the graph again he should see the state where he left.

Note : I dont want to serialise the svg elements to show the state of the sunburst. If i serialise it then the chart will be static and user cant click on the sunburst and traverse to other arcs.

Proposed Solution : one solution came to my mind is simulate mouse clicks on the sunburst nodes till the last node user looks into. I am not able to devise an algorithm for this . Please guide me whether any other solution is possible ..


回答1:


The approach you said is easy to implement. I have made a small sample for it. Click the Start Save button to start saving the state of Sunburst. Click Stop Save button after performing a few zooming actions. You can make any further changes to the chart. Now, clicking Load button will show you the saved state of the chart.

var width = 500,
    height = 500,
    radius = Math.min(width, height) / 2;


var x = d3.scale.linear()
    .range([0, 2 * Math.PI]);

var y = d3.scale.sqrt()
    .range([0, radius]);

var color = d3.scale.category10();

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ") rotate(-90 0 0)");

var partition = d3.layout.partition()
    .value(function(d) {
        return d.size;
    });

var arc = d3.svg.arc()
    .startAngle(function(d) {
        return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
    })
    .endAngle(function(d) {
        return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
    })
    .innerRadius(function(d) {
        return Math.max(0, y(d.y));
    })
    .outerRadius(function(d) {
        return Math.max(0, y(d.y + d.dy));
    });

var root = getData();
var savedData = partition.nodes(root);
var g = svg.selectAll("g")
    .data(partition.nodes(root))
    .enter().append("g");

var path = g.append("path")
    .attr("d", arc)
    .style("fill", function(d) {
        return color((d.children ? d : d.parent).name);
    })
    .on("click", click);

var text = g.append("text")
    .attr("x", function(d) {
        return y(d.y);
    })
    .attr("dx", "6") // margin
    .attr("dy", ".35em") // vertical-align
    .attr("transform", function(d) {
        return "rotate(" + computeTextRotation(d) + ")";
    })
    .text(function(d) {
        return d.name;
    })
    .style("fill", "white");

function computeTextRotation(d) {
        var angle = x(d.x + d.dx / 2) - Math.PI / 2;
        return angle / Math.PI * 180;
    }
    
var saveData = false;
var savedData = [];
d3.select("#saveBtn").on("click", function() {
    if (d3.select(this).attr("value") == "Start Save") {
        savedData = [];
        d3.select(this).attr("value", "Stop Save");
        saveData = true;
    } else {
        d3.select(this).attr("value", "Start Save");
        saveData = false;
    }
});
d3.select("#loadBtn").on("click", function() {
    var root = g.filter(function(d) {
        return d.name == "Root"
    }).data();
    click(root[0]);
    savedData.forEach(function(val) {
        var node = g.filter(function(d, i) {
            return i == val
        }).data();
        click(node[0]);
    });
});

function click(d, i) {       
        if (saveData) {
            if(d.name=="Root"){
               savedData = [];
            } else{
                savedData.push(i);
            }
        }
        // fade out all text elements
        if (d.size !== undefined) {
            d.size += 100;
        };
        text.transition().attr("opacity", 0);

        path.transition()
            .duration(750)
            .attrTween("d", arcTween(d))
            .each("end", function(e, i) {
                // check if the animated element's data e lies within the visible angle span given in d
                if (e.x >= d.x && e.x < (d.x + d.dx)) {
                    // get a selection of the associated text element
                    var arcText = d3.select(this.parentNode).select("text");
                    // fade in the text element and recalculate positions
                    arcText.transition().duration(750)
                        .attr("opacity", 1)
                        .attr("transform", function() {
                            return "rotate(" + computeTextRotation(e) + ")"
                        })
                        .attr("x", function(d) {
                            return y(d.y);
                        });
                }
            });
    } 

// Word wrap!
var insertLinebreaks = function(t, d, width) {
    alert(0)
    var el = d3.select(t);
    var p = d3.select(t.parentNode);
    p.append("g")
        .attr("x", function(d) {
            return y(d.y);
        })          
        .attr("transform", function(d) {
            return "rotate(" + computeTextRotation(d) + ")";
        })           
        .append("foreignObject")
        .attr('x', -width / 2)
        .attr("width", width)
        .attr("height", 200)
        .append("xhtml:p")
        .attr('style', 'word-wrap: break-word; text-align:center;')
        .html(d.name);
    alert(1)
    el.remove();
    alert(2)
};



d3.select(self.frameElement).style("height", height + "px");

// Interpolate the scales!
function arcTween(d) {
    var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
        yd = d3.interpolate(y.domain(), [d.y, 1]),
        yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
    return function(d, i) {
        return i ? function(t) {
            return arc(d);
        } : function(t) {
            x.domain(xd(t));
            y.domain(yd(t)).range(yr(t));
            return arc(d);
        };
    };
}

function getData() {
    return {
        "name": "Root",
        "children": [{
            "name": "A1",
            "children": [{
                "name": "B1",
                "size": 30
            }, {
                "name": "B2",
                "size": 40
            }, {
                "name": "B3",
                "children": [{
                    "name": "C1",
                    "size": 10
                }, {
                    "name": "C2",
                    "size": 15
                }]
            }]
        }, {
            "name": "A2",
            "children": [{
                "name": "B4",
                "size": 40
            }, {
                "name": "B5",
                "size": 30
            }, {
                "name": "B6",
                "size": 10
            }]
        }, {
            "name": "A3",
            "children": [{
                    "name": "B7",
                    "size": 50
                }, {
                    "name": "B8",
                    "size": 15
                }

            ]
        }]
    }
};
path {
    stroke: #fff;
    fill-rule: evenodd;
}
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="main"></div>
<input type="button" value="Start Save" id="saveBtn"/>
<input type="button" value="Load" id="loadBtn"/>

I don't know where do you plan to save the state of the sunburst. I would suggest that Localstorage would be a nice option.

Hope this helps.



来源:https://stackoverflow.com/questions/29739838/capturing-saving-the-current-state-of-d3-js-sunburst-chart

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!