Interactive Line Chart

A Line Chart report is used to show one value compared to another, usually when the x-axis is time.

In most cases, bar charts are the preferred option if your x axis is something other than time.

An example can be found in the Wind Farm Wind Speed Display.

This is a more complex version of the Simple Line Chart, which does not have interactivity.

This overrides the updateTooltip function and calls tip on the interactive elements so that they will create tooltips when the mouse hovers over them.

It uses the getMouseAxisPos function (which is specific to SVG reports) to convert the mouse position into both the X and Y values of the chart that the mouse is hovering over.

Example

Description

You should replace the following…

ElementReplace With
[ASSET]The name of the asset to display
[PROPERTY]The name of the property you want to report on
[PLACES]The maximum decimal places to show
[UNITS]The measurement units
class ActiveReport extends SVGReport {
	initialise() {
		super.initialise();
		this.property = '[PROPERTY]';
	};
 
	create() {
		this.singleQueryReport("'[ASSET]' ASSET '" + this.property + "' PROPERTY VALUES {\"grain\": -2000,%%} GETHISTORY");		
	}
 
	updateTooltip(ev) {
		var pos = this.getMouseAxisPos(this.x,this.y,ev.clientX,ev.clientY);
 
		var bi = d3.bisector(d => d[0]);
		var indx = bi.right(this.data,pos[0], 1);
 
		this.svgbase.select('.axismarker')
				.attr("x1",this.x(pos[0]))
				.attr("x2",this.x(pos[0]))
				.style("display","");
 
                if (indx >= this.data.length)
                         indx = this.data.length-1;
 
		var tt = "<table style=\"font-size: small;\"><tr><td colspan=\"2\" style=\"color: black;\">" + this.data[indx][0] + "<br/><br/></td></tr>";
		for(var q=0;q<this.columns.length;q++)
		{
			tt += "<tr><td><div style=\"background-color: " + this.getSequenceColour(q) + "; border: 1px solid black; width: 20px; height: 20px;\"></div></td><td><label style=\"color: black;\">" + this.columns[q].name.replace(" " + this.property,"") + ": " + this.data[indx][q+1].toFixed([PLACES]) + " [UNITS]";
		}
		tt += "</table>";
 
		return tt;
	}
 
	draw(data) {
		//Get the SVG and sizing
		$('svg').html("");
 
		var height = this.sizing[1];
		var width = this.sizing[0];
 
		//Calculate the min and max across all channels
		var xextent = d3.extent(data,d => d[0]);
		var yextent = d3.extent(data,d => d[1]);
		for(var q=0;q<this.columns.length;q++)
		{
			var ex = d3.extent(data,d => d[q+1]);
			if (ex[0] < yextent[0])
				yextent[0] = ex[0];
			if (ex[1] > yextent[1])
				yextent[1] = ex[1];
		}
 
		//Add a small buffer to the Y axis to add some padding
		var yspan = (yextent[1] - yextent[0]) * 0.08;
		if (yextent[0] != 0)
		{
			yextent[0] -= yspan;
		}
		if (yextent[1] != 0)
		{
			yextent[1] += yspan;
		}
 
		//Calculate the margin for the report
		var margin = {top: this.margin.top, left: 40,right: 20,bottom: 50};
		var svgbase = this.svgbase;
		var svg = svgbase;		
 
		//Create the X and Y axes
		var x = d3.scaleTime().domain(xextent).rangeRound([margin.left, width - margin.right]);
		var y = d3.scaleLinear().domain(yextent).rangeRound([height - margin.bottom,margin.top]);
 
		//Create an appropriate tick format
		var xTickFormat = x.tickFormat(null, "%H:%M, %-d %b %Y");
		var yTickFormat = y.tickFormat(100,null);
 
		//Save the axes so the tooltip can access them
		this.x = x;
		this.y = y;		
 
		//Draw a set of axes
		this.drawAxisSet(x,y,"Time","[PROPERTY] ([UNITS])",margin.left,margin.right,width,height,"main");		
 
		//Draw each of the lines
		for(var vx=1;vx<data[0].length;vx++)
		{
			svg.append("path")
			  .datum(data)
			  .attr("fill", "none")
			  .attr("stroke", this.getSequenceColour(vx-1))
			  .attr("stroke-width", 2)
			  .attr("stroke-linejoin", "round")
			  .attr("stroke-linecap", "round")
			  .attr("d", d3.line()
			.curve(d3.curveStep)
			.x(d => x(d[0]))
			.y(d => y(d[vx]))
			.defined(d => { if (isNaN(d[1])) return false; return true; } ))
			  .style("pointer-events","none")
			  .call(this.tip);
		}
 
		svg.select('#main')
			.call(this.tip);		
	}	
}