I'm struggling with plotting a single 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. The code below almost works. Take a look at this snippet. The issue with typings arises when at the bottom I delete 'any'.
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
}
}
}