最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dashed Curves on Html5 Canvas Bezier - Stack Overflow

programmeradmin3浏览0评论

For one of my application I would need to draw a dashed curves on the bezier path in Html5 canvas... The dash' length and gaps in between should be variable... It is achivable in JavaFx, see this link... I would like to achieve same effect using Html5 canvas. I know how to draw dashed straight lines, but not curved lines along the bezier...

Though I am not an expert, I know the bezier drawing algorithm, problem I see with this algorithm is, it allows you to identify coordinates on the bezier using the time parameter which ranges from 0 to 1...

This is not sufficient because to draw a dashed bezier, I would need to draw many small beziers, with specified length parameter and at given gap distance, on the main bezier path. There must be some algorithm which is used by JavaFx. If anyone can help me out that would be great.

For one of my application I would need to draw a dashed curves on the bezier path in Html5 canvas... The dash' length and gaps in between should be variable... It is achivable in JavaFx, see this link... I would like to achieve same effect using Html5 canvas. I know how to draw dashed straight lines, but not curved lines along the bezier...

Though I am not an expert, I know the bezier drawing algorithm, problem I see with this algorithm is, it allows you to identify coordinates on the bezier using the time parameter which ranges from 0 to 1...

This is not sufficient because to draw a dashed bezier, I would need to draw many small beziers, with specified length parameter and at given gap distance, on the main bezier path. There must be some algorithm which is used by JavaFx. If anyone can help me out that would be great.

Share Improve this question asked Sep 8, 2011 at 18:28 Software EnthusiasticSoftware Enthusiastic 26.5k17 gold badges60 silver badges68 bronze badges 3
  • There is a smart implementation of something similar that you may be able to adapt to dashed curves here: stackoverflow./questions/4576724/dotted-stroke-in-canvas Live example here: phrogz/tmp/canvas_dashed_line.html – unmounted Commented Sep 8, 2011 at 18:36
  • As I said, I know how to plot the dashed line, the problem is how to draw dashed curves on the bezier path... – Software Enthusiastic Commented Sep 8, 2011 at 18:39
  • I guess you could use the mod op (%) at your bez drawing algo. Set alpha to zero for even position and regular alpha for odd position on the curve relative to its length. If you can provide your bezier algo to me, I don't mind plugging this math in. :) – Juho Vepsäläinen Commented Sep 8, 2011 at 19:03
Add a ment  | 

2 Answers 2

Reset to default 5

I would presume that JavaFX is using a general technique for drawing any dashed curve and just happens to be using it on a bezier in that example.

The hard part is figuring out where to start and stop each dash, which requires knowing the arc length of your bezier curve at various points along it.

There is an analytic approach, but I would suggest the following:

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 e 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]);
    }
  }
};

//bine 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();
};

The main problem with this approach is its unintelligent granularity. When step is too big for your (small) dashes or (big) curve, the step size will not work well and dash boundaries will not fall exactly where you want them to. When step is too small, you may end up doing lineTo()s on points that are a sub-pixel distance away from each other, making for AA artifacts sometimes. Filtering out sub-pixel distance coordinates is not hard, but it is inefficient to generate more 'vertices' than you really need. Coming up with a better step size is actually something I'd consider attacking more analytically.

There is one bonus to using this approach: if you replace bezier(controlPoints, t) with anything else that evaluates to a curve, you'll be drawing dashed whatevers!-- again with the same potential problems listed in the previous paragraph. But a really good solution to the granularity problem could work for all 'well-behaved' curves.

In the future we might be able to use context.setLineDash(segments) : http://www.whatwg/specs/web-apps/current-work/multipage/the-canvas-element.html#line-styles

发布评论

评论列表(0)

  1. 暂无评论