Marek J
Marek J

Reputation: 75

Plot a line using d3.js library in Power BI custom visual

I'm struggling with plotting a sigle line in Power BI custom visual. Reports in Power BI are written using TypeScript and d3.js v.3.0. I'm able to plot chart with axes, but the line doesn't appear. Using pure d3.js in HTML file is really easy, but it is hard to integrate it with TypeScript due to typings preservation.

While developing this code I have had several problems with typings. Code below almost works. Take a look at this snippet. Issue with typings arises, when at the bottom I delete 'any'.

Here is link to sandbox at CodePen: https://codepen.io/SuszonyDzik/pen/aBaJJQ

module powerbi.extensibility.visual {
    export class Visual implements IVisual {
        private target: HTMLElement;
        private updateCount: number;

        private svg: d3.Selection<SVGAElement>;
        private host: IVisualHost;
        private selectionManager: ISelectionManager;

        //private xAxis: d3.Selection<SVGAElement>;
        //private yAxis: d3.Selection<SVGAElement>;


        private data = [
            {date: "2011-10-01",    close: 582.13},
            {date: "2011-10-10",    close: 303.00},
            {date: "2011-10-20",    close: 103.00},
            {date: "2011-10-25",    close: 143.00},
        ]

        static Config = {
            xScalePadding: 0.1,
            solidOpacity: 1,
            transparentOpacity: 0.5,
            xAxisFontMultiplier: 0.04,
        };

        private margin = {top: 20, right: 30, bottom: 30, left: 80};



        constructor(options: VisualConstructorOptions) {
            this.host = options.host;

            let svg = this.svg = d3.select(options.element)
                .append('svg')
                .classed('worksheet', true);
        }

        public update(options: VisualUpdateOptions) {
            let width = options.viewport.width - this.margin.left - this.margin.right;
            let height = options.viewport.height - this.margin.top - this.margin.bottom;

            this.svg.attr({
                width: width + this.margin.left + this.margin.right,
                height: height + this.margin.top + this.margin.bottom
            });



            let parseDate = d3.time.format("%Y-%m-%d").parse;                       

            let xScale = d3.time.scale()
                .domain(this.data.map(function(d) { return parseDate(d.date); }))
                .range([0, width])

            let yScale = d3.scale.linear()
                .domain([0, d3.max(this.data, function(d) { return d.close; })])
                .range([height, 0]);        

            let xAxis = d3.svg.axis()
                .scale(xScale)
                .orient("bottom")
                .ticks(10)

            let yAxis = d3.svg.axis()
                .scale(yScale)
                .orient("left")
                .ticks(10)
                .innerTickSize(-width)
                .outerTickSize(10)
                .tickPadding(10)



            let worksheet = d3.select(".worksheet")
                .attr("width", width + this.margin.left + this.margin.right)
                .attr("height", height + this.margin.top + this.margin.bottom);


            // remove exsisting axis and bar
            this.svg.selectAll('.axis').remove();
            this.svg.selectAll('.bar').remove();
            this.svg.selectAll('.chart').remove();


            let chart  = d3.select(".worksheet")
              .append("g")
                .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")")
                .attr("class", "chart")

            chart.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);


            chart.append("g")
                .attr("class", "y axis")
                .call(yAxis)


            let line = d3.svg.line()
            .x(function(d) { console.log(parseDate(this.data.date)); return xScale(parseDate(this.data.date)); })
            .y(function(d) { return yScale(this.data.close); })
            .interpolate("linear")

            chart.append("path")
                .datum(this.data)
                .attr("class", "line")          
                .attr("d", <any> line)

        }

        public destroy(): void {
            //TODO: Perform any cleanup tasks here
        }
    }
}

Power BI chart with axes but without line

Upvotes: 3

Views: 1918

Answers (1)

Kasipathi Bendalam
Kasipathi Bendalam

Reputation: 46

Please change the code from

chart.append("path")
.datum(this.data)
.attr("class", "line")          
.attr("d", <any> line)

To

chart.append("path")
.datum(this.data)
.attr("class", "line") 
.attr("d", "M" + this.data.map((d)=> {
return xScale( parseDate(d.date)) + ',' + yScale(d.close);
}).join('L'))

And also from the below

let xScale = d3.time.scale()
.domain(this.data.map(function(d) { return parseDate(d.date); }))
.range([0, width])

to

let xScale = d3.time.scale() 
.domain(d3.extent(this.data,function(d) { return parseDate(d.date); }))
.range([0, width])

I have modified the code and worked. Please find the output. Output

Upvotes: 1

Related Questions