创建像Semi Circle这样的车速表

时间:2016-11-14 10:23:38

标签: html5 css3 canvas

我正在创建像半圆一样的速度计,我已经成功创造了所有颜色的半圆。请参阅以下设计:

我面临的问题是创建将充当指针的三角形。它会在300到850之间移动。在这个范围内,这个值将达到什么值。

JS Fiddle Link

enter image description here

<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();
}

};

1 个答案:

答案 0 :(得分:2)

这个问题已经多次得到解答,但我觉得你需要在你的代码逻辑中做一些更正。

要围绕画布中的某个点旋转形状,请使用translate(x,y)rotate(radian)方法。 首先,将上下文移动到旋转锚点,然后相应地旋转,最后再次平移以提供所需的偏移 将您的背景视为可以移动和旋转的纸张。

在你的代码片段中,你有很大的抗锯齿效果。这是因为您使所有弧从角度0开始。绘制弧时,浏览器将创建半透明像素,以使线条看起来平滑。但是如果你在相同的位置绘制多个弧,这些像素越来越不透明,导致这些可见的伪像。

这是你的代码,有点重构:

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>