RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 968028
Accepted
corocoto
corocoto
Asked:2020-04-11 00:19:18 +0000 UTC2020-04-11 00:19:18 +0000 UTC 2020-04-11 00:19:18 +0000 UTC

在画布上绘制速度计的箭头

  • 772

我想用画布制作速度计动画。但是我需要速度计指针是三角形的,当值改变时,它指向所需的值,但它的底部始终保持在中心。告诉我你需要申请什么公式或算法。代码如下所示。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
    const canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d"),

        // general settings
        middleX = canvas.width / 2,
        middleY = canvas.height / 2,
        radius = 240,

        counterClockwise = false,

        // ticks settings
        tickWidth = canvas.width / 100,
        // tickColor = "#746845";
        tickOffsetFromArc = canvas.width / 40,

        // Center circle settings
        centerCircleRadius = canvas.width / 20,
        centerCircleColor = "#ccc",
        centerCircleBorderWidth = canvas.width / 100,

        // Arrow settings
        arrowValueIndex = .73,
        arrowColor = "#464646",
        arrowWidth = canvas.width / 50,

        // numbers
        digits = [0, 20, 40, 50, 60, 70, 80, 90, 100],
        digitsColor = "#0a0a0a",
        digitsFont = "bold 20px Tahoma",
        digitsOffsetFromArc = canvas.width / 15,

        //zones
        zonesCount = digits.length - 1;
    // beginning and ending of our arc. Sets by radius*pi
    let startAngleIndex = .75,
        endAngleIndex = 2.25,
        step = (endAngleIndex - startAngleIndex) / zonesCount;

    /*draw zones*/
    let DrawZones = function () {
        const greyZonesCount = zonesCount / 1.6;
              greenZonesCount = zonesCount - greyZonesCount,
              startAngle = (startAngleIndex - 0.02) * Math.PI,
              endGreyAngle = (startAngleIndex + greyZonesCount * step) * Math.PI,
              endGreenAngle = (endAngleIndex + 0.02) * Math.PI,

              //zones' options
              sectionOptions = [
                  {
                      startAngle: startAngle,
                      endAngle: endGreyAngle,
                      color: "#e7e7e7",
                      zoneLineWidth: 2
                  },
                  {
                      startAngle: endGreyAngle,
                      endAngle: endGreenAngle,
                      color: "#13b74b",
                      zoneLineWidth: 5
                  },
              ];

        this.DrawZone = function (options) {
            ctx.beginPath();
            ctx.arc(middleX, middleY, radius, options.startAngle, options.endAngle, counterClockwise);
            ctx.lineWidth = options.zoneLineWidth;
            ctx.strokeStyle = options.color;
            ctx.lineCap = "round";
            ctx.stroke();
        };

        sectionOptions.forEach(options => this.DrawZone(options));
    };

    /*draw dots*/
    let DrawTicks = function () {
        startAngleIndex = .73,
        endAngleIndex = 2.27,
        step = (endAngleIndex - startAngleIndex) / zonesCount;
        this.DrawTick = function (angle,count) {

            let fromX = middleX + (radius - tickOffsetFromArc) * Math.cos(angle),
                fromY = middleY + (radius - tickOffsetFromArc) * Math.sin(angle),
                toX = middleX + (radius + tickOffsetFromArc) * Math.cos(angle),
                toY = middleY + (radius + tickOffsetFromArc) * Math.sin(angle),

                centerOfDotX=(fromX+toX)/2,
                centerOfDotY=(fromY+toY)/2;
            ctx.beginPath();
            ctx.arc(centerOfDotX,centerOfDotY,6,0,Math.PI*2,true);
            if (count<6){
                switch (count) {
                    case 1:
                    case 2:
                    case 3:
                        ctx.fillStyle="#FF0000";
                        break;
                    default:
                        ctx.fillStyle="#F9AF00";
                        break;
                }
            }else{
                ctx.fillStyle="#FFF";
                ctx.strokeStyle="#13B74B";
                ctx.shadowColor = "#a8bbaa";
                ctx.shadowBlur = 15;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 0;
                ctx.stroke();
            }
            ctx.fill();
            ctx.closePath();
            ctx.shadowBlur =0;
        };
        let count=0;
        for (let i = startAngleIndex; i <= endAngleIndex; i += step) {
            let angle = i * Math.PI;
            count++;
            this.DrawTick(angle,count);
        }
    };

    //draw numbers
    let DrawDigits = function () {
        let angleIndex = startAngleIndex;

        digits.forEach(function (digit) {
            let angle = angleIndex * Math.PI,
                    x = middleX + (radius - digitsOffsetFromArc) * Math.cos(angle),
                    y = middleY + (radius - digitsOffsetFromArc) * Math.sin(angle);

            angleIndex += step;

            ctx.font = digitsFont;
            ctx.fillStyle = digitsColor;
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.fillText(digit, x, y);
        });
    };
    /*draw arrow РИСОВАНИЕ СТРЕЛКИ*/
    let DrawArrow = function () {
        let arrowAngle = arrowValueIndex * Math.PI;
        let toX = middleX + (radius) * Math.cos(arrowAngle)+50;
        let toY = middleY + (radius) * Math.sin(arrowAngle)-50;

        ctx.beginPath();
        ctx.moveTo(middleX, middleY);
        ctx.lineTo(toX, toY);
        ctx.strokeStyle = arrowColor;
        ctx.lineWidth = arrowWidth;
        ctx.stroke();
        ctx.closePath();
    };


window.onload=()=>{
    DrawZones();
    DrawTicks();
    DrawDigits();
    DrawArrow();
};

</script>
</body>
</html>

javascript
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Stranger in the Q
    2020-04-11T03:08:49Z2020-04-11T03:08:49Z

    这里是另一种选择,老的不破坏,让有第二个答案:

    let canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d"),
    
        // general settings
        middleX = canvas.width / 2,
        middleY = canvas.height / 2,
        radius = 240,
    
        counterClockwise = false,
    
        // ticks settings
        tickWidth = canvas.width / 100,
        // tickColor = "#746845";
        tickOffsetFromArc = canvas.width / 40,
    
        // Center circle settings
        centerCircleRadius = canvas.width / 20,
        centerCircleColor = "#ccc",
        centerCircleBorderWidth = canvas.width / 100,
    
        // Arrow settings
        arrowValueIndex = 0,
        arrowColor = "#464646",
        arrowWidth = canvas.width / 150,
    
        // numbers
        digits = [0, 20, 40, 50, 60, 70, 80, 90, 100],
        digitsColor = "#0a0a0a",
        digitsFont = "bold 20px Tahoma",
        digitsOffsetFromArc = canvas.width / 15,
    
        //zones
        zonesCount = digits.length - 1;
    // beginning and ending of our arc. Sets by radius*pi
    let startAngleIndex = .75,
        endAngleIndex = 2.25,
        step = (endAngleIndex - startAngleIndex) / zonesCount;
    
    /*draw zones*/
    let DrawZones = function () {
      const greyZonesCount = zonesCount / 1.6;
        greenZonesCount = zonesCount - greyZonesCount,
        startAngle = (startAngleIndex - 0.02) * Math.PI,
        endGreyAngle = (startAngleIndex + greyZonesCount * step) * Math.PI,
        endGreenAngle = (endAngleIndex + 0.02) * Math.PI,
    
        //zones' options
        sectionOptions = [{
          startAngle: startAngle,
          endAngle: endGreyAngle,
          color: "#e7e7e7",
          zoneLineWidth: 2
        },{
          startAngle: endGreyAngle,
          endAngle: endGreenAngle,
          color: "#13b74b",
          zoneLineWidth: 5
        }];
    
      this.DrawZone = function (options) {
        ctx.beginPath();
        ctx.arc(middleX, middleY, radius, options.startAngle, options.endAngle, counterClockwise);
        ctx.lineWidth = options.zoneLineWidth;
        ctx.strokeStyle = options.color;
        ctx.lineCap = "round";
        ctx.stroke();
      };
    
      sectionOptions.forEach(options => this.DrawZone(options));
    };
    
    /*draw dots*/
    let DrawTicks = function () {
      startAngleIndex = .73,
      endAngleIndex = 2.27,
      step = (endAngleIndex - startAngleIndex) / zonesCount;
      this.DrawTick = function (angle,count) {
        let fromX = middleX + (radius - tickOffsetFromArc) * Math.cos(angle),
            fromY = middleY + (radius - tickOffsetFromArc) * Math.sin(angle),
            toX = middleX + (radius + tickOffsetFromArc) * Math.cos(angle),
            toY = middleY + (radius + tickOffsetFromArc) * Math.sin(angle),
            centerOfDotX=(fromX+toX)/2,
            centerOfDotY=(fromY+toY)/2;
        ctx.beginPath();
        ctx.arc(centerOfDotX,centerOfDotY,6,0,Math.PI*2,true);
        if (count<6){
          switch (count) {
            case 1:
            case 2:
            case 3:
              ctx.fillStyle="#FF0000";
              break;
            default:
              ctx.fillStyle="#F9AF00";
              break;
          }
        } else {
          ctx.fillStyle="#FFF";
          ctx.strokeStyle="#13B74B";
          ctx.shadowColor = "#a8bbaa";
          ctx.shadowBlur = 15;
          ctx.shadowOffsetX = 0;
          ctx.shadowOffsetY = 0;
          ctx.stroke();
        }
        ctx.fill();
        ctx.closePath();
        ctx.shadowBlur =0;
      };
      let count=0;
      for (let i = startAngleIndex; i <= endAngleIndex; i += step) {
        let angle = i * Math.PI;
        count++;
        this.DrawTick(angle,count);
      }
    };
    
    //draw numbers
    let DrawDigits = function () {
      let angleIndex = startAngleIndex;
      digits.forEach(function (digit) {
        let angle = angleIndex * Math.PI,
                x = middleX + (radius - digitsOffsetFromArc) * Math.cos(angle),
                y = middleY + (radius - digitsOffsetFromArc) * Math.sin(angle);
        angleIndex += step;
        ctx.font = digitsFont;
        ctx.fillStyle = digitsColor;
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(digit, x, y);
      });
    };
    
    /*draw arrow РИСОВАНИЕ СТРЕЛКИ*/
    let DrawArrow = function () {
        ctx.beginPath();
        ctx.moveTo(middleX-17, middleY-47);
        ctx.lineTo(middleX, middleY-180);
        ctx.lineTo(middleX+17, middleY-47);
        ctx.strokeStyle = arrowColor;
        ctx.lineWidth = arrowWidth;
        ctx.stroke();
        ctx.closePath();
        ctx.beginPath();
        ctx.arc(middleX, middleY, 50, Math.PI/8- Math.PI/2, 2 * Math.PI-Math.PI/8- Math.PI/2);
        ctx.stroke();
    };
    
    function draw() {
    
       ctx.clearRect(0,0,canvas.width,canvas.height);
       
       DrawZones();
       DrawTicks();
       DrawDigits();
       
       ctx.translate(middleX,middleY);
       ctx.rotate(arrowValueIndex);
       ctx.translate(-middleX,-middleY);
       
       DrawArrow();
     
       ctx.translate(middleX,middleY);
       ctx.rotate(-arrowValueIndex);
       ctx.translate(-middleX,-middleY);
    }
    
    window.onload = draw
    
    function val(value) {
      let sector = Math.PI*0.385
      if (value < 40)
        arrowValueIndex = value/40*sector - sector*2;
      else
        arrowValueIndex = (value-40)/60*sector*3 - sector;
      document.querySelector('span').textContent = value;
      draw();
    }
    <input type="range" value="60" onmousemove="val(this.value)"><span></span><br>
    <canvas id="canvas" width="500" height="500"></canvas>

    • 3
  2. Stranger in the Q
    2020-04-11T01:56:28Z2020-04-11T01:56:28Z

    可惜尺度分布不均匀,如果均匀的话可以这样

    function draw() {
    
       ctx.clearRect(0,0,canvas.width,canvas.height) //очистка канвы
    
       ctx.translate(middleX,middleY);   // сдвиг в центр
       ctx.rotate(arrowValueIndex);      // поворот табло
       ctx.translate(-middleX,-middleY); // сдвиг обратно
    
       DrawZones();
       DrawTicks();                      // рисует табло
       DrawDigits();
    
       ctx.translate(middleX,middleY);   // сдвиг в центр
       ctx.rotate(-arrowValueIndex);     // обратный поворот табло
       ctx.translate(-middleX,-middleY); // сдвиг обратно
    
       DrawArrow();                      // стрелка
    
    }
    

    let canvas = document.getElementById("canvas"),
            ctx = canvas.getContext("2d"),
    
            // general settings
            middleX = canvas.width / 2,
            middleY = canvas.height / 2,
            radius = 240,
    
            counterClockwise = false,
    
            // ticks settings
            tickWidth = canvas.width / 100,
            // tickColor = "#746845";
            tickOffsetFromArc = canvas.width / 40,
    
            // Center circle settings
            centerCircleRadius = canvas.width / 20,
            centerCircleColor = "#ccc",
            centerCircleBorderWidth = canvas.width / 100,
    
            // Arrow settings
            arrowValueIndex = 0,
            arrowColor = "#464646",
            arrowWidth = canvas.width / 150,
    
            // numbers
            digits = [0, 20, 40, 50, 60, 70, 80, 90, 100],
            digitsColor = "#0a0a0a",
            digitsFont = "bold 20px Tahoma",
            digitsOffsetFromArc = canvas.width / 15,
    
            //zones
            zonesCount = digits.length - 1;
        // beginning and ending of our arc. Sets by radius*pi
        let startAngleIndex = .75,
            endAngleIndex = 2.25,
            step = (endAngleIndex - startAngleIndex) / zonesCount;
    
        /*draw zones*/
        let DrawZones = function () {
            const greyZonesCount = zonesCount / 1.6;
                  greenZonesCount = zonesCount - greyZonesCount,
                  startAngle = (startAngleIndex - 0.02) * Math.PI,
                  endGreyAngle = (startAngleIndex + greyZonesCount * step) * Math.PI,
                  endGreenAngle = (endAngleIndex + 0.02) * Math.PI,
    
                  //zones' options
                  sectionOptions = [
                      {
                          startAngle: startAngle,
                          endAngle: endGreyAngle,
                          color: "#e7e7e7",
                          zoneLineWidth: 2
                      },
                      {
                          startAngle: endGreyAngle,
                          endAngle: endGreenAngle,
                          color: "#13b74b",
                          zoneLineWidth: 5
                      },
                  ];
    
            this.DrawZone = function (options) {
                ctx.beginPath();
                ctx.arc(middleX, middleY, radius, options.startAngle, options.endAngle, counterClockwise);
                ctx.lineWidth = options.zoneLineWidth;
                ctx.strokeStyle = options.color;
                ctx.lineCap = "round";
                ctx.stroke();
            };
    
            sectionOptions.forEach(options => this.DrawZone(options));
        };
    
        /*draw dots*/
        let DrawTicks = function () {
            startAngleIndex = .73,
            endAngleIndex = 2.27,
            step = (endAngleIndex - startAngleIndex) / zonesCount;
            this.DrawTick = function (angle,count) {
    
                let fromX = middleX + (radius - tickOffsetFromArc) * Math.cos(angle),
                    fromY = middleY + (radius - tickOffsetFromArc) * Math.sin(angle),
                    toX = middleX + (radius + tickOffsetFromArc) * Math.cos(angle),
                    toY = middleY + (radius + tickOffsetFromArc) * Math.sin(angle),
    
                    centerOfDotX=(fromX+toX)/2,
                    centerOfDotY=(fromY+toY)/2;
                ctx.beginPath();
                ctx.arc(centerOfDotX,centerOfDotY,6,0,Math.PI*2,true);
                if (count<6){
                    switch (count) {
                        case 1:
                        case 2:
                        case 3:
                            ctx.fillStyle="#FF0000";
                            break;
                        default:
                            ctx.fillStyle="#F9AF00";
                            break;
                    }
                }else{
                    ctx.fillStyle="#FFF";
                    ctx.strokeStyle="#13B74B";
                    ctx.shadowColor = "#a8bbaa";
                    ctx.shadowBlur = 15;
                    ctx.shadowOffsetX = 0;
                    ctx.shadowOffsetY = 0;
                    ctx.stroke();
                }
                ctx.fill();
                ctx.closePath();
                ctx.shadowBlur =0;
            };
            let count=0;
            for (let i = startAngleIndex; i <= endAngleIndex; i += step) {
                let angle = i * Math.PI;
                count++;
                this.DrawTick(angle,count);
            }
        };
    
        //draw numbers
        let DrawDigits = function () {
            let angleIndex = startAngleIndex;
    
            digits.forEach(function (digit) {
                let angle = angleIndex * Math.PI,
                        x = middleX + (radius - digitsOffsetFromArc) * Math.cos(angle),
                        y = middleY + (radius - digitsOffsetFromArc) * Math.sin(angle);
    
                angleIndex += step;
    
                ctx.font = digitsFont;
                ctx.fillStyle = digitsColor;
                ctx.textAlign = "center";
                ctx.textBaseline = "middle";
                ctx.fillText(digit, x, y);
            });
        };
        /*draw arrow РИСОВАНИЕ СТРЕЛКИ*/
        let DrawArrow = function () {
            ctx.beginPath();
            ctx.moveTo(middleX-17, middleY-47);
            ctx.lineTo(middleX, middleY-180);
            ctx.lineTo(middleX+17, middleY-47);
            ctx.strokeStyle = arrowColor;
            ctx.lineWidth = arrowWidth;
            ctx.stroke();
            ctx.closePath();
            ctx.beginPath();
            ctx.arc(middleX, middleY, 50, Math.PI/8- Math.PI/2, 2 * Math.PI-Math.PI/8- Math.PI/2);
            ctx.stroke();
        };
    
    function draw() {
    
       ctx.clearRect(0,0,canvas.width,canvas.height)
       
       ctx.translate(middleX,middleY);
       ctx.rotate(arrowValueIndex);
       ctx.translate(-middleX,-middleY);
       
       DrawZones();
       DrawTicks();
       DrawDigits();
       
       ctx.translate(middleX,middleY);
       ctx.rotate(-arrowValueIndex);
       ctx.translate(-middleX,-middleY);
       
       DrawArrow();
       
    }
    
    window.onload = draw;
    
    function val(value) {
      let sector = Math.PI*0.385
      if (value < 40)
        arrowValueIndex = value/40*sector - sector*2;
      else
        arrowValueIndex = (value-40)/60*sector*3 - sector;
      document.querySelector('span').textContent = value;
      draw()
    }
    <input type="range" value="60" onmousemove="val(this.value)"><span></span><br>
    <canvas id="canvas" width="500" height="500"></canvas>

    • 1
  3. Андрей
    2020-04-11T00:33:37Z2020-04-11T00:33:37Z

    没有使用画布,但查看实现数据,它可能会有所帮助: http ://www.knowstack.com/html5-canvas-speedometer/

    https://github.com/vjt/canvas-speedometer

    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5