0

I'm trying to build a lwc component that will print a map chart with values from salesforce. In each region I have several accounts and I want to sum all my data for the connected commercial. So I plan to use a SOQL query, retrieve my data and put them in my chart.

But when I look for some example they use CSV file to import values.

var promises = [];
promises.push(d3.json('d3js/map-population/regions.json'));
promises.push(d3.csv("d3js/map-population/population.csv"));

Promise.all(promises).then(function(values) {
    const geojson = values[0];
    const csv = values[1];
    
    var features = deps
        .selectAll("path")
        .data(geojson.features)
        .enter()
        .append("path")
        .attr('id', d => "d" + d.properties.CODE_REG)
        .attr("d", path);

//Some code

csv.forEach(function(e,i) {
    d3.select("#d" + e.CODE_REG)
        .attr("class", d => "region q" + quantile(+e.POP) + "-9")
        .on("mouseover", function(d) {
            div.transition()        
                .duration(200)      
                .style("opacity", .9);
            div.html("<b>Region : </b>" + e.NAME_REGION + "<br>"
                    + "<b>Population : </b>" + e.POP + "<br>")
                .style("left", (d3.event.pageX + 30) + "px")     
                .style("top", (d3.event.pageY - 30) + "px");
        })
        .on("mouseout", function(d) {
                div.style("opacity", 0);
                div.html("")
                    .style("left", "-500px")
                    .style("top", "-500px");
        });
});

Here I want to replace my csv value with a List<Account> from this kind of query SELECT Region__c, PostCode__c, Value1 FROM Account WHERE User = thisUser so in my forEach I want to print the SUM of all my Value1 instead of POP from there example. But I wasn't able to populate my map with my values from Salesforce.

EDIT

My JSON is a map with coordinate with at the end "properties":{"code":"75","name":"Paris"} with code the code of my department name the name of my department. So the JSON map a list of coordinate with my department infos. Here a sample of the CSV they provided :

CODE_REG,NAME_REGION,CODE_DEPT,NAME_DEPT,NB_ARRONDS,NB_CANTONS,NB_COMMUNES,POP
82,Rhône-Alpes,01,Ain,4,43,419,614331
22,Picardie,02,Aisne,5,42,816,555094
83,Auvergne,03,Allier,3,35,320,353124

This is a csv from a tutorial site I used to build my programme. Now I have some difficulties to adapt it. I guessed that in the foreach statement they use the information in the csv to print POPvalue for each department. But now I want to use a List to print my own values from salesforce.

  • Can you add some more details such as current csv sample data, json sample data etc.? Also, what do you mean by "so in my forEach I want to print the SUM of all my Value1 instead of POP from there example" ? May be also provide some screenshot of current output (that uses CSV & JSON). – arut Dec 2 '20 at 8:29
  • @arut I updated my post. Hope it will help. – Jack Dec 2 '20 at 13:06
  • I'm still not clear on how you are trying to interpret the account data into a visual map, but I've tried to answer based on my understanding on what you are looking for. Check if the answer helps. – arut Dec 2 '20 at 19:02
1
+50

In the code sample provided, the following line is resolved via a promise: d3.csv("d3js/map-population/population.csv"). So, what does this line of code do exactly? d3.csv is a method in d3JS that sits on top of d3-fetch API. It parses any csv file supplied to it as input and returns a JS array of objects (made from CSV content). For example, following sample CSV content:

CODE_REG,NAME_REGION,CODE_DEPT,NAME_DEPT,NB_ARRONDS,NB_CANTONS,NB_COMMUNES,POP
82,Rhône-Alpes,01,Ain,4,43,419,614331
22,Picardie,02,Aisne,5,42,816,555094
83,Auvergne,03,Allier,3,35,320,353124

will be parsed and returned as an array (of objects) shown below:

(3) [{...}, {...}, {...}]
 0: {CODE_REG: "82", NAME_REGION: "Rhône-Alpes", CODE_DEPT: "01", NAME_DEPT: "Ain", NB_ARRONDS: "4", NB_CANTONS: "43", NB_COMMUNES: "419", POP: "614331"}
 1: {CODE_REG: "22", NAME_REGION: "Picardie", CODE_DEPT: "02", NAME_DEPT: "Aisne", NB_ARRONDS: "5", NB_CANTONS: "42", NB_COMMUNES: "816", POP: "555094"}
 2: {CODE_REG: "83", NAME_REGION: "Auvergne", CODE_DEPT: "03", NAME_DEPT: "Allier", NB_ARRONDS: "3", NB_CANTONS: "35", NB_COMMUNES: "320", POP: "352124"}
 columns: (8) ["CODE_REG", "NAME_REGION", "CODE_DEPT", "NAME_DEPT", "NB_ARRONDS", "NB_CANTONS", "NB_COMMUNES", "POP"]
  length: 4

This returned JS array is captured into a constant in the line const csv = values[1]; and each entry of this array is processed in the forEach method; where e represents each element in the array and i represents the index #.

csv.forEach(function(e,i) {
    // Do something here
}

How to adapt this in your lightning web component? Let us assume that the apex method getAccounts returns a List<Account> [SOQL used in apex being SELECT Region__c, PostCode__c, Value1 FROM Account WHERE User = thisUser]. Apex method would be called using a wired function in LWC as shown in the code sample below.

@wire(getAccounts)
wiredAccounts(result){
    this.accounts = result.data;
}

The return values from apex received into this.accounts or result.data is already a JS array (of objects) in the following format:

(3) [{...}, {...}, {...}]
 0: {Region__c: "a", PostCode__c: "b", Value1: "10"}
 1: {Region__c: "c", PostCode__c: "d", Value1: "20"}
 2: {Region__c: "e", PostCode__c: "f", Value1: "30"}
  length: 3

Only entry missing in this array is the columns entry (that might be required for d3 JS library). To add this, you can modify your LWC wire adapter code as shown below:

@wire(getAccounts)
wiredAccounts(result){
    this.accounts = result.data.map(e => e);
    // Adds an array entry for the column names
    this.accounts["columns"] = Object.keys(this.accounts[0]);
}

So, the final array (of objects) would be as shown below:

(3) [{...}, {...}, {...}]
 0: {Region__c: "a", PostCode__c: "b", Value1: "10"}
 1: {Region__c: "c", PostCode__c: "d", Value1: "20"}
 2: {Region__c: "e", PostCode__c: "f", Value1: "30"}
 columns: (3) ["Region__c", "PostCode__c", "Value1"]
  length: 4

Now that you have the JS array in the format required by d3JS, you should be able to use the following code (incorporating the same logic from your sample code):

this.accounts.forEach(function(e,i) {
    // Do something there
}

If you wanted to group by Region__c & PostCode__c and find the sum of Value1, you will need to use SOQL aggregate queries in your apex code and the logic to parse/ format the JS array would be same as above snippets (or a small variation of the same).

Note: Your post doesn't give quite a clear picture of the map visually (may be because I'm not an expert in d3JS) and about how you are interpreting the account data into a visual map. So, I've tried to answer considering what is required by d3JS and how you can adapt your sample code into LWC. If this answer doesn't help, I suggest you add more details in your question.

  • Thx, it helped a lot. My problem was that i don't know how does the CSV looks like when converted in array. So adding the columns section help a lot ! – Jack Dec 3 '20 at 9:53
  • 1
    You can debug the JS code in chrome dev tools and look up the structure of the variables. You can google out and find resources to understand debugging JS. For example, Debugging in Chrome, Debug LWC etc. – arut Dec 3 '20 at 10:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.