score:0

Accepted answer

I seem to have found a solution. After boning up on Javascript objects, I re-wrote my code to create and return a chart object that encapsulates the chart properties and methods. I can then call the render method in multiple chart objects to update them individually.

the new chart script:

function AgeChart(chartContainer, data) {

    var chartObj = {

    // public properties
    xAxisLabel: "Alter",
    yAxisLabel: "Anzahl",
    margin: {top: 20, right: 10, bottom: 50, left: 60},
    width: 0,
    height: 0,
    dummyData: 0,
    sizeMax: 0,
    countMax: 0,

    // private properties
    $chartGroup: 0,
    $container: "",
    $d: 0,
    $svg: 0,
    $x: d3.scaleBand()
        .paddingInner(0.16)
        .paddingOuter(0.1),
    $xscale: d3.scaleBand()
        .paddingInner(0.16)
        .paddingOuter(0.1),
    $y: d3.scaleLinear(),
    $xAxis: 0,
    $yAxis: 0,

    // property sets
    get data() { return this.$d; },
    set data(d) {
        this.$d = d;
        this.dummyData = parseAgedData(d);
        this.sizeMax = d.AgeDistribution.DataOwnerSizeMax;
        for (var i = 0; i < this.dummyData.length; i++) {
            if(this.dummyData[i].doCount > this.countMax) {
                this.countMax = chartObj.dummyData[i].doCount;
            }
        };
        this.$xscale.domain(this.dummyData.map(function(d) {
            return d.label;
        }));
        this.$x.domain(this.dummyData.map(function(d,i) {
            return i + 1;
        }))
        this.$y.domain([0, this.countMax]);
    },
    get container() { return this.$container },
    set container(c) {
        this.$container = c;
        updateDimensions();
        this.$svg = d3.select(this.container)
            .append("svg")
            .attr("id", chartObj.container.substring(1) + "Svg")
            .classed("age-chart-canvas", true);
        this.$chartGroup = this.$svg.append("g")
            .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
        this.$yAxis = this.$chartGroup.append("g")
            .attr("class", "axis axis--y");
        this.$xAxis = this.$chartGroup.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0," + this.height + ")");
    },

    // methods
    render: function() {

        updateDimensions();

        this.$xscale.rangeRound([0, this.width]);
        this.$x.rangeRound([0, this.width]);
        this.$y.rangeRound([this.height, 0]);
        this.$yAxis.call(d3.axisLeft(this.$y))
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", "0.71em")
            .attr("text-anchor", "end")
            .text(function(d) {
                return d;
            });
        var chartW = this.width;
        d3.selectAll("g.axis--y g.tick line")
            .attr("x1", function(d) {
                return chartW;
            });
        this.$xAxis.call(d3.axisBottom(this.$xscale));
        d3.selectAll("g.axis--x g.tick line")
            .attr("y2", function(d, i) {
                if(i%2 == 0)
                    return 6;
                else
                    return 16;
            })
            .style("fill", "#bdbdbd");
        d3.selectAll("g.axis--x g.tick text")
            .attr("y", function(d, i) {
                if(i%2 == 0)
                    return 9;
                else
                    return 20;
            });

       }
    };

    chartObj.data = data;
    chartObj.container = chartContainer;
    chartObj.render();

    function updateDimensions() {

        var containerW = getDimension(chartObj.container, "width"),
        containerH = getDimension(chartObj.container, "height");
        chartObj.width = containerW - chartObj.margin.left -   
        chartObj.margin.right;
        chartObj.height = containerH - chartObj.margin.top -   
        chartObj.margin.bottom;

   };

    return chartObj;

};

then on my page I call render() when the window is resized and all charts are updated independently...

    <script type="text/javascript">

        $(document).ready(function() {

            var vData = ageDistributionData;
            var dData = ageDistributionData;
            var mData = ageDistributionData;

            var vChart = AgeChart("#vChart", vData);
            var dChart = new AgeChart("#dChart", dData);
            var mChart = new AgeChart("#mChart", mData);

            window.addEventListener("resize", function() {
                vChart.render();
                dChart.render();
                mChart.render();
            })

        });

    </script>

Any tips or suggestions are most welcome.

score:1

I was also stuck on this same issue. I know you found a solution but I thought I'd offer what I found in case it helps someone else who ends up at this page, since this question more accurately described my problem than anything else I've found.

My solution finally came from the following Stack Overflow post. The answer there explains that you need to add a namespace to the listener, otherwise the existing listener will be removed when a new one is added.

How to have multiple d3 window resize events

For this example, I had to change this code:

    d3.select(window).on("resize", render);

to

    var resizeId = "resize." + scope.chartId
    d3.select(window).on(resizeId, render);

where scope.chartId was a unique id for each chart so that the listener was also unique and would not be removed when a new chart was added.


Related Query