0

I have the following situation: Three different JSON files need to be loaded before firing the function to generate the chart. Here's the code:

<div id="jsonloading"></div>
<div id="chartc3"></div>
<script>
    var scene;
    var surchargedata;
    var ratiodata;
    var variables;

    $.getJSON('/assets/json/surcharge.json', function(data) {
        surchargedata = data;
        console.log(surchargedata);
    });

    $.getJSON('/assets/json/ratio.json', function(data) {
        ratiodata = data;
        console.log(ratiodata);
    });

    $.getJSON('/assets/json/variables.json', function(data) {
        variables = data;
        console.log(variables);
    });

    $.getJSON('/assets/json/chartc3.json', function(data) {
        console.log("chartc3");
        console.log(surchargedata);
        console.log(ratiodata);
        console.log(variables);
        //Max value for y-axis
        scene = data;
        var maxs = 0;
        for (var j = 0; j < scene.length; j++) {
            var maxtemp = Math.max(scene[j].Marketable, scene[j]['Your Bid'], scene[j]['Total Requested Capacity']);
            maxs = Math.max(maxs, maxtemp);
        }

        //Chart
        var chart = c3.generate({
            bindto: '#chartc3',
            data: {
                json: scene,
                selection: {
                    enabled: false
                },
                keys: {
                    x: 'round',
                    value: ['Marketable', 'Total Requested Capacity', 'Your Bid'],
                },
                types: {
                    Marketable: 'area'
                },
                colors: {
                    Marketable: '#EBEBEB',
                        'Total Requested Capacity': '#272E80',
                        'Your Bid': '#00888A'
                }
            },
            point: {
                show: false
            },
            axis: {
                x: {
                    type: 'category',
                    label: {
                        text: 'Round Number',
                        position: 'outer-center',
                    }
                },
                y: {
                    min: 0,
                    padding: {
                        bottom: 0
                    },
                    tick: {
                        values: [
                            [0],
                            [maxs]
                        ],
                        format: function(d) {
                            return d3.format(',f')(d) + " " + variables.unit
                        }
                    }
                }
            },
            grid: {
                y: {
                    lines: [{
                        value: 10000000,
                        text: 'Value'
                    }]
                },
            },
            legend: {
                position: 'right'
            },
            regions: [{
                axis: 'x',
                start: 29,
                end: 34,
                class: 'regionX'
            }, ],
            tooltip: {
                contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
                    var $$ = this,
                        config = $$.config,
                        CLASS = $$.CLASS,
                        titleFormat = config.tooltip_format_title || defaultTitleFormat,
                        nameFormat = config.tooltip_format_name || function(name) {
                            return name;
                        },
                        valueFormat = config.tooltip_format_value || defaultValueFormat,
                        text, i, title, value, name, bgcolor;

                    var count = 0;
                    for (i = 0; i < d.length; i++) {
                        if (!(d[i] && (d[i].value || d[i].value === 0))) {
                            continue;
                        }

                        if (!text) {
                            title = 'Round:' + scene[d[i].index].round + ', Ratio: ' + ratiodata[d[i].index].ratio + " %";
                            text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
                        }

                        name = nameFormat(d[i].name);
                        value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
                        bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);

                        text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
                        text += "<td class='name'><span style='background-color:" + bgcolor + "; border-radius: 5px;'></span>" + name + "</td>";
                        text += "<td class='value'>" + value + "</td>";
                        text += "</tr>";
                    } //for

                    text += "<tr class='" + CLASS.tooltipName + "-Surcharge" + "'>";
                    text += "<td id='footer'>" + "Surcharge: " + surchargedata[d[0].index].Surcharge + "</td>";
                    text += "<td id='footer'></td>";
                    text += "</tr></table>";

                    return text;
                }
            }

        }); //end chart
        //chart.select(['Marketable'], [31,32,33]);
    }); //end getjson
</script>

I know that getJson() is asynchronous and so I cant't be sure to load all of the data before firing the function for the chart (generate()). Besides I can't use the attribute async=false because it is deprecated.

What is the best solution to guarantee the right behavior?

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
Silvio S.
  • 547
  • 5
  • 20

2 Answers2

1

You can store the promises returned from the $.getJSON calls in an array. You can then provide this array to $.when to execute the chart initialisation code once all the requests have completed. Try this:

var promises = []
promises.push($.getJSON('/assets/json/surcharge.json', function(data) { 
    surchargedata = data;
}));
promises.push($.getJSON('/assets/json/ratio.json', function(data) { 
    ratiodata = data;
}));
promises.push($.getJSON('/assets/json/variables.json', function(data){ 
    variables = data;
}));

$.when.apply(this, promises).done(function() {
    $.getJSON('/assets/json/chartc3.json', function(data) { 
        // setup chart here...
    });
});

Note however that it would be better to combine surcharge.json, ratio.json and variables.json to a single object which can be retrieved in one call.

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
0

I solved in this way:

   <script>

    var sceneround;
    var surcharge;
    var ratiodata;
    var variables;

 $.ajax({
            url: '/assets/json/surcharge.json',
            dataType: 'json',

            success: function (response) {
                surcharge=response;
              Ratio();
            }
        }); 

function Ratio() {
 $.ajax({
            url: '/assets/json/ratio.json',
            dataType: 'json',

            success: function (response) {
                ratiodata=response;
              Variables();
            }
        }); 
};

function Variables() {
 $.ajax({
            url: '/assets/json/variables.json',
            dataType: 'json',

            success: function (response) {
               variables=response; 
              DrawChart();
            }
        }); 
};


function DrawChart() {
$.getJSON('/assets/json/chartc3.json', function(data) 
{ 

    //Max value for y-axis
    sceneround=data;
Silvio S.
  • 547
  • 5
  • 20
  • ***Never*** use `async: false`. It is incredibly bad practice as it will completely lock the browser until the requests complete. - this will appear to the user as though the browser has actually crashed. – Rory McCrossan Jul 07 '15 at 13:21
  • Sorry I was wrong, it is the same without async: false in this case. Every function will be fired after the first. Is it all right ? – Silvio S. Jul 07 '15 at 13:27
  • This solution will work, however the downside is that the requests will be called one after the other. With my solution below all the requests will be called at the same time, so it will be much quicker. Did you try it? – Rory McCrossan Jul 07 '15 at 13:29
  • By the way : here http://stackoverflow.com/questions/31137088/c3js-add-an-attribute-in-the-json-file-and-read-it-in-my-chart my old question – Silvio S. Jul 07 '15 at 13:29
  • Yes but in that case the lower bound will be the element where there are more data. In any case you will have to wait for the slower getJson() is it all right ? (your solution is surely quicker) – Silvio S. Jul 07 '15 at 13:32
  • That's right, in my example, if the requests take 5, 10 and 15 seconds respectively, my code will complete in 15 seconds. Yours would take 30 seconds. – Rory McCrossan Jul 07 '15 at 13:33