Salesforce LWC With Third Party JS : D3



Salesforce Lightning Web Component With Third Party JS : D3

Third-Party JavaScript Libraries

Using JavaScript to manipulate the DOM isn’t recommended because the Lightning Web Components engine does it more efficiently. However, there are some third-party JavaScript libraries that take over the DOM.

Manipulate the DOM with JavaScript

Using JavaScript to manipulate the DOM isn’t recommended because the Lightning Web Components engine does it more efficiently. However, there are some third-party JavaScript libraries that take over the DOM.

If a call to appendChild() manipulates the DOM, styling isn’t applied to the appended element.

When using these libraries in a Lightning web component, add lwc:dom="manual" to any HTML element that you want to manipulate with JavaScript. When the engine sees the directive, it preserves encapsulation.

Add the lwc:dom="manual" directive to an empty native HTML element. The owner of the component calls appendChild() on that element to manually insert the DOM.



<template>
    <div lwc:dom="manual"></div>
</template>


Download D3

Download D3 at d3js.com. Upload d3.zip to your Salesforce organization as a static resource.

In the component’s JavaScript class, import loadStyle and loadScript from lightning/platformResourceLoader. Import the d3 static resource as well. Note that D3 is the static resource reference for loading the resources, and d3 is the name of the static resource uploaded to Salesforce.

NOTE : In a Lightning web component, you can’t use document to query for DOM elements. Instead, use this.template. For example, this D3 code sample uses this.template.querySelector('svg.d3'). See DOM Access Containment.

I've created Lighting Web Component With D3 to Show Family Relationship and code is below :

Apex Class



public class AccountWithContactsController {
	@AuraEnabled(cacheable=true)
    public static list<Account> getAccountAndContacts(String recordId){
        //string accountId
        List<Account> lstAccount = new List<Account>([SELECT Id, Name,(Select Id,Name From Contacts) FROM Account WHERE Id =:recordId]);
        return lstAccount;
    }
}



LWC : Template (HTML Code)



<template>    
    <lightning-card title="Family Relationships" icon-name="custom:custom19">
         <div class="slds-m-around_medium">
            <svg
                class="d3"
                width={svgWidth}
                height={svgHeight}
                lwc:dom="manual"
            ></svg>
        </div> 
    </lightning-card>
</template>



LWC : JS (Process Code)



/* global d3 */
import { LightningElement,track,api } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
//Static Resource
import D3 from '@salesforce/resourceUrl/D3';
import getAccountAndContacts from '@salesforce/apex/AccountWithContactsController.getAccountAndContacts';

export default class FamilyTreeD3 extends LightningElement {
    svgWidth = 800;
    svgHeight = 500;
    @api recordId;
    d3Initialized = false;
    @track account;
    renderedCallback() {
        if (this.d3Initialized) {
            return;
        }
        this.d3Initialized = true;

        Promise.all([
            loadScript(this, D3 + '/d3.v5.min.js'),
            loadStyle(this, D3 + '/style.css')
        ])
            .then(() => {
                this.initializeD3();
            })
            .catch(error => {
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Error loading D3',
                        message: error.message,
                        variant: 'error'
                    })
                );
            });
    }

    initializeD3() {
        // Example adopted from https://bl.ocks.org/mbostock/2675ff61ea5e063ede2b5d63c08020c7
        const svg = d3.select(this.template.querySelector('svg.d3'));
        const width = this.svgWidth;
        const height = this.svgHeight;
        const color = d3.scaleOrdinal(d3.schemeDark2);
        getAccountAndContacts({
            recordId : this.recordId
        })
            .then(result => {
                let nodes=[]; 
                let links=[];
                for(let i=0;i<result.length;i++){
                    nodes.push({id:result[i].Name,group: 1,label:result[i].Name,color: "#e12870"});
                    if(result[i].Contacts.length > 0){
                        for(let c=0;c<result[i].Contacts.length;c++){
                            nodes.push({id:result[i].Contacts[c].Id,group: 1, label:result[i].Contacts[c].Name,color: "#36b8f1"});                           
                            links.push({ source: result[i].Contacts[c].Id, target: result[i].Name, value: (10+i) });                            
                        }
                    }
                }
                console.log('nodes ',nodes);
                console.log('links ',links);


                const simulation = d3
                    .forceSimulation()
                    .force(
                        'link',
                        d3.forceLink().id(d => {
                            return d.id;
                        })
                        .distance(function (d) {
                            return 151;
                        })
                        
                    )
                    .force('charge', d3.forceManyBody())
                    .force('center', d3.forceCenter(width / 2, height / 2))
                    .force("collide", d3.forceCollide(71).iterations(10))
                    

                const link = svg
                    .append('g')
                    .attr('class', 'links')
                    .selectAll('line')
                    .data(links)
                    .enter()
                    .append('line')
                    .attr('stroke-width', d => {
                        return Math.sqrt(d.value);
                    });
                    
                    const node = svg
                    .selectAll('circle')
                    .data(nodes)
                    .enter()
                    .append('g')   
                    .attr('class', 'nodes');
                    

                    node.append("circle")
                    .attr("r", 71)
                    .attr("fill", function(d) { return d.color; });
                    node.append("text")
                    .text(function(d) { return d.label; });

                simulation.nodes(nodes).on('tick', ticked);

                simulation.force('link').links(links);

                
                
                function ticked() {
                    link.attr('x1', d => d.source.x)
                        .attr('y1', d => d.source.y)
                        .attr('x2', d => d.target.x)
                        .attr('y2', d => d.target.y)
                        //.attr('x3', d => d.target.x)
                        //.attr('y3', d => d.target.y);
                        //node.attr('cx', d => d.x).attr('cy', d => d.y);
                        node.attr("transform", function (d) {
                            return "translate(" + d.x + "," + d.y + ")";
                        });
                    
                }

                function dragstarted(d) {
                    if (!d3.event.active) {
                        simulation.alphaTarget(0.3).restart();
                    }
                    d.fx = d.x;
                    d.fy = d.y;
                }

                function dragged(d) {
                    d.fx = d3.event.x;
                    d.fy = d3.event.y;
                }

                function dragended(d) {
                    if (!d3.event.active) {
                        simulation.alphaTarget(0);
                    }
                    d.fx = null;
                    d.fy = null;
                }
                


                
            })
            .catch(error => {
                this.error = error;
            });
        
    }
    
}



LWC : XML (Config Code)



<template>    
<!--xml version="1.0" encoding="UTF-8"?-->
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>50.0</apiVersion>
   <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
</template>



LWC :Output


Happy Sharing...

Everyone has their own favorites, so please feel free to share with yours contacts and comments below for any type of help!

Comments

  1. Excellent article for the people who need information about this course.
    Learn Data Science Online

    ReplyDelete
  2. Thanks for sharing such informative blog. Best netsuite integration company provides professional custom API development and integration services. Hire our experienced API developers and programmers for API integration service.
    system integration services

    ReplyDelete

Post a Comment

Popular posts from this blog

Salesforce LWC : Compact Layout on Hover

Communications between Lightning Components : Salesforce