【问题标题】:Dashed Curves on Html5 Canvas BezierHtml5 Canvas Bezier 上的虚线曲线
【发布时间】:2011-09-08 18:28:40
【问题描述】:

对于我的一个应用程序,我需要在 Html5 画布中的贝塞尔路径上绘制虚线曲线...短划线的长度和中间的间隙应该是可变的...它可以在 JavaFx 中实现,see this link。 .. 我想用 Html5 画布达到同样的效果。我知道如何绘制虚直线,但不知道如何沿着贝塞尔曲线绘制曲线...

虽然我不是专家,但我知道bezier drawing algorithm,我看到这个算法的问题是,它允许您使用范围从 0 到 1 的时间参数来识别贝塞尔曲线上的坐标...

这还不够,因为要绘制虚线贝塞尔曲线,我需要在主贝塞尔曲线路径上绘制许多具有指定长度参数和给定间隙距离的小贝塞尔曲线。 JavaFx 必须使用某种算法。如果有人可以帮助我,那就太好了。

【问题讨论】:

  • 有一个类似的智能实现,您可以在这里适应虚线:stackoverflow.com/questions/4576724/dotted-stroke-in-canvas 现场示例:phrogz.net/tmp/canvas_dashed_line.html
  • 正如我所说,我知道如何绘制虚线,问题是如何在贝塞尔路径上绘制虚线......
  • 我猜你可以在你的 bez 绘图算法中使用 mod op (%)。将偶数位置的 alpha 设置为零,曲线上相对于其长度的奇数位置设置常规 alpha。如果您可以向我提供您的贝塞尔算法,我不介意将这个数学插入。:)

标签: javascript math geometry bezier html5-canvas


【解决方案1】:

我认为 JavaFX 正在使用一种通用技术来绘制任何虚线曲线,并且在该示例中恰好在贝塞尔曲线上使用它。

最困难的部分是确定每个破折号的开始和停止位置,这需要知道贝塞尔曲线沿其各个点的arc length。

有一种分析方法,但我建议如下:

var bezier = function(controlPoints, t) {
  /* your code here, I'll presume it returns a 2-element array of x and y. */
};

//just figure out the coordinates of all the points in each dash, don't draw.
//returns an array of arrays, each sub-array will have an even number of nu-
//merical elements, to wit, x and y pairs.

//Argument dashPattern should be an array of alternating dash and space
//lengths, e.g., [10, 10] would be dots, [30, 10] would be dashes,
//[30, 10, 10, 10] would be 30-length dash, 10-length spaces, 10-length dash
// and 10-length space.
var calculateDashedBezier = function(controlPoints, dashPattern) {
  var step = 0.001; //this really should be set by an intelligent method,
                    //rather than using a constant, but it serves as an
                    //example.

  //possibly gratuitous helper functions
  var delta = function(p0, p1) {
    return [p1[0] - p0[0], p1[1] - p0[1]];
  };
  var arcLength = function(p0, p1) {
    var d = delta(p0, p1);
    return Math.sqrt(d[0]*d[0] + d[1] * d[1]);
  };

  var subPaths = [];
  var loc = bezier(controlPoints, 0);
  var lastLoc = loc;

  var dashIndex = 0;
  var length = 0;
  var thisPath = [];
  for(var t = step; t <= 1; t += step) {
    loc = bezier(controlPoints, t);
    length += arcLength(lastLoc, loc);
    lastLoc = loc;

    //detect when we come to the end of a dash or space
    if(length >= dashPattern[dashIndex]) {

      //if we are on a dash, we need to record the path.
      if(dashIndex % 2 == 0)
        subPaths.push(thisPath);

      //go to the next dash or space in the pattern
      dashIndex = (dashIndex + 1) % dashPattern.length;

      //clear the arclength and path.
      thisPath = [];
      length = 0;
    }

    //if we are on a dash and not a space, add a point to the path.
    if(dashIndex % 2 == 0) {
      thisPath.push(loc[0], loc[1]);
    }
  }
  if(thisPath.length > 0)
    subPaths.push(thisPath);
  return subPaths;
};

//take output of the previous function and build an appropriate path
var pathParts = function(ctx, pathParts) {
  for(var i = 0; i < pathParts.length; i++) {
    var part = pathParts[i];
    if(part.length > 0)
      ctx.moveTo(part[0], part[1]);
    for(var j = 1; j < part.length / 2; j++) {
      ctx.lineTo(part[2*j], part[2*j+1]);
    }
  }
};

//combine the above two functions to actually draw a dashed curve.
var drawDashedBezier = function(ctx, controlPoints, dashPattern) {
  var dashes = calculateDashedBezier(controlPoints, dashPattern);
  ctx.beginPath();
  ctx.strokeStyle = /* ... */
  ctx.lineWidth = /* ... */
  pathParts(ctx, dashes);
  ctx.stroke();
};

这种方法的主要问题是其不智能的粒度。当步长对于您的(小)破折号或(大)曲线来说太大时,步长将无法正常工作,并且破折号边界不会完全落在您想要的位置。当步长太小时,您最终可能会在彼此相距亚像素距离的点上执行lineTo()s,有时会产生 AA 伪影。过滤掉亚像素距离坐标并不难,但是生成比你真正需要的更多的“顶点”是低效的。提出更好的步长实际上是我会考虑进行更多分析的攻击。

使用这种方法有一个好处:如果您将bezier(controlPoints, t) 替换为任何其他计算结果为曲线的东西,您将绘制虚线!--再次出现上一段中列出的相同潜在问题。但是对于粒度问题,一个非常好的解决方案可能适用于所有“表现良好”的曲线。

【讨论】:

  • 您正确地指出,假定步长 = 0.001 是一个很大的风险,因为您可能不知道高级贝塞尔曲线的大小。如果通过找到中点递归计算步长,直到两点的距离变为零或曲线变直...
  • 另一种更简单的方法是将step 设置为贝塞尔曲线的弧长除以最小虚线长度的近似值。尽管如此,如果您的曲线使得1/step 远大于弧长除以最小虚线长度,则固定的step 将正常工作。
【解决方案2】:

将来我们也许可以使用context.setLineDash(segments): http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#line-styles

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-21
    • 2019-10-11
    • 2019-02-28
    • 2012-09-07
    • 1970-01-01
    • 2020-12-16
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多