1

I have this messy and ugly nested json parse calls(!!) which I am trying to simplify, I was hoping with d3.queue. The first json is used by function doFirstChart to do a chart after some basic typesetting. The function makes the chart and also returns some extra data which are used together with the second json file and another user-defined parameter by the function doSecondChart to do the next chart.

    var c = 'someValue'
    d3.json(countryJson, function (data) {
        data.forEach(function (d) {
            d.Country_Num = +d.Country_Num
            d.y = +d.Y
            d.x = +d.X
        });

       dataOut = doFirstChart(data);

        d3.json(salesJson, function (salesData) {
            salesData.forEach(function (d) {
                d.Expt = +d.Expt
                d.x = +d.x
                d.y = +d.y
            });
            doSecondChart(dataOut, salesData, c)
            console.log("Done!!")
        });
    });

It sounds like d3.queue is the appropriate tool for these situations, I have failed however to make it work even with a simplified example. For example (ignoring the exta parameter c) the following I was hoping to do trick but obviously I am not using it correctly.

d3.queue()
.defer(d3.json, 'path\to\country\data')
.await(doFirstChart)
.defer(d3.json, 'path\to\sales\data')
.await(doSecondChart)

I dont even get right the simplest of all:

 d3.queue()
 .defer(d3.json, 'path\to\country\data')
 .await(doFirstChart)

How is this working please?

5
  • What are you receiving on doFirstChart() function? Can you show the function declaration for it? (with it's declared parameters) Commented Oct 7, 2018 at 17:12
  • which version of D3 are you using Commented Oct 7, 2018 at 17:15
  • @GabrielBalsaCantú: doFirstChart() function takes as argument the data from a json file and renders a scatter plot. Hence it looks like: function sectionChart(data) { // some code }. It returns the location on the Dom where these circles appear ( something like nodes[i].getAttribute('cx') for example) Commented Oct 7, 2018 at 17:29
  • @rioV8: version 4.13.0. Havent tried v5, I dont know something will break, havent checked Commented Oct 7, 2018 at 17:31
  • d3v5 doesn't have d3.queue anymore, use Promises then Commented Oct 7, 2018 at 17:44

1 Answer 1

4

Using Defer after await is throwing you an error, change this:

d3.queue()
  .defer(d3.json, 'path\to\country\data')
  .await(doFirstChart)
  .defer(d3.json, 'path\to\sales\data')
  .await(doSecondChart)

To this:

d3.queue()
  .defer(d3.json, 'path\to\country\data')
  .defer(d3.json, 'path\to\sales\data')
  .await(splitCharts)

Where the function splitCharts(err, ...args) is either:

function splitCharts(err, ...charts){
    doFirstChart(charts[0]);
    doSecondChart(charts[1]);
}

The problem you were having was using defer after and await, and probably your function parameters, where you were not expecting (err, ...args) as parameters.

This example will console.log the queue process, so you can work your way from there:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="http://d3js.org/topojson.v1.min.js"></script>
    <script src="https://d3js.org/d3-queue.v3.min.js"></script>
</head>
<body>
    <script>
        function doFirstChart(err, ...args) {
            console.log('[FUNC]: ', args);
        }

        d3.queue()
            .defer(d3.json, 'https://gist.githubusercontent.com/GbalsaC/db387adae4e84e999960ef79267ceada/raw/0cf2b08280452c7dbb04f81fafcb304bb841bc36/test1.json')
            .defer(d3.json, 'https://gist.githubusercontent.com/GbalsaC/db387adae4e84e999960ef79267ceada/raw/0cf2b08280452c7dbb04f81fafcb304bb841bc36/test1.json')
            .await(doFirstChart)

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

Note: If you want to pass a custom parameter to the .await() callback, you have to define doFirstChart function as such:

function doFirstChart(myParam){
   // Now you'll return an anonymous function as first step
   return (err, ...args) => {
      // Here you'll do your thing, like rendering the data
      console.log('My Param: ', myParam); // Your Custom param
      console.log('[FUNC]: ', args); // As before
   }
}

So, now you can change the <script></script> tag to:

<script>
    const paramTest = 'Testa Rossa';
    function doFirstChart(myParam) {
        return (err, ...args) => {
         console.log('My Param: ', myParam);
         console.log('[FUNC]: ', args);
        }
    }

    d3.queue()
        .defer(d3.json, 'https://gist.githubusercontent.com/GbalsaC/db387adae4e84e999960ef79267ceada/raw/0cf2b08280452c7dbb04f81fafcb304bb841bc36/test1.json')
        .defer(d3.json, 'https://gist.githubusercontent.com/GbalsaC/db387adae4e84e999960ef79267ceada/raw/0cf2b08280452c7dbb04f81fafcb304bb841bc36/test1.json')
        .await(doFirstChart(paramTest)) // do a first param declaration

</script>
Sign up to request clarification or add additional context in comments.

3 Comments

Brilliant! Many thanks!! Do you know how I can pass a used-defined parameter to the await callback please....something like ".await(doFirstChart(myParam))".....which obviously doesnt work
In that case I'll recommend a nested function for doFirstChart,I'll edit my answer to reflect it, don't forget to accept my answer! ;)
That works like a charm! many many thanks, I couldnt understand the examples on queue. I wouldnt have figure out this in 100 years

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.