Creating a Dynamic Line Chart in Canvas
Problem
You want to display a line chart in your web page, but the data changes over time, and you want to dynamically update it.
Solution
Use the canvas element and the path method to create the chart. When the data changes,
update the chart:
var array1 = [[100,100], [150, 50], [200,185], [250, 185], [300,250], [350,100], [400,250], [450, 100], [500,20], [550,80], [600, 120]]; var imgcanvas = document.getElementById("imgcanvas"); if (imgcanvas.getContext) { var ctx = imgcanvas.getContext('2d'); // rect one ctx.strokeRect(0,0,600,300); // line path ctx.beginPath(); ctx.moveTo(0,100); for (var i = 0; i < array1.length; i++) { ctx.lineTo(array1[i][0], array1[i][1]); } ctx.stroke(); }
EXPLAIN
Canvas paths are the way to create arbitrary shapes in Canvas. After getting the canvas
context, ctx, the path is begun with a call to ctx.beginPath(), which begins a new
Canvas path. The next line of code is ctx.moveTo, which moves the drawing “pen” to a
beginning location, but without drawing. From that point, several lineTo() calls are
made using an array of paired values representing the x,y location for each line endpoint.
After the path has been defined, it’s drawn. We’re not creating a closed path, so I’m not
using ctx.closePath(), which would draw all the defined lines and then attempt to
draw a line from the ending point to the beginning point. Instead, I’m drawing the line
given the points that have been defined, using ctx.stroke().
The appearance of the drawing is influenced by two Canvas settings: strokeStyle and
fillStyle. The strokeStyle setting sets the color for the outline of a drawing, while
the fillStyle does the same for the drawing filling:
ctx.strokeStyle="black"; ctx.fillStyle="#ff0000;
Any CSS setting will do, or you can use a CanvasGradient or CanvasPattern. You can use the rgba setting to add transparency:
ctx.fillStyle="rgba(255,0,0,0.5)";
You can also use the globalAlpha setting to set the transparency for any drawing that follows:
ctx.globalAlpha = 0.2;
You can further control the appearance of the drawing outline by changing the stroke’s line width:
ctx.line
To dynamically update the chart, you can incorporate timers, and either replace the path (by creating an entirely new context, which would erase the old), or add the new line chart to the same chart.
Shows a web page that creates the line in the solution and then creates two others, each drawn after a short period of time using timers. The colors for the stroke path are changed between lines.
Using timers to dynamically update a line chart
<!DOCTYPE html> <head> <title>Canvas Chart</title> <meta charset="utf-8" /> </head> <body> <canvas id="imgcanvas" width="650" height="350"> <p>Include an image that has a static representation of the chart</p> </canvas> <script> var points = [[[100,100], [150, 50], [200,185], [250, 185], [300,250], [350,100], [400,250], [450, 100], [500,20], [550,80], [600, 120]], [[100,100], [150, 150], [200,135], [250, 285], [300,150], [350,150], [400,280], [450, 100], [500,120], [550,80], [600, 190]], [[100,200], [150, 100], [200,35], [250, 185], [300,10], [350,15], [400,80], [450, 100], [500,120], [550,80], [600, 120]]]; var colors = ['black','red','green']; var imgcanvas = document.getElementById("imgcanvas"); if (imgcanvas.getContext) { var ctx = imgcanvas.getContext('2d'); // rectangle wrapping line chart ctx.strokeRect(0,0,600,300); points.forEach(function(element, indx, arry) { setTimeout(function() { // set up beginning ctx.beginPath(); ctx.moveTo(0,100); ctx.strokeStyle = colors[indx]; for (var i = 0; i < element.length; i++) { ctx.lineTo(element[i][0], element[i][1]); } ctx.stroke(); }, indx * 5000); }); } </script> </body>
Simplify Your Canvas Charts Using a Library
It doesn’t have to be difficult to create a chart using Canvas from scratch, but why walk
the steps taken by others? There are several excellent libraries that can simplify not only
chart making but other Canvas effects.
Over 50 libraries for chart making are listed in a TechSlides Page, including the in‐
creasingly popular D3, which I’ll cover in .
Most of the libraries are freely
available, though some do charge a fee for commercial use.
One of the libraries, Highcharts, even provides demonstrations that you can edit in
jsFiddle, making it easy to try out the library’s capability. It’s dependent on jQuery,
reducing the code to an absurdly simple level. As an example, one of the demonstrations
is for a very professional line chart, with plot lines and labels,
Yet the code to create this example is equivalent to that in the following code block,
which I modified to feature my own locations and temperature metric, which you can
try yourself at jsFiddle:
$(function () { $('#container').highcharts({ title: { text: 'Monthly Average Temperature', x: -20 //center }, subtitle: { text: 'Source: Weather.com', x: -20 }, xAxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] }, yAxis: { title: { text: 'Temperature (°F)' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { valueSuffix: '°F' }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0 }, series: [{ name: 'Seattle, WA', data: [47,51,55,59,65,70,75,75,70,60,52,47] }, { name: 'Grand Isle, VT', data: [27,31,40,54,67,76,81,79,71,57,45,33] }, { name: 'St. Louis, MO', data: [40,45,55,67,77,85,89,88,81,69,56,43] }] }); });
Not only is the plotted chart professional looking, it’s zoomable, which means you can move your mouse cursor over the chart to examine the plot points in detail. That level of interactivity isn’t necessarily trivial in Canvas, because one of the downsides to Canvas is the fact that you can’t attach event handlers to the individual elements of Canvas— only to the Canvas area itself.
Not being able to attach an event to individual elements means that you’ll have to keep track of where the mouse is, and what’s underneath it at any point in time.
Thankfully, you can attach event handlers to SVG elements, as demonstrated.
No comments:
Post a Comment