将圆角应用于路径/多边形

时间:2013-10-09 10:34:54

标签: javascript canvas svg raphael fabricjs

我正在为一个必须在几周内开始的项目收集一些信息。 该项目包含基于浏览器的绘图工具,用户可以在其中添加预定义的形状或自己形成形状。形状必须是可选择的,可自由缩放,并可使用类似Illustrator的transformtool(手柄)旋转。 我们想到的预定义形状是:矩形,椭圆,半椭圆和(等腰)三角形。

到目前为止,为了达到这个目的,我想到了RaphaelJS或FabricJS,但是...每个形状(多边形/路径)都必须用某个cornerradius绘制。并且在缩放时必须保持角半径,因此不会发生失真。用户可以通过输入指定舍入。

有一些障碍/问题:

  • 是否有一些统一的数学公式将角径应用于我提到的形状?或者每个形状都必须被视为迷你项目本身?我想将它作为路径或多边形返回,因此可以使用SVG或画布绘制。
  • 通过拖动变换手柄,每次缩放或旋转操作都会导致(大量)计算以检索我认为的更新形状。矩形是最容易实现的,除了椭圆之外,所有其他形状将更难计算。有没有办法加快这个过程?

我找到了一个网站,用户可以在其中绘制流程图并在几乎所有提供的形状上应用cornerradius。它运作得非常顺利,我无法确定它们是如何做到的。 链接:https://www.lucidchart.com/(尝试按钮)

现在,我有点无能为力,我想在数学方面平庸。也许有人可以把我推向正确的方向并分享一些经验?

提前致谢。

顺便说一句。绩效是这个项目的关键。图纸的输出必须是SVG格式。

3 个答案:

答案 0 :(得分:33)

我最终遇到了类似的问题,但却找不到简单的解决方案。我最终编写了一个基于Adobe Illustrator操作的相当通用的转角函数。它使用贝塞尔曲线而不是弧线,但我认为结果相当不错。

它支持使用SVG图像的坐标空间中给出的半径进行舍入,或者作为角点与其邻居之间距离的一部分。

要使用它,请在项目中包含rounding.js并调用函数:

roundPathCorners(pathString, radius, useFractionalRadius)

代码和一些测试路径在这里:http://embed.plnkr.co/kGnGGyoOCKil02k04snu/preview

以下是Plnkr的示例:

SVG Path Rounding Examples

答案 1 :(得分:2)

起点可能是using-svg-curves-to-imitate-rounded-corners。原理是用速记相对立方转换每个角。此示例非常基本,仅适用于两种可能的极端情况。

我认为扩展这个像角替换用速记相对立方可以扩展以覆盖其他路径段。每个细分都有一个曲线上的坐标点,必须用s段替换。数学可以是这个解决方案的有趣部分。

答案 2 :(得分:2)

尽管这个问题存在了一段时间,但有些人可能会停下来尝试这个解决方案:

var BORDER_RADIUS = 20;

function roundedPath( /* x1, y1, x2, y2, ..., xN, yN */ ){
    context.beginPath();
    if (!arguments.length) return;

    //compute the middle of the first line as start-stop-point:
    var deltaY = (arguments[3] - arguments[1]);
    var deltaX = (arguments[2] - arguments[0]);
    var xPerY = deltaY / deltaX;
    var startX = arguments[0] + deltaX / 2;
    var startY = arguments[1] + xPerY * deltaX / 2;

    //walk around using arcTo:
    context.moveTo(startX, startY);
    var x1, y1, x2, y2;
    x2 = arguments[2];
    y2 = arguments[3];
    for (var i = 4; i < arguments.length; i += 2) {
        x1 = x2;
        y1 = y2;
        x2 = arguments[i];
        y2 = arguments[i + 1];
        context.arcTo(x1, y1, x2, y2, BORDER_RADIUS);
    }

    //finally, close the path:
    context.arcTo(x2, y2, arguments[0], arguments[1], BORDER_RADIUS);
    context.arcTo(arguments[0], arguments[1], startX, startY, BORDER_RADIUS);
    context.closePath();
}

诀窍是在第一行的中间开始(并停止),然后使用arcTo函数,该函数描述得非常好here

现在你“只是”必须找到一种方法将所有形状表示为多边形。