Capturing/Saving d3.js Sunburst 图表的当前状态

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

我是 d3.js 的新手。我在 d3.js 可缩放旭日图 http://bl.ocks.org/mbostock/4348373 中工作。当用户放大特定弧线时,我需要捕捉旭日图的这种状态。当用户返回旭日图或再次加载图表时,他应该看到他离开时的状态。

注意:我不想序列化 svg 元素来显示旭日的状态。如果我对其进行序列化,那么图表将是静态的,用户无法单击旭日并遍历其他弧线。

建议的解决方案: 我想到的一个解决方案是模拟鼠标点击 sunburst 节点,直到最后一个节点用户查看为止。 我无法为此设计算法。 请指导我是否还有其他解决方案..

你说的方法很容易实现。我为它做了一个小样本。 单击 Start Save 按钮开始保存 Sunburst 的状态。执行一些缩放操作后单击 Stop Save 按钮。您可以对图表进行任何进一步的更改。现在,单击 Load 按钮将显示图表的保存状态。

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"/>

不知道你打算把旭日的状态保存到哪里。我建议 Localstorage 是一个不错的选择。

希望这对您有所帮助。