简体   繁体   中英

How to update d3.js stacked area chart?

I have a stacked area chart built in d3.js and I want to update how the data is displayed on a button click-- showing absolute numbers, relative numbers, and displaying the data as a silhouette. I have worked out how to create these three formats with my data, but when I update the chart, it redraws it rather than updating the stacked areas. I'm not able to see what I'm doing wrong. I would greatly appreciate if someone could help!

My code is below, and can also be viewed in this Plunker: https://plnkr.co/edit/Y5zmRLnSJu0SALj3?open=lib%2Fscript.js

<!DOCTYPE html>
<meta charset="utf-8">
<style>
    body {
        font: 12px sans-serif;
    }

    .axis path,
    .axis line {
        fill: none;
        stroke: none;
        shape-rendering: crispEdges;
    }

    .browser text {
        text-anchor: end;
    }
</style>

<body>

    <script src="https://d3js.org/d3.v4.js"></script>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>

    <div id="chartType">
        <div class="form-check form-check-inline">
            <input type="radio" name="ctype" class="chartTypeRadio" value="Number" checked>
            <label class="charttype">Number</label>
            <input type="radio" name="ctype" class="chartTypeRadio" value="Percent">
            <label class="charttype">Percent</label>
            <input type="radio" name="ctype" class="chartTypeRadio" value="Silhouette">
            <label class="charttype">Silhouette</label>
        </div>
    </div>

    <div id="chart">
    </div>

</body>

<script>

    var select2 = d3.selectAll(".chartTypeRadio")
        .on("change", function () {
            let type = $("input[type='radio'][name='ctype']:checked").val();
            console.log('type', type)
            chartType(type, 750)
        })

    var margin = { top: 50, right: 0, bottom: 30, left: 50 },
        width = 740 - margin.left - margin.right,
        height = 400 - margin.top - margin.bottom;

    var parseDate = d3.timeParse("%m/%d/%Y");

    var formatSi = d3.format(".3s");

    var formatNumber = d3.format(".1f"),
        formatThousand = function (x) { return formatNumber(x / 1e3); };

    var x = d3.scaleTime()
        .range([0, width]);

    var y = d3.scaleLinear()
        .range([height, 0]);

    var color = d3.scaleOrdinal()
        .domain(["18 to 25", "26 to 34", "35 to 39", "40 to 44", "45 & Over"])
        .range(["#EF4136", "#56423E", "#BEA6A1", "#00A0AA", "#006976"])

    var xAxis = d3.axisBottom(x).ticks(5)

    var yAxis = d3.axisLeft(y)

    var area = d3.area()
        .x(function (d) {
            return x(d.data.date);
        })
        .y0(function (d) { return y(d[0]); })
        .y1(function (d) { return y(d[1]); });

    var stack = d3.stack()

    var svg = d3.select('body').append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

    chartType('Number', 750)

    function chartType(type, speed) {
        console.log('type', type)

        d3.csv('data.csv', function (error, data) {
            color.domain(d3.keys(data[0]).filter(function (key) { return key !== 'date'; }));
            var keys = data.columns.filter(function (key) { return key !== 'date'; })
            data.forEach(function (d) {
                d.date = parseDate(d.date);
            });

            var maxDateVal = d3.max(data, function (d) {
                var vals = d3.keys(d).map(function (key) { return key !== 'date' ? d[key] : 0 });
                return d3.sum(vals);
            });

            x.domain(d3.extent(data, function (d) { return d.date; }));
            y.domain([0, maxDateVal])

            if (type == 'Percent') {
                y.domain([0, 1])
            }
            else if (type == 'Silhouette') {
                y.domain([-maxDateVal / 2, maxDateVal / 2])
            }
            stack.keys(keys);

            stack.order(d3.stackOrderNone);
            stack.offset(d3.stackOffsetNone);
            if (type == 'Percent') {
                stack.offset(d3.stackOffsetExpand);
            }
            else if (type == 'Silhouette') {
                stack.offset(d3.stackOffsetSilhouette)
            }

            var segments = svg.append('g').attr('class', 'segments')

            var segment = segments.selectAll('path')
                .data(stack(data))

            segment.enter()
                .append('path')
                .attr('class', 'segment')
                .merge(segment);

            segments.selectAll('.segment')
                .transition().duration(850).ease(d3.easeCubicInOut)
                .attr('d', area)
                .style('fill', function (d) { return color(d.key); });

            segment.exit().remove();

            svg.selectAll(".axis").remove();

            svg.append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(0,' + height + ')')
                .call(xAxis);

            svg.append('g')
                .attr('class', 'y axis')
                .call(yAxis);

            var legend = svg.selectAll(".legend")
                .data(stack(data))
                .enter()
                .append("g")
                .attr("class", "legend")
                .attr("transform", "translate(" + (0) + "," + -40 + ")");

            legend.append("rect")
                .attr("x", function (d, i) { return 100 * i; })
                .attr("y", 0)
                .attr("width", 10)
                .attr("height", 10)
                .style('fill', function (d) { return color(d.key); })

            legend.append("text")
                .attr("dx", "1.15em")
                .attr("x", function (d, i) { return 100 * i; })
                .attr("y", 10)
                .text(function (d) {
                    return d.key
                })


        });
    }



</script>
</body>
</html>

Your segments group is recreated each time you choose another type of chart.

Replace:

var segments = svg.append('g').attr('class', 'segments')

with:

var segments = svg.select('g.segments');
if (!segments.node())
  segments = svg.append('g').attr('class', 'segments')

See it working here .

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