【问题标题】:How to draw triangle pointers inside of circle如何在圆内绘制三角形指针
【发布时间】:2020-04-04 05:11:25
【问题描述】:

我意识到这是一道简单的三角问题,但我的高中现在让我失望了。

给定一个角度,我已将其转换为弧度以获得第一个点。如何在画布上绘制三角形的下两个点,以使小三角形始终指向圆形。所以假设我已经画了一个给定半径的圆。现在我想要一个函数来绘制一个三角形,该三角形位于它内部的圆的边缘,无论角度如何,它都指向外面。 (可以这么说,跟随边缘)

function drawPointerTriangle(ctx, angle){
    var radians = angle * (Math.PI/180)
    var startX = this.radius + this.radius/1.34 * Math.cos(radians)
    var startY = this.radius - this.radius/1.34 * Math.sin(radians)
    // This gives me my starting point on the outer edge of the circle, plotted at the angle I need    
    ctx.moveTo(startX, startY);

   // HOW DO I THEN CALCULATE x1,y1 and x2, y2.  So that no matter what angle I enter into this function, the arrow/triangle always points outwards to the circle.
    ctx.lineTo(x1, y1);
    ctx.lineTo(x2, y2);


}

例如

【问题讨论】:

    标签: javascript html canvas trigonometry


    【解决方案1】:

    你没有说你想画什么类型的三角形,所以我认为它是一个等边三角形。

    看看这张图片(信用here

    我将逆时针从右上角到右下角调用 3 个点 p1、p2、p3。

    可以很方便的计算出三角形在原点与三角形质心重合的坐标系中的三点坐标。

    给定一个点属于圆的边缘和我们刚刚计算的点p1,我们可以计算从我们的主坐标系到三角形坐标系的平移参数。然后,我们只需要将另外两个点的坐标转换回我们的主坐标系。即 (x1,y1) 和 (x2,y2)。

    您可以查看下面基于您的代码的演示。

    const w = 300;
    const h = 300;
    
    function calculateTrianglePoints(angle, width) {
      let r = width / Math.sqrt(3);
      let firstPoint = [
        r * Math.cos(angle),
        r * Math.sin(angle),
      ]
    
      let secondPoint = [
        r * Math.cos(angle + 2 * Math.PI / 3),
        r * Math.sin(angle + 2 * Math.PI / 3),
      ]
    
      let thirdPoint = [
        r * Math.cos(angle + 4 * Math.PI / 3),
        r * Math.sin(angle + 4 * Math.PI / 3),
      ]
    
      return [firstPoint, secondPoint, thirdPoint]
    }
    
    const radius = 100
    const triangleWidth = 20;
    
    function drawPointerTriangle(ctx, angle) {
      var radians = angle * (Math.PI / 180)
      var startX = radius * Math.cos(radians)
      var startY = radius * Math.sin(radians)
      var [pt0, pt1, pt2] = calculateTrianglePoints(radians, triangleWidth);
      var delta = [
        startX - pt0[0],
        startY - pt0[1],
      ]
    
      pt1[0] = pt1[0] + delta[0]
      pt1[1] = pt1[1] + delta[1]
      pt2[0] = pt2[0] + delta[0]
      pt2[1] = pt2[1] + delta[1]
      ctx.beginPath();
      // This gives me my starting point on the outer edge of the circle, plotted at the angle I need    
      ctx.moveTo(startX, startY);
    
      [x1, y1] = pt1;
      [x2, y2] = pt2;
      // HOW DO I THEN CALCULATE x1,y1 and x2, y2.  So that no matter what angle I enter into this function, the arrow/triangle always points outwards to the circle.
      ctx.lineTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.closePath();
      ctx.fillStyle = '#FF0000';
      ctx.fill();
    }
    
    function drawCircle(ctx, radius) {
      ctx.beginPath();
      ctx.arc(0, 0, radius, 0, 2 * Math.PI);
      ctx.closePath();
      ctx.fillStyle = '#000';
      ctx.fill();
    }
    
    function clear(ctx) {
      ctx.fillStyle = '#fff';
      ctx.fillRect(-w / 2, -h / 2, w, h);
    }
    
    function normalizeAngle(pointCoordinate, angle) {
      const [x, y] = pointCoordinate;
      if (x > 0 && y > 0) return angle;
      else if (x > 0 && y < 0) return 360 + angle;
      else if (x < 0 && y < 0) return 180 - angle;
      else if (x < 0 && y > 0) return 180 - angle;
    }
    
    function getAngleFromPoint(point) {
      const [x, y] = point;
      if (x == 0 && y == 0) return 0;
      else if (x == 0) return 90 * (y > 0 ? 1 : -1);
      else if (y == 0) return 180 * (x >= 0 ? 0: 1);
      const radians = Math.asin(y / Math.sqrt(
        x ** 2 + y ** 2
      ))
    
      return normalizeAngle(point, radians / (Math.PI / 180))
    }
    
    document.addEventListener('DOMContentLoaded', function() {
      const canvas = document.querySelector('canvas');
      const angleText = document.querySelector('.angle');
      const ctx = canvas.getContext('2d');
      ctx.translate(w / 2, h / 2);
      drawCircle(ctx, radius);
      drawPointerTriangle(ctx, 0);
      canvas.addEventListener('mousemove', _.throttle(function(ev) {
        let mouseCoordinate = [
          ev.clientX - w / 2,
          ev.clientY - h / 2
        ]
        
        let degAngle = getAngleFromPoint(mouseCoordinate)
    
        clear(ctx);
        drawCircle(ctx, radius);
        drawPointerTriangle(ctx, degAngle)
        angleText.innerText = Math.floor((360 - degAngle)*100)/100;
      }, 15))
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
    <canvas width=300 height=300></canvas>
    <div class="angle">0</div>

    【讨论】:

    • 我实际上在得到答案之前就弄清楚了,但我把这个给了你,因为它是一个非常彻底的答案,有一些很好的示例代码;)
    【解决方案2】:

    减小半径,改变角度,再次调用cos/sin:

    function drawPointerTriangle(ctx, angle)
    {
        var radians = angle * (Math.PI/180);
        var radius = this.radius/1.34;
        var startX = this.center.x + radius * Math.cos(radians);
        var startY = this.center.y + radius * Math.sin(radians);
    
        ctx.moveTo(startX, startY);
    
        radius  *= 0.9;
        radians += 0.1;
        var x1  = this.center.x + radius * Math.cos(radians);
        var y1  = this.center.y + radius * Math.sin(radians);
    
        radians -= 0.2;
        var x1  = this.center.x + radius * Math.cos(radians);
        var y1  = this.center.y + radius * Math.sin(radians);
    
        ctx.lineTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.lineTo(startX, startY);
    }
    

    生成的三角形的大小与圆的大小成正比。


    如果您需要等边、固定大小的三角形,请使用:

    //get h by pythagoras
    h = sqrt( a^2 - (a/2)^2 );)
    //get phi using arcustangens:
    phi = atan( a/2, radius-h );
    //reduced radius h by pythagoras:
    radius = sqrt( (radius-h)^2 + (a/2)^2 );
    
    radians += phi;
    ...
    radians -= 2*phi;
    ...
    

    【讨论】:

      猜你喜欢
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-06
      • 2021-09-14
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多