簡體   English   中英

Html5 Canvas Bezier上的虛線曲線

[英]Dashed Curves on Html5 Canvas Bezier

對於我的一個應用程序,我需要在Html5畫布的bezier路徑上畫一條虛線曲線......它們之間的短划線和間隙應該是可變的...它可以在JavaFx中找到, 請看這個鏈接 ...我想用Html5畫布達到同樣的效果。 我知道如何繪制虛線直線,但沿着貝塞爾曲線不是曲線...

雖然我不是專家,但我知道bezier繪圖算法 ,我用這個算法看到的問題是,它允許你使用時間參數識別貝塞爾坐標,范圍從0到1 ......

這是不夠的,因為要繪制一個虛線貝塞爾曲線,我需要在主貝塞爾曲線路徑上繪制許多具有指定長度參數且在給定間隙距離處的小貝塞爾曲線。 必須有一些JavaFx使用的算法。 如果有人能幫助我,這將是偉大的。

將來我們可以使用context.setLineDash(segments)http//www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#line-styles

我認為JavaFX正在使用一種通用技術繪制任何虛線曲線,恰好在該示例中恰好在貝塞爾曲線上使用它。

困難的部分是確定從哪里開始和停止每個破折號,這需要知道沿着它的各個點處的貝塞爾曲線的弧長

有一種分析方法,但我建議如下:

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)替換為評估曲線的任何其他東西,你將會繪制虛線的whatevers! - 再次出現與前一段中列出的相同的潛在問題。 但是粒度問題的一個非常好的解決方案可以適用於所有“表現良好”的曲線。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM