Domanda

Per una delle mie applicazione avrei bisogno di disegnare una curva tratteggiata sul percorso Bezier in tela HTML5 ... La lunghezza del trattino e la spazi vuoti nel mezzo dovrebbero essere variabili ... è attivabile in Javafx, Vedi questo link... Vorrei ottenere lo stesso effetto usando la tela HTML5. So come disegnare linee rette tratteggiate, ma non linee curve lungo la Bezier ...

Anche se non sono un esperto, conosco il Algoritmo di disegno di Bezier, Problema che vedo con questo algoritmo è che ti consente di identificare le coordinate sulla Bezier usando il parametro Time che varia da 0 a 1 ...

Ciò non è sufficiente perché per disegnare un tratteggio tratteggiato, avrei bisogno di disegnare molti piccoli banci, con parametro di lunghezza specificato e a una data distanza di gap, sul percorso principale principale. Ci deve essere un po 'di algoritmo che viene utilizzato da Javafx. Se qualcuno può aiutarmi, sarebbe fantastico.

È stato utile?

Soluzione

Presumo che Javafx stia usando una tecnica generale per disegnare qualsiasi curva tratteggiata e in quell'esempio lo sta solo usando su un Bezier.

La parte difficile è capire da dove iniziare e fermare ogni cruscotto, il che richiede di conoscere il lunghezza dell'arco della tua curva di Bezier in vari punti lungo di essa.

C'è un approccio analitico, ma suggerirei quanto segue:

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

Il problema principale con questo approccio è la sua granularità poco intelligente. Quando il passo è troppo grande per i tuoi (piccoli) trattini o (grande) curva, la dimensione del passo non funzionerà bene e i confini del trattino non cadranno esattamente dove vuoi. Quando il passaggio è troppo piccolo, potresti finire per farlo lineTo()s su punti che sono una distanza sub-pixel l'una dall'altra, a volte realizzando artefatti AA. Filtrando le coordinate della distanza dei sub-pixel non è difficile, ma è inefficiente generare più "vertici" di quanto tu abbia davvero bisogno. Ottenere una dimensione del passo migliore è in realtà qualcosa che prenderei in considerazione di attaccare in modo più analitico.

C'è un bonus per l'utilizzo di questo approccio: se si sostituisce bezier(controlPoints, t) Con qualsiasi altra cosa che valuti una curva, attirerai whatevers tratteggiati!- Ancora una volta con gli stessi potenziali problemi elencati nel paragrafo precedente. Ma una soluzione davvero buona al problema della granularità potrebbe funzionare per tutte le curve "ben educate".

Altri suggerimenti

In futuro potremmo essere in grado di usare context.setLineDash(segments) : http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#line-styles

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top