The canvas element is part of HTML5. It allows for dynamic, scriptable rendering of 2D shapes. It allows a developer to draw just as an artist would on their canvas; albeit, without the same creative flare an artist may have. As I’m a developer I couldn’t resist having an attempt. They first step was to come up with a project to do. Not being that creative I decided to draw a speedometer – similar to the ones we see in most cars. Initially it sounded quite simple, although, I did find parts quite tricky. This was due to my less than impressive maths skills and inexperience with the Canvas implementation. I’ll start with the end result and then explain how the parts of the speedometer were rendered. With any luck some skilled mathematician will be able to explain the maths I’ve used because I have managed to get it working without fully understanding the mathematical theory :-).
The End Result
- the metallic outer arc;
- the background semi-circle;
- the coloured speed arc;
- the speed tick marks and labels;
- and, finally the needle and its base.
The combination of drawing each of these components results in the complete speedometer.
The HTML Source
The following code is stripped to the minimum in order to draw the speedometer above.
<html lang="en"> <head> <meta charset="utf-8" /> <title>Speedometer HTML5 Canvas</title> <script src="speedometer.js"></script> </head> <body onload='draw(0);'> <canvas id="tutorial" width="440" height="220">Canvas not available.</canvas> <div> <form id="drawTemp"> <input type="text" id="txtSpeed" name="txtSpeed" value="20" maxlength="2"/> <input type="button" value="Draw" onclick="drawWithInputValue();"> </form> </div> </body> </html>
The HTML is fairly straight forward. The items of interest are the canvas, the ‘onload’ event for the body and the script tag. For those who are not familiar with HTML, let me explain how the canvas turns into the speedometer. When any HTML page loads the browser will run the JavaScript code attached to the onload event of the body tag e.g.
<body onload='draw(0);'>
In this example the JavaScript function called ‘draw’ will be called. The next logical question is what and where is this function? In this case the draw function is defined in the script included in the header:
<script type="text/javascript" src="speedometer.js"></script>
The browser will load any JavaScript code included in a script tag prior to displaying the page to the user. Therefore, the content of my script “speedometer.js” will be loaded and thus the function called ‘draw’ will be available. If you were to look inside the aforementioned script you will be able to see the code e.g.
function draw(iSpeed) { /* Main entry point for drawing the speedometer * If canvas is not support alert the user. */ var canvas = document.getElementById('tutorial'); // Canvas good? if (canvas != null && canvas.getContext) { var options = buildOptionsAsJSON(canvas, iSpeed); // Clear canvas clearCanvas(options); // Draw the metallic styled edge drawMetallicArc(options); // Draw thw background drawBackground(options); // Draw tick marks drawTicks(options); // Draw labels on markers drawTextMarkers(options); // Draw speeometer colour arc drawSpeedometerColourArc(options); // Draw the needle and base drawNeedle(options); } else { alert("Canvas not supported by your browser!"); } }
The content of the function is quite readable and can be matched to the sections I mentioned above. The first of these is drawing the metallic edge. Of course, the code for this is defined in the aptly named JavaScript function ‘drawMetallicArc’:
function drawMetallicArc(options) { /* Draw the metallic border of the speedometer * by drawing two semi-circles, one over lapping * the other with a bit of alpha transparency */ drawOuterMetallicArc(options); drawInnerMetallicArc(options); }
The content of the function reveals the metallic edge of the speedometer is drawn by overlapping an outer semi-circle with a smaller inner one. Let’s look at the content:
function drawOuterMetallicArc(options) { /* Draw the metallic border of the speedometer * Outer grey area */ options.ctx.beginPath(); // Nice shade of grey options.ctx.fillStyle = "rgb(127,127,127)"; // Draw the outer circle options.ctx.arc(options.center.X, options.center.Y, options.radius, 0, Math.PI, true); // Fill the last object options.ctx.fill(); } function drawInnerMetallicArc(options) { /* Draw the metallic border of the speedometer * Inner white area */ options.ctx.beginPath(); // White options.ctx.fillStyle = "rgb(255,255,255)"; // Outer circle (subtle edge in white->grey) options.ctx.arc(options.center.X, options.center.Y, (options.radius / 100) * 90, 0, Math.PI, true); options.ctx.fill(); }
function drawBackground(options) { /* Black background with alphs transparency to * blend the edges of the metallic edge and * black background */ options.ctx.globalAlpha = 0.2; options.ctx.fillStyle = "rgb(0,0,0)"; // Draw semi-transparent circles for (var i = 170; i < 180 ; i++) { options.ctx.beginPath(); options.ctx.arc(options.center.X, options.center.Y, 1 * i, 0, Math.PI, true); options.ctx.fill(); } }
function drawTicks(options) { /* Two tick in the coloured arc! * Small ticks every 5 * Large ticks every 10 */ drawSmallTickMarks(options); drawLargeTickMarks(options); }
function drawSmallTickMarks(options) { /* The small tick marks against the coloured * arc drawn every 5 mph from 10 degrees to * 170 degrees. */ var tickvalue = options.levelRadius - 8; var iTick = 0; var gaugeOptions = options.gaugeOptions; var iTickRad = 0; applyDefaultContextSettings(options); // Tick every 20 degrees (small ticks) for (iTick = 10; iTick < 180; iTick += 20) { iTickRad = degToRad(iTick); /* Calculate the X and Y of both ends of the * line I need to draw at angle represented at Tick. * The aim is to draw the a line starting on the * coloured arc and continueing towards the outer edge * in the direction from the center of the gauge. */ var onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue); var onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue); var innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius); var innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius); var fromX = (options.center.X - gaugeOptions.radius) + onArchX; var fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY; var toX = (options.center.X - gaugeOptions.radius) + innerTickX; var toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY; // Create a line expressed in JSON var line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6); // Draw the line drawLine(options, line); } } function drawLargeTickMarks(options) { /* The large tick marks against the coloured * arc drawn every 10 mph from 10 degrees to * 170 degrees. */ var tickvalue = options.levelRadius - 8; var iTick = 0; var gaugeOptions = options.gaugeOptions; var iTickRad = 0; var innerTickY; var innerTickX; var onArchX; var onArchY; var fromX; var fromY; var toX; var toY; var line; applyDefaultContextSettings(options); tickvalue = options.levelRadius - 2; // 10 units (major ticks) for (iTick = 20; iTick < 180; iTick += 20) { iTickRad = degToRad(iTick); /* Calculate the X and Y of both ends of the * line I need to draw at angle represented at Tick. * The aim is to draw the a line starting on the * coloured arc and continueing towards the outer edge * in the direction from the center of the gauge. */ onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue); onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue); innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius); innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius); fromX = (options.center.X - gaugeOptions.radius) + onArchX; fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY; toX = (options.center.X - gaugeOptions.radius) + innerTickX; toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY; // Create a line expressed in JSON line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6); // Draw the line drawLine(options, line); } }
function drawTextMarkers(options) { /* The text labels marks above the coloured * arc drawn every 10 mph from 10 degrees to * 170 degrees. */ var innerTickX = 0; var innerTickY = 0; var iTick = 0; var gaugeOptions = options.gaugeOptions; var iTickToPrint = 0; applyDefaultContextSettings(options); // Font styling options.ctx.font = 'italic 10px sans-serif'; options.ctx.textBaseline = 'top'; options.ctx.beginPath(); // Tick every 20 (small ticks) for (iTick = 10; iTick < 180; iTick += 20) { innerTickX = gaugeOptions.radius - (Math.cos(degToRad(iTick)) * gaugeOptions.radius); innerTickY = gaugeOptions.radius - (Math.sin(degToRad(iTick)) * gaugeOptions.radius); // Some cludging to center the values (TODO: Improve) if(iTick { options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX, (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5); } if(iTick < 50) { options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX - 5, (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5); } else if(iTick < 90) { options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX, (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY ); } else if(iTick == 90) { options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 4, (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY ); } else if(iTick < 145) { options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 10, (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY ); } else { options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 15, (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5); } // MPH increase by 10 every 20 degrees iTickToPrint += 10; } options.ctx.stroke(); }
function drawSpeedometerColourArc(options) { /* Draws the colour arc. Three different colours * used here; thus, same arc drawn 3 times with * different colours. * TODO: Gradient possible? */ var startOfGreen = 10; var endOfGreen = 200; var endOfOrange = 280; drawSpeedometerPart(options, 1.0, "rgb(82, 240, 55)", startOfGreen); drawSpeedometerPart(options, 0.9, "rgb(198, 111, 0)", endOfGreen); drawSpeedometerPart(options, 0.9, "rgb(255, 0, 0)", endOfOrange); }
The function ‘drawSpeedometerColourArc’ simply calls a helper function three times. The helper function draws separate parts of the the arc in different colours:
function drawNeedleDial(options, alphaValue, strokeStyle, fillStyle) { /* Draws the metallic dial that covers the base of the * needle. */ options.ctx.globalAlpha = alphaValue options.ctx.lineWidth = 3; options.ctx.strokeStyle = strokeStyle; options.ctx.fillStyle = fillStyle; // Draw several transparent circles with alpha for (var i = 0;i < 30; i++) { options.ctx.beginPath(); options.ctx.arc(options.center.X, options.center.Y, 1*i, 0, Math.PI, true); options.ctx.fill(); options.ctx.stroke(); } }
function drawNeedle(options) { /* Draw the needle in a nice read colour at the * angle that represents the options.speed value. */ var iSpeedAsAngle = convertSpeedToAngle(options); var iSpeedAsAngleRad = degToRad(iSpeedAsAngle); var gaugeOptions = options.gaugeOptions; var innerTickX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * 20); var innerTickY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * 20); var fromX = (options.center.X - gaugeOptions.radius) + innerTickX; var fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY; var endNeedleX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * gaugeOptions.radius); var endNeedleY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * gaugeOptions.radius); var toX = (options.center.X - gaugeOptions.radius) + endNeedleX; var toY = (gaugeOptions.center.Y - gaugeOptions.radius) + endNeedleY; var line = createLine(fromX, fromY, toX, toY, "rgb(255,0,0)", 5, 0.6); drawLine(options, line); // Two circle to draw the dial at the base (give its a nice effect?) drawNeedleDial(options, 0.6, "rgb(127, 127, 127)", "rgb(255,255,255)"); drawNeedleDial(options, 0.2, "rgb(127, 127, 127)", "rgb(127,127,127)"); }
Hi Ray. I love this article of yours. I’ve been working with HTML5 as well, though haven’t worked on canvas yet. I wish to reblog this article, may i?
Thanks for the feedback. I would really appreciate the reblog, thanks!
can we write the code for bike speedometer, can we install in digitalmeter
Reblogged this on teknonics and commented:
A great article on HTML5’s Canvas element by Ray Hammond. The HTML5 element is used to draw graphics, on the fly, via javascript.
Hi,
Thank you for your detailed explanation on how to draw this speed dial. Where can I find the reference to the function drawSpeedometerPart ? Thanks.
Kumudini
I found the source code. Thanks.
Glad you found it. I hope you find it useful.
Ray, I Need to place two dials on a single canvas. How can I use the javacript in such a case?
thanks
Hi Jcole, The draw function obtains a handle to the canvas object and then uses this canvas to draw the speedometer. To have two speedometers on the same screen you could simply have two canvas elements with difference ids. Then if you modify the draw function to take the id of the canvas object it will then draw a speedometer on each.
Is there any way to manage the speed of the needle? It is too fast. I am wishing for more dynamic effect like it slowly reaches to the value. (Pardon me for my ignorance, I am new to HTML).
Thanks
It should be simple to add the feature you require. I would simply add a timer that adjusts the current angle in small intervals until the needle reaches the desired location, at which point the timer should stop.
Chandar, I’ve updated the source code to show you want I mean.
Thanks a ton! š Really Really appreciate it..
hi ray..
nice work..
I want to caliberate the meter between values 10 to 40.
and colors as: 10 to 18: red, 18 to 25 green, 25 to 30: yellow, and red again above 30
please help to caliberate it…
Hi KP, the calibration is simply a case of converting your values to the corresponding values along the semi-circle. For example the semi-circle cover 0-180 degrees and your range covers 0-30 (adjusted by 10 for the screen display). This, the 50% mark on your range would be 15 which is equivalent to the 90 degrees mark on the 180 degree arc – simple mathematical conversion.
The colours are also easily altered, look at the 3 variable in the function drawSpeedometerColourArc.
great work..very useful..
Thanks Ram
Is it possible to dynamically change the needle’s position ?
Yes, the needle can be changed dynamically. For example, you could connect to a server using an AJAX long wait, or, Web Socket – when the server has a new speed this can be passed from server to the client. Within the client you can simply called the function ‘draw(iSpeed)’.
‘
Thanks š
Hi, it’s a great article. Now, I’m making some alterations with needles. I want to change the length of needle – is there easy way to do that?
Thanks for the feedback. The needle is drawn within the function drawNeedle(). This function references the variable gaugeOptions.radius. Adjusting the value of this will affect the length.
Hey there. That article is really great, but i got a little problem. Always when i want to start it, i get the message “buildOptionsAsJSON is not defined”. What i have to do here to make it go away?
The ‘buildOptionsAsJSON’ is defined within the included JS file which can be found at my Github account https://github.com/rheh/HTML5-canvas-projects/tree/master/thermometer
It would be wise to pull the full source code from there.
Excellent blog you have here but I was wondering if you knew of
any community forums that cover the same topics talked about
in this article? I’d really like to be a part of community where I can get suggestions from other experienced individuals that share the same interest. If you have any suggestions, please let me know. Many thanks!
Thanks for the feedback. There are a few online communities you can look at. There is a HTML5 group on Facebook with has a wide audience.https://www.facebook.com/groups/html5devs/
I also recommend reddit groups for HTML5 and web development.
hai Rey…execellent artical i have ever seen in html5
Thanks, appreciate the feedback
Hi Ray, very informative article, thanks for sharing. I’ve managed to make the needle’s position change dynamically, but I’m having trouble recalibrating it to mange a higher range of speeds – say 10x what it is currently. Do you have any suggestions? The only real problem I seem to be having is with the math in the “convertSpeedToAngle” function, but I may be missing something somewhere else…. Anyway, great blog, thanks again!
I figured it out
Excellent – thanks for the feedback.
Hi! I could have sworn I’ve visited this web site before but after browsing through a few of the articles I realized it’s new to me.
Anyhow, I’m definitely happy I stumbled upon it and I’ll
be bookmarking it and checking back regularly!
Regarding the positioning of the numbers… this can be done much easier.
I set textBaseline to ‘middle’ and textAlign to ‘center’.
Wow, sounds interesting. I would like to see that. Can you push to my git repo.
How to increase the max speed from 80 to something else?
To modify the range and thus the maximum value is simply a case of converting your values to the corresponding values along the semi-circle. For example the semi-circle cover 0-180 degrees and any new range covers 0-X (adjusted by 10 for the screen display). Thus, the 50% mark on your range would be x/2 which is equivalent to the 90 degrees mark on the 180 degree arc ā simple mathematical conversion.
thnx for reply. so if I need to make 80 to 2000, what values in the .js file I have to change?
hello plz help
Simply modify the function drawTextMarkers to:
function drawTextMarkers(options) {
/* The text labels marks above the coloured
* arc drawn every 10 mph from 10 degrees to
* 170 degrees.
*/
var innerTickX = 0,
innerTickY = 0,
iTick = 0,
gaugeOptions = options.gaugeOptions,
iTickToPrint = 80;
applyDefaultContextSettings(options);
// Font styling
options.ctx.font = ‘italic 10px sans-serif’;
options.ctx.textBaseline = ‘top’;
options.ctx.beginPath();
// Tick every 20 (small ticks)
for (iTick = 10; iTick < 180; iTick += 20) {
innerTickX = gaugeOptions.radius – (Math.cos(degToRad(iTick)) * gaugeOptions.radius);
innerTickY = gaugeOptions.radius – (Math.sin(degToRad(iTick)) * gaugeOptions.radius);
// Some cludging to center the values (TODO: Improve)
if (iTick <= 10) {
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY + 5);
} else if (iTick < 50) {
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX – 5,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY + 5);
} else if (iTick < 90) {
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY);
} else if (iTick === 90) {
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX + 4,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY);
} else if (iTick < 145) {
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX + 10,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY);
} else {
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX + 15,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY + 5);
}
// MPH increase by 10 every 20 degrees
iTickToPrint += Math.round(2160 / 9);
}
options.ctx.stroke();
}
It is not working for me. What i might be missing here. I simply pasted the above code thats all. All i’m getting is an html form with default value 20 in it. Love your explanation btw.
Thanks for the feedback. Rather than copy and pasting the code it would be better to download the code from my github repository. If you look at the last paragraph of the Blog you see the links to the source code and a working example. Hope that helps!
Is it possible to dynamically change the needleās position ?
I donwload https://github.com/rheh/HTML5-canvas-projects/tree/master/speedometer
the funcion draw is: (It don’t have arguments)
function draw() {
It’s the drawNeedle function that you should be looking at. That accepts a parameter which holds the angle.
Hey Ray thanx for the tutorial its a great and helped a lot to understand the canvas deeply but would like to know if there is a way to fit the arcs according to the reduction of the size.
ie if the screen size is small the speedometer tends to fit itself to the screen.
Thanx
The example is pretty rigid as doesn’t scale well. The area you should be looking at is the radius and outerradius values,
very well written and really informative..
good job!!
Thank you! I did a screen with 10 gauges, each one with different value source (ajax) and it works quickly, also the memory use is minimal.
Thank you again and keep going.
Excellent! Thanks for the feedback.
Hello,
I need to covert this 180 degree semicircle to 270 degree circle , i tried doing the same via 1.5*math.pi in draw outer metallic and inner circle but it didnot work
plz guide !!!!!!!
got the answer thanks
Excellent!
Hi, I am sorry but I tried the codings but nothing comes out of my web page. So can I check with you if the tag are all in the script?
A working version can be found on my GitHub account https://github.com/rheh/HTML5-canvas-projects/tree/master/speedometer
for the Modified speedometer.js so the needle moves frame by frame between values…, do I just have to copy the all the codings into my document? But I dont understand the ‘+’ and ‘-‘ sign at the page as well as the different color. Please advise.
Thanks.. =D
Direct links to the HTML page a JS file needed are https://raw.github.com/rheh/HTML5-canvas-projects/master/speedometer/speedometer.js and https://raw.github.com/rheh/HTML5-canvas-projects/master/speedometer/canvas.html
how to increase the size of needle and speedo meter
The size is programmatically controlled. If you look at the main variables the width and height can be changed. But, I’ve not tested it to determine what side effects this will have!
how do I change the color of the text markers from white to any other color?
how do I change the color of the text markers from white to any other color?
Also I am trying to make 4 speedometers. I changed the element id in both the html and Javascript page but it displays only the last speedometer. the other canvas remains blank.
Check to ensure the Ids are unique and match. I sounds like your doing the right thing in creating 4 canvas and changing the Ids accordingly.
The function drawTextMarkers draws the text. You should add a line in this function to change the colour, I think ‘options.ctx.fillStyle = ‘blue’;’ should do it.
how to fix tickMarks and maximum range up to 100
I am not able to find this function buildOptionsAsJSON anywhere in the code or in the gitgub you mentioned. Can you help me out please
Line 425: here https://github.com/rheh/HTML5-canvas-projects/blob/master/speedometer/speedometer.js
Hope it helps.
I would like to change the text markers, so I modified:
function drawTextMarkers(options)
{
var innerTickX = 0;
var innerTickY = 0;
var iTick = 0.0;
var gaugeOptions = options.gaugeOptions;
var iTickToPrint = 0.0;
applyDefaultContextSettings(options);
// Font styling
options.ctx.font = ‘italic 10px sans-serif’;
options.ctx.textBaseline = ‘top’;
options.ctx.beginPath();
// Tick every 20 (small ticks)
for (iTick = 18; iTick < 90; iTick += 18)
{
innerTickX = gaugeOptions.radius – (Math.cos(degToRad(iTick)) * gaugeOptions.radius);
innerTickY = gaugeOptions.radius – (Math.sin(degToRad(iTick)) * gaugeOptions.radius);
options.ctx.fillText(iTickToPrint, (options.center.X – gaugeOptions.radius – 12) + innerTickX,
(gaugeOptions.center.Y – gaugeOptions.radius – 12) + innerTickY + 5);
// MPH increase by 10 every 20 degrees
iTickToPrint += 18;
}
options.ctx.stroke();
}
But, it only draw the text markers until 54, instead of 90, why? how can I resolve it? thans
I know, by incremeting the iTick.
I would like to change the position of the needle to a fixed position, is that possible?
Hard to understand what you are trying to achieve; but, in theory anything is possible.
I just started some web-development and needed a speedometer. I forked your git-hub project and modified your speedometer.js to support some of my needs (different sizes, more than one on the page, different numerical ranges (I’m using it as a percent visualizer so needed it to go from 0-100), I also wanted a larger color arc as I’m more interested in showing the needle is within a range than an actual value.) My modifications make it easier to customize (without changing the speedometer.js file so you can have different speedometers with different numerical ranges and only one copy of speedometer.js), scales to fit the canvas it is drawn in, centers itself within the canvas, and allows more than one speedometer on a page. My updated code is here:
https://github.com/siannce/HTML5-canvas-projects/blob/master/speedometer/speedometer.js
Thanks for the original!
Awesome work , it is helpful for me. thank you.
This very good article. I have some mathematics doubts. To calcule x and y i use the lines above. Why i need subtract in case of Y coordinate?
Obs: I modify the code to try understand more.
var x = options.center.X + Math.cos(iTickRad) * gaugeOptions.radius;
var y = options.center.Y – Math.sin(iTickRad) * gaugeOptions.radius;
var tox = options.center.X + Math.cos(iTickRad) * (gaugeOptions.radius – 18);
var toy = options.center.Y – Math.sin(iTickRad) * (gaugeOptions.radius – 18);
Thanks.
what can be done to display the textmarkers inside instead of displaying above the ticks…
Modifying the radius applied when drawing the textmarkers will do the trick
Hey Ray, this is awesome! It’s exactly what I’ve been looking for. I have used your code to create an Angular JS directive for the speedometer. I tried to make as much of it customizable as possible. https://github.com/ridgeboy40/speedometer
Looks really good!
Thank you very much .. This is really amazing š .. But how can I change the position and size of the canvas ?
Thanks for this post! This is awesome! You said that the code above could be used freely; would there be a note to the same effect somewhere for the code in the Git repository?
Yeah, use freely as you wish. Best of luck.
Hi,
I need help.
I changed buildOptionsAsJSON
function buildOptionsAsJSON(canvas,iSpeed,t) {
/* Setting for the speedometer
* Alter these to modify its look and feel
*/
//var centerX = 100,
alert(“in build”);
var centerX = 0,
centerY = 100,
//radius = 140,
radius = 70,
//outerRadius = 200;
outerRadius = 100;
// Create a speedometer object using Javascript object notation
return {
ctx: canvas.getContext(‘2d’),
speed: iSpeed,
center: {
X: outerRadius*t + 150,
Y: centerY
},
levelRadius: radius – 10,
gaugeOptions: {
center: {
X: outerRadius*t + 150,
Y: centerY
},
radius: radius
},
radius: outerRadius
};
}
but it not working.
Please suggest.
What are you trying to make it do?
This is awesome. How can we make it where the speedometer isn’t adjusted 10 deg? I don’t get the point for that.
To be honest I’m not sure what the point is either :-). I must have been feeling artistic the day I wrote the blog. The adjustment is present in the initialising loop variable. For example the function drawSmallTickMarks starts its loop at 10 degrees. Adjusting these will control were the arc starts
Hi Ray,
I need to make a speedometer which shows minutes from 0 to 5 and needle moves seconds by second.When I am putting my minutes variable in speedometer xval it is going directly from 0 to 1 to 2 and 3 and so on instead of going one by one from 1 to 2 i.e it is not moving in between
It sounds like you need to wait for each transition to finish before starting the next
Hey thanks for sharing it !
Can we display to needles (with different colors, representing different data) on the same speedometer, at the same time ?
Hi ! Thanks for sharing it š
Is it possible to display two needles at te same time on the same speedometer (with different colors and data) ?
Yes it sure is. You would have to have two needle gauge values and call the draw function for the needle twice with the different values
Hi thanks for this amazing speedometer !
Is there a way to rotate text markers ?
I believe there is. Talk a look at my code for drawing a dartboard here https://github.com/rheh/HTML5-canvas-projects/blob/master/dartboard/dartboard.js specifically, the drawLabel function.
Hello Sir,
This thing already i implemented in android,but i wants to start the scale from 95 to 120.can you help..plz sir..
It more of a presentation issue. The basic maths is the same, you will just need to add an offset they printing the text to the canvas
Thanks a lot it was really helpful. The code worked without a bug