Javascript d3.js-如何更新图表数据?

Javascript d3.js-如何更新图表数据?,javascript,d3.js,transition,Javascript,D3.js,Transition,我学习D3.js旅程中的另一个步骤 我有一个简单的可重用图表,我称之为“聚类图”,我试图让我的头脑简单地更新一些值,而不增加或减少任何元素 这里有一把小提琴: 图表脚本如下所示: function clusterChart() { var width = 500, radiusAll = 90, maxRadius = radiusAll - 5, padding = 8, height = 3 * (radius

我学习D3.js旅程中的另一个步骤

我有一个简单的可重用图表,我称之为“聚类图”,我试图让我的头脑简单地更新一些值,而不增加或减少任何元素

这里有一把小提琴:

图表脚本如下所示:

    function clusterChart() {
    var width = 500,
        radiusAll = 90,
        maxRadius = radiusAll - 5,
        padding = 8, 
        height = 3 * (radiusAll*2 + padding),
        startAngle = Math.PI / 2,
        val = function(d) { return d; },
        onTotalMouseOver = null,
        onTotalClick = null,
        onClusterMouseOver = null,
        onClusterClick = null;

    function chart(selection) {
        selection.each(function(data) {

            var cx = width / 2,
                cy = height / 2,
                stepAngle = 2 * Math.PI / data.Clusters.length,
                outerRadius = 2*radiusAll + padding;


            //  Remove svg, if already exist
            d3.select(this).select('svg').remove();

            //cluster radius range and scale
            var r = d3.scale.linear()
                        .domain([0, d3.max(data.Clusters, function(d){return d[1];})])
                        .range([50, maxRadius]);

            //  Add svg element
            var svg = d3.select(this).append('svg')
                .attr('class', 'cluster-chart')
                .attr("viewBox", "0 0 " + width + " " + height )
                .attr("preserveAspectRatio", "xMidYMin meet")
                .attr('width', width)
                .attr('height', height);

            //  Total group value
            var totalCluster = svg.append('g')
                .attr('class', 'total-cluster');

            totalCluster.append('circle')
                .attr('cx', cx)
                .attr('cy', cy)
                .attr('r', radiusAll)
                .on('mouseover', onTotalMouseOver)
                .on('click', onTotalClick);

            totalCluster.append('text')
                .attr('class', 'value')
                .attr('x', cx)
                .attr('y', cy + 4)
                .text(val(data.Value));

            totalCluster.append('text')
                .attr('class', 'group-name')
                .attr('x', cx)
                .attr('y', cy + 16)
                .text(val(data.Name));

            //  Clusters values
            var cluster =  svg.selectAll('g.cluster')
                .data(data.Clusters)
                .enter().append('g')
                .attr('class', function(d, i) { 
                    if(d[1] === 0){ return 'cluster empty'}
                    else {return 'cluster'}
                });

            cluster.append('circle')
                .attr('cx', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
                .attr('cy', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius; })
                .attr("r", function (d, i) { return r(d[1]); })
                .on('mouseover', function(d, i, j) {
                    //do something
                    if (onClusterMouseOver != null) onClusterMouseOver(d, i, j);
                })
                .on('mouseout', function() {
                    //do something
                })
                .on('click', function(d, i){ onClusterClick(d); });  

            cluster.append('text')
                .attr('class', 'value')
                .attr('x', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
                .attr('y', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius - 4; })
                .text(function(d) { return val(d[1]); });

            cluster.append('text')
                .attr('class', 'group-name')
                .attr('x', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
                .attr('y', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius + 16; })
                .text(function(d) { return val(d[0]); });

            $(window).resize(function() {
              var w = $('.cluster-chart').width(); //make this more generic
              svg.attr("width", w);
              svg.attr("height", w * height / width);
            });

        });


    }


    chart.width = function(_) {
        if (!arguments.length) return width;
        width = _;
        return chart;
    };

    chart.height = function(_) {
        if (!arguments.length) return height;
        height = _;
        return chart;
    };

    chart.val = function(_) {
        if (!arguments.length) return val;
        val = _;
        return chart;
    };

    chart.onClusterClick = function(_) {
        if (!arguments.length) return onClusterClick;
        onClusterClick = _;
        return chart;
    };

    return chart;
 }
.datum({
    Name: 'Total Widgets',
    Value: 150,
    Clusters: [
        ['Other', 25],
        ['FooBars', 25],
        ['Foos', 25],
        ['Bars', 75],
        ['BarFoos', 0]
    ]
})
我这样称呼这个图表:

d3.select('#clusters')
.datum({
    Name: 'Total Widgets',
    Value: 224,
    Clusters: [
        ['Other', 45],
        ['FooBars', 30],
        ['Foos', 50],
        ['Bars', 124],
        ['BarFoos', 0]
    ]
})
.call( clusterChart() );
最终,数据将来自一个json文件,但目前它在函数中

假设我想在单击#doSomething按钮时更新值,更新的数据如下所示:

    function clusterChart() {
    var width = 500,
        radiusAll = 90,
        maxRadius = radiusAll - 5,
        padding = 8, 
        height = 3 * (radiusAll*2 + padding),
        startAngle = Math.PI / 2,
        val = function(d) { return d; },
        onTotalMouseOver = null,
        onTotalClick = null,
        onClusterMouseOver = null,
        onClusterClick = null;

    function chart(selection) {
        selection.each(function(data) {

            var cx = width / 2,
                cy = height / 2,
                stepAngle = 2 * Math.PI / data.Clusters.length,
                outerRadius = 2*radiusAll + padding;


            //  Remove svg, if already exist
            d3.select(this).select('svg').remove();

            //cluster radius range and scale
            var r = d3.scale.linear()
                        .domain([0, d3.max(data.Clusters, function(d){return d[1];})])
                        .range([50, maxRadius]);

            //  Add svg element
            var svg = d3.select(this).append('svg')
                .attr('class', 'cluster-chart')
                .attr("viewBox", "0 0 " + width + " " + height )
                .attr("preserveAspectRatio", "xMidYMin meet")
                .attr('width', width)
                .attr('height', height);

            //  Total group value
            var totalCluster = svg.append('g')
                .attr('class', 'total-cluster');

            totalCluster.append('circle')
                .attr('cx', cx)
                .attr('cy', cy)
                .attr('r', radiusAll)
                .on('mouseover', onTotalMouseOver)
                .on('click', onTotalClick);

            totalCluster.append('text')
                .attr('class', 'value')
                .attr('x', cx)
                .attr('y', cy + 4)
                .text(val(data.Value));

            totalCluster.append('text')
                .attr('class', 'group-name')
                .attr('x', cx)
                .attr('y', cy + 16)
                .text(val(data.Name));

            //  Clusters values
            var cluster =  svg.selectAll('g.cluster')
                .data(data.Clusters)
                .enter().append('g')
                .attr('class', function(d, i) { 
                    if(d[1] === 0){ return 'cluster empty'}
                    else {return 'cluster'}
                });

            cluster.append('circle')
                .attr('cx', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
                .attr('cy', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius; })
                .attr("r", function (d, i) { return r(d[1]); })
                .on('mouseover', function(d, i, j) {
                    //do something
                    if (onClusterMouseOver != null) onClusterMouseOver(d, i, j);
                })
                .on('mouseout', function() {
                    //do something
                })
                .on('click', function(d, i){ onClusterClick(d); });  

            cluster.append('text')
                .attr('class', 'value')
                .attr('x', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
                .attr('y', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius - 4; })
                .text(function(d) { return val(d[1]); });

            cluster.append('text')
                .attr('class', 'group-name')
                .attr('x', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
                .attr('y', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius + 16; })
                .text(function(d) { return val(d[0]); });

            $(window).resize(function() {
              var w = $('.cluster-chart').width(); //make this more generic
              svg.attr("width", w);
              svg.attr("height", w * height / width);
            });

        });


    }


    chart.width = function(_) {
        if (!arguments.length) return width;
        width = _;
        return chart;
    };

    chart.height = function(_) {
        if (!arguments.length) return height;
        height = _;
        return chart;
    };

    chart.val = function(_) {
        if (!arguments.length) return val;
        val = _;
        return chart;
    };

    chart.onClusterClick = function(_) {
        if (!arguments.length) return onClusterClick;
        onClusterClick = _;
        return chart;
    };

    return chart;
 }
.datum({
    Name: 'Total Widgets',
    Value: 150,
    Clusters: [
        ['Other', 25],
        ['FooBars', 25],
        ['Foos', 25],
        ['Bars', 75],
        ['BarFoos', 0]
    ]
})
如何更新该数据,并随着半径的变化进行良好的过渡?

更新:好的,我意识到一行几乎抹去了我“更新”图表的能力

//  Remove svg, if already exist
d3.select(this).select('svg').remove();
相反,我应该这样做:

//  Add svg element
var svg = d3.select(this).selectAll('svg')
所以我不会抹掉整个图表。但即使这样,我也不知道如何使用新数据进行更新


有什么线索吗?

原则上,您所要做的就是绑定新数据,更新半径的比例,然后运行代码根据绑定的数据设置半径。@Larskothoff谢谢-原则上是的。我对d3的了解还有很大差距。我真的不明白如何在不重新绘制整个图表的情况下只获取我想要的部分图表代码。将研究生命周期事件演示以获取线索