Lightning ComponentでLightning ContainerなしでD3.jsを使う #salesforce

凝ったチャートを作りたい場合、D3.jsを使いたいことがあります。

Lightning ComponentでD3.jsを使う場合、v3以下だと以下のようなエラーが起き、表示できません。

[Cannot read property 'document' of undefined] eval()@https://xxxxxx-dev-ed.lightning.force.com/resource/1537117226000/d3lib/d3lib/d3.v3.min.js:3:4187 Proxy.eval()@https://xxxxxx-dev-ed.lightning.force.com/resource/1537117226000/d3lib/d3lib/d3.v3.min.js:5:23548

Lightning Containerを使えば回避できそうですが、d3 v4を使えば、Lightning Containerなしでも表示できました(v5は未確認)。

サンプル

f:id:jappy:20180917154203p:plain

ChromeとIE11での動作を確認しています。

Component

D3のライブラリは静的リソースから読み込みます。バージョンは4.13.0です。

<aura:component implements="flexipage:availableForAllPageTypes">
    <ltng:require scripts="{!join(',',
                  $Resource.d3lib + '/d3lib/d3.min.js')}"
                  afterScriptsLoaded="{!c.initD3Charts}" />
    
    <lightning:card>
        <div id="chart"></div>
    </lightning:card>
</aura:component>

Controller

({
    initD3Charts : function(component, event, helper) {
        helper.renderGraph('#chart');
    }
})

Helper

({    
    renderGraph: function(selector) {
        // margin convention practice
        var margin = { top: 20, right: 20, bottom: 30, left: 50 };
        var width = 960 - margin.left - margin.right;
        var height = 400 - margin.top - margin.bottom;
        
        var num = 100;
        var yMax = 1000;
        
        var xScale = d3.scaleTime()
            .range([0, width])
            .domain([0, num-1]);
        
        var yScale = d3.scaleLinear()
            .range([height, 0])
            .domain([0, yMax]);
        
        // line generator
        var valueLine = d3.line()
            .x(function(d, i) { return xScale(i); })
            .y(function(d) { return yScale(d.value); });
        
        // create dataset
        var dataset = d3.range(num).map(function(d) { return {'value': d3.randomUniform(yMax)()}; });
        
        // add svg tag
        var svg = d3.select(selector).append('svg')
            .attr('width', width + margin.left + margin.right)
            .attr('height', height + margin.top + margin.bottom)
            .append('g')
            .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
        
        // X axis
        svg.append('g')
            .attr('transform', 'translate(0,' + height + ')')
            .call(d3.axisBottom(xScale));
        
        // Y axis
        svg.append('g')
            .call(d3.axisLeft(yScale));
        
        svg.append('path')
            .datum(dataset)
            .attr('class', 'line')
            .attr('d', valueLine);
    }
})