Reputation: 166
I am creating speedometer like semi circle and I have have been successful creating semicircle with all the colors. See the design below:
The problem I am facing is creating the triangle which will act as pointer. It will move around value from 300 to 850. What ever the value will get in this range it will point there.
<canvas id="myCanvas" height="350" width="666">
</canvas>
JS:
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.font = "14px Trebuchet MS";
context.fillStyle = "#aaaaaa";
context.fillText("300", 60, 218);
context.font = "14px Trebuchet MS";
context.fillStyle = "#aaaaaa";
context.fillText("850", 280, 218);
// drawArcShadow x y rad sAng eAng clockwise line fill
drawArcShadow(180, 200, 100, 0, 180, true, "#eeeeee","white");
function drawArcShadow(xPos, yPos, radius, startAngle, endAngle, clockwise, lineColor, fillColor) {
var startAngle = startAngle * (Math.PI/180);
var endAngle = endAngle * (Math.PI/180);
var radius = radius;
context.strokeStyle = lineColor;
context.fillStyle = fillColor;
context.lineWidth = 20;
context.beginPath();
context.arc(xPos, yPos, radius, startAngle, endAngle, clockwise);
context.fill();
context.stroke();
}
// drawArc x y rad sAng eAng clockwise line fill
drawArc(180, 200, 110, 0, 180, true, "#c1634a","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 263, true, "#ab5741","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 264, true, "#e59636","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 288, true, "#ce8631","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 289, true, "#e8d932","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 302, true, "#d0c52d","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 303, true, "#aecd9c","rgba(255, 255, 255, 0)");
drawArc(180, 200, 110, 0, 320, true, "#8db872","rgba(255, 255, 255, 0)");
function drawArc(xPos, yPos, radius, startAngle, endAngle, clockwise, lineColor, fillColor) {
var startAngle = startAngle * (Math.PI/180);
var endAngle = endAngle * (Math.PI/180);
var radius = radius;
context.strokeStyle = lineColor;
context.fillStyle = fillColor;
context.lineWidth = 20;
context.beginPath();
context.arc(xPos, yPos, radius, startAngle, endAngle, clockwise);
context.fill();
context.stroke();
}
};
Upvotes: 0
Views: 1908
Reputation: 136658
This question already has been answered many times, but I felt you need some more corrections in your code's logic.
To rotate a shape around a point in canvas, use translate(x,y)
and rotate(radian)
methods.
First you move your context to the rotation anchor point, then you rotate accordingly, and finally you translate again to give the desired offset.
Think of your context as a leaf of paper that you can move and rotate.
In your snippet, you had big antialiasing artifacts. This is because you made all your arcs start at angle 0. When drawing an arc, the browser will create semi-transparent pixels so the line looks smooth. But if you do draw multiple arcs at the same positions, these pixels are more and more opaque, leading to these visible artifacts.
Here is your code, a bit refactored :
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
function drawTriangle() {
var ratio = Math.PI / (slider.max - slider.min);
var angle = ((slider.value - slider.min) * ratio) + Math.PI;
var radius = 110;
// first move our cursor to the center of our arcs
context.translate(180, 200);
// then rotate the whole context
context.rotate(angle);
// move our cursor to our arc's radius
context.translate(radius, 0);
// draw the triangle
context.fillStyle = 'black';
context.beginPath();
// this draws the triangle around its center point
context.lineTo(10, -5);
context.lineTo(10, 5)
context.lineTo(-10, 0)
context.closePath();
context.fill();
// place back our context's transfrom to its default
context.setTransform(1, 0, 0, 1, 0, 0);
}
function drawArcShadow(xPos, yPos, radius, startAngle, endAngle, clockwise, lineColor, fillColor) {
var startAngle = startAngle * (Math.PI / 180);
var endAngle = endAngle * (Math.PI / 180);
var radius = radius;
context.strokeStyle = lineColor;
context.fillStyle = fillColor;
context.lineWidth = 20;
context.beginPath();
context.arc(xPos, yPos, radius, startAngle, endAngle, clockwise);
context.fill();
context.stroke();
}
function draw() {
// clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// text
context.font = "14px Trebuchet MS";
context.fillStyle = "#aaaaaa";
// since we don't change the properties, no need to tell the browser to do so
context.fillText("300", 60, 218);
context.fillText("850", 280, 218);
// drawArcShadow x y rad sAng eAng clockwise line fill
drawArcShadow(180, 200, 100, 0, 180, true, "#eeeeee", "white");
// drawArc x y rad sAng eAng ANTIclockwise line fill
// be careful, 6th argument of arc() is ANTI-clockwise boolean
// here I changed all start angle to avoid anti-aliasing artifacts + I removed the transparent fill parameter
drawArc(180, 200, 110, 263, 180, true, "#c1634a", null);
drawArc(180, 200, 110, 264, 263, true, "#ab5741", null);
drawArc(180, 200, 110, 288, 264, true, "#e59636", null);
drawArc(180, 200, 110, 289, 288, true, "#ce8631", null);
drawArc(180, 200, 110, 302, 289, true, "#e8d932", null);
drawArc(180, 200, 110, 303, 302, true, "#d0c52d", null);
drawArc(180, 200, 110, 320, 303, true, "#aecd9c", null);
drawArc(180, 200, 110, 0, 320, true, "#8db872", null);
drawTriangle();
}
function drawArc(xPos, yPos, radius, startAngle, endAngle, clockwise, lineColor, fillColor) {
var startAngle = startAngle * (Math.PI / 180);
var endAngle = endAngle * (Math.PI / 180);
context.strokeStyle = lineColor;
context.fillStyle = fillColor;
context.lineWidth = 20;
context.beginPath();
context.arc(xPos, yPos, radius, startAngle, endAngle, clockwise);
// instead of filling transparent, which produces nothing, just don't pass the fillColor parameter and don't call fill().
fillColor && context.fill();
context.stroke();
}
slider.oninput = draw;
draw();
<input type="range" id="slider" min="300" max="850">
<canvas id="myCanvas" height="350" width="666"></canvas>
Upvotes: 2