【问题标题】:How to draw. arcs in javascript?如何绘制。 javascript中的弧线?
【发布时间】:2020-10-22 15:08:11
【问题描述】:

如何在javascript中实现圆角?

以下是绘制圆角的C#代码。

一些带有 Paint 的几何图形:


0. 你有一个角落:
![角落][1]

1.你知道角点的坐标,设P1, P2 and P:
![角点][2]

2. 现在您可以从向量之间的点和角度获取向量:
![向量和角度][3]

angle = atan(PY - P1Y, PX - P1X) - atan(PY - P2Y , PX - P2X)

3.获取角点与圆交点之间的线段长度。
![段][4]
段 = PC1 = PC2 = 半径 / |tan(角度 / 2)|

4. 这里需要检查段的长度和PP1和PP2的最小长度:
![最小长度][5]
PP1 的长度:
PP1 = sqrt((PX - P1X)2 sup> + (PY - P1Y)2)

PP长度2:

PP2 = sqrt((PX - P2X)2 sup> + (PY - P2Y)2)

如果段 > PP1 或段 > PP2 那么你需要减小半径:

min = Min(PP1, PP2) (对于多边形,最好将此值除以 2)
段 > 分钟 ?
    段 = 分钟
    半径 = 段 * |tan(角度 / 2)|

5.获取PO的长度:
PO = sqrt(radius2 + segment2)

6、通过向量坐标、长度的比例得到C1X和C1Y向量的长度和段的长度:
![PC1的坐标][6]

比例:

(PX - C1X) / (PX - P1X) = PC1 / PP1

所以:

C1X = PX - (PX - P1 X) * PC1 / PP1

C1Y也是一样:

C1Y = PY - (PY - P1 Y) * PC1 / PP1

7、用同样的方法得到C2X和C2Y
C2X = PX - (PX - P2 X) * PC2 / PP2
C2Y = PY - (PY - P2Y sub>) * PC2 / PP2

8. 现在您可以使用向量PC1 和PC2 的相加,以相同的方式按比例找到圆心:
![向量相加][7]
(PX - OX) / (PX - CX) = PO / PC
(PY - OY) / (PY - CY) = PO / PC

这里:

CX = C1X + C2X - P X
CY = C1Y + C2Y - P是的
PC = sqrt((PX - CX)2 + (PY - CY )2)

让:

dx = PX - CX = PX * 2 - C1X - C2X
dy = PY - CY = PY * 2 - C1Y - C2Y

所以:

PC = sqrt(dx2 + dy2)

OX = PX - dx * PO / PC
OY = PY - dy * PO / PC

9.在这里你可以画一个圆弧。为此,您需要获取弧的起始角度和结束角度:
![圆弧][8]
找到它[这里][9]:
startAngle = atan((C1Y - OY) / (C1X - OX))
endAngle = atan((C2Y - OY) / (C2X sub> - OX))

10. 最后你需要得到一个扫角并做一些检查:
![扫描角度][10]
sweepAngle = endAngle - startAngle

如果 sweepAngle

sweepAngle < 0 ?    
    sweepAngle = - sweepAngle
    startAngle = endAngle

检查sweepAngle是否> 180度:

sweepAngle > 180 ?    
    sweepAngle = 180 - sweepAngle

11. 现在你可以画一个圆角了:
![结果][11]

使用 c# 的一些几何图形:

private void DrawRoundedCorner(Graphics graphics, PointF angularPoint, 
                                PointF p1, PointF p2, float radius)
{
    //Vector 1
    double dx1 = angularPoint.X - p1.X;
    double dy1 = angularPoint.Y - p1.Y;

    //Vector 2
    double dx2 = angularPoint.X - p2.X;
    double dy2 = angularPoint.Y - p2.Y;

    //Angle between vector 1 and vector 2 divided by 2
    double angle = (Math.Atan2(dy1, dx1) - Math.Atan2(dy2, dx2)) / 2;

    // The length of segment between angular point and the
    // points of intersection with the circle of a given radius
    double tan = Math.Abs(Math.Tan(angle));
    double segment = radius / tan;

    //Check the segment
    double length1 = GetLength(dx1, dy1);
    double length2 = GetLength(dx2, dy2);

    double length = Math.Min(length1, length2);

    if (segment > length)
    {
        segment = length;
        radius = (float)(length * tan);
    }

    // Points of intersection are calculated by the proportion between 
    // the coordinates of the vector, length of vector and the length of the segment.
    var p1Cross = GetProportionPoint(angularPoint, segment, length1, dx1, dy1);
    var p2Cross = GetProportionPoint(angularPoint, segment, length2, dx2, dy2);

    // Calculation of the coordinates of the circle 
    // center by the addition of angular vectors.
    double dx = angularPoint.X * 2 - p1Cross.X - p2Cross.X;
    double dy = angularPoint.Y * 2 - p1Cross.Y - p2Cross.Y;

    double L = GetLength(dx, dy);
    double d = GetLength(segment, radius);

    var circlePoint = GetProportionPoint(angularPoint, d, L, dx, dy);

    //StartAngle and EndAngle of arc
    var startAngle = Math.Atan2(p1Cross.Y - circlePoint.Y, p1Cross.X - circlePoint.X);
    var endAngle = Math.Atan2(p2Cross.Y - circlePoint.Y, p2Cross.X - circlePoint.X);

    //Sweep angle
    var sweepAngle = endAngle - startAngle;

    //Some additional checks
    if (sweepAngle < 0)
    {
        startAngle = endAngle;
        sweepAngle = -sweepAngle;
    }

    if (sweepAngle > Math.PI)
        sweepAngle = Math.PI - sweepAngle;

    //Draw result using graphics
    var pen = new Pen(Color.Black);

    graphics.Clear(Color.White);
    graphics.SmoothingMode = SmoothingMode.AntiAlias;

    graphics.DrawLine(pen, p1, p1Cross);
    graphics.DrawLine(pen, p2, p2Cross);

    var left = circlePoint.X - radius;
    var top = circlePoint.Y - radius;
    var diameter = 2 * radius;
    var degreeFactor = 180 / Math.PI;

    graphics.DrawArc(pen, left, top, diameter, diameter, 
                     (float)(startAngle * degreeFactor), 
                     (float)(sweepAngle * degreeFactor));
}

private double GetLength(double dx, double dy)
{
    return Math.Sqrt(dx * dx + dy * dy);
}

private PointF GetProportionPoint(PointF point, double segment, 
                                  double length, double dx, double dy)
{
    double factor = segment / length;

    return new PointF((float)(point.X - dx * factor), 
                      (float)(point.Y - dy * factor));
}

要获得弧点,您可以使用:

//One point for each degree. But in some cases it will be necessary 
// to use more points. Just change a degreeFactor.
int pointsCount = (int)Math.Abs(sweepAngle * degreeFactor);
int sign = Math.Sign(sweepAngle);

PointF[] points = new PointF[pointsCount];

for (int i = 0; i < pointsCount; ++i)
{
    var pointX = 
       (float)(circlePoint.X  
               + Math.Cos(startAngle + sign * (double)i / degreeFactor)  
               * radius);

    var pointY = 
       (float)(circlePoint.Y 
               + Math.Sin(startAngle + sign * (double)i / degreeFactor) 
               * radius);

    points[i] = new PointF(pointX, pointY);
}

我已经实现了这是 javascript:

    let radius = 10;

    const angle =
      Math.atan(p.x - p1.x, p.x - p1.x) - Math.atan(p.y - p2.y, p.x - p2.x);
    let segment = radius / Math.abs(Math.tan(angle / 2));

    const pp1 = Math.sqrt(Math.pow(p.x - p1.x, 2) + Math.pow(p.y - p1.y, 2));
    const pp2 = Math.sqrt(Math.pow(p.x - p2.x, 2) + Math.pow(p.y - p2.y, 2));

    const min = Math.min(pp1, pp2);

    if (segment > min) {
      segment = min;
      radius = segment * Math.abs(Math.tan(angle / 2));
    }

    const po = Math.sqrt(Math.pow(radius, 2) + Math.pow(segment, 2));

    const r = 10;

    const c1x = p.x - ((p.x - p1.x) * segment) / pp1;
    const c1y = p.y - ((p.y - p1.y) * segment) / pp1;
    const c2x = p.x - ((p.x - p2.x) * segment) / pp2;
    const c2y = p.y - ((p.y - p2.y) * segment) / pp2;

    const dx = p.x * 2 - c1x - c2x;
    const dy = p.y * 2 - c1y - c2y;

    const pc = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));

    const ox = p.x - (dx * po) / pc;
    const oy = p.y - (dy * po) / pc;

    let startAngle = Math.atan((c1y - oy) / (c1x - ox));
    let endAngle = Math.atan((c2y - oy) / (c2x - ox));

    let sweepAngle = endAngle - startAngle;

    if (sweepAngle < 0) {
      sweepAngle = -sweepAngle;
      startAngle = endAngle;
    }

    if (sweepAngle > 180) sweepAngle = 180 - sweepAngle;

但问题是圆角没有按预期绘制!

c#中arc的绘制与html canvas arc不同。

那么如何使用上面的数据在html5画布中绘制呢?

【问题讨论】:

    标签: javascript


    【解决方案1】:

    要在html5画布中绘制弧线,可以使用ctx.arc(xPos, yPos, radius, startAngle, endAngle, (optional boolean, defaults to false) counterClockwise);

    文档可以在W3Schools.com找到

    更多通用 html5 画布文档也可以在W3Schools.com找到

    【讨论】:

      猜你喜欢
      • 2014-11-16
      • 2018-08-25
      • 2017-08-28
      • 2018-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-28
      相关资源
      最近更新 更多