48 votes

trait en pointillé dans <canvas>

Je suppose qu'il n'est pas possible de définir une propriété d'attaque telle que CSS qui est assez facile. Avec les CSS, nous disposons de tirets, de pointillés, de solides, mais sur le canevas, lorsque l'on dessine des lignes ou des traits, cela ne semble pas être une option. Comment l'avez-vous mis en œuvre ?

J'ai vu quelques exemples mais ils sont vraiment longs pour une fonction aussi stupide.

Par exemple :

http://groups.google.com/group/javascript-information-visualization-toolkit/browse_thread/thread/22000c0d0a1c54f9?pli=1

66voto

Phrogz Points 112337

Question amusante ! J'ai écrit une implémentation personnalisée des lignes en pointillés ; vous pouvez Essayez-le ici . J'ai suivi l'exemple d'Adobe Illustrator et je vous ai permis de spécifier un ensemble de longueurs de tirets/intervalles.

Pour la postérité de stackoverflow, voici mon implémentation (légèrement modifiée pour les largeurs de ligne s/o) :

var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if (CP && CP.lineTo){
  CP.dashedLine = function(x,y,x2,y2,dashArray){
    if (!dashArray) dashArray=[10,5];
    if (dashLength==0) dashLength = 0.001; // Hack for Safari
    var dashCount = dashArray.length;
    this.moveTo(x, y);
    var dx = (x2-x), dy = (y2-y);
    var slope = dx ? dy/dx : 1e15;
    var distRemaining = Math.sqrt( dx*dx + dy*dy );
    var dashIndex=0, draw=true;
    while (distRemaining>=0.1){
      var dashLength = dashArray[dashIndex++%dashCount];
      if (dashLength > distRemaining) dashLength = distRemaining;
      var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) );
      if (dx<0) xStep = -xStep;
      x += xStep
      y += slope*xStep;
      this[draw ? 'lineTo' : 'moveTo'](x,y);
      distRemaining -= dashLength;
      draw = !draw;
    }
  }
}

Pour tracer une ligne de 20,150 à 170,10 avec des tirets de 30px de long suivis d'un espace de 10px, vous utiliserez :

myContext.dashedLine(20,150,170,10,[30,10]);

Pour dessiner des tirets et des points alternés, utilisez (par exemple) :

myContext.lineCap   = 'round';
myContext.lineWidth = 4; // Lines 4px wide, dots of diameter 4
myContext.dashedLine(20,150,170,10,[30,10,0,10]);

La longueur du tiret "très court" de 0 combinée avec le capuchon de ligne arrondi donne des points le long de votre ligne.

Si quelqu'un connaît un moyen d'accéder au point actuel d'un chemin de contexte de canevas, j'aimerais bien le savoir, car cela me permettrait d'écrire ceci sous la forme suivante ctx.dashTo(x,y,dashes) au lieu de vous demander de spécifier à nouveau le point de départ dans l'appel de la méthode.

43voto

Rod MacDougall Points 380

Cette version simplifiée du code de Phrogz utilise la fonctionnalité de transformation intégrée de Canvas et gère également les cas particuliers, par exemple lorsque dx = 0.

var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if (CP.lineTo) {
    CP.dashedLine = function(x, y, x2, y2, da) {
        if (!da) da = [10,5];
        this.save();
        var dx = (x2-x), dy = (y2-y);
        var len = Math.sqrt(dx*dx + dy*dy);
        var rot = Math.atan2(dy, dx);
        this.translate(x, y);
        this.moveTo(0, 0);
        this.rotate(rot);       
        var dc = da.length;
        var di = 0, draw = true;
        x = 0;
        while (len > x) {
            x += da[di++ % dc];
            if (x > len) x = len;
            draw ? this.lineTo(x, 0): this.moveTo(x, 0);
            draw = !draw;
        }       
        this.restore();
    }
}

Je pense que mes calculs sont corrects et que le rendu semble correct.

6voto

robertc Points 35382

Mozilla a travaillé sur un mise en œuvre de l'échantillonnage en pointillés pour les canevas, ce qui pourrait être ajouté à la spécification dans un avenir proche.

6voto

saiya_moebius Points 69

La solution de Phroz est excellente. Mais lorsque je l'ai utilisée dans mon application, j'ai trouvé deux bogues.

Le code suivant est une version déboguée (et remaniée pour plus de lisibilité) de celui de Phroz.

// Fixed: Minus xStep bug (when x2 < x, original code bugs)
// Fixed: Vertical line bug (when abs(x - x2) is zero, original code bugs because of NaN)
var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if(CP && CP.lineTo) CP.dashedLine = function(x, y, x2, y2, dashArray){
    if(! dashArray) dashArray=[10,5];
    var dashCount = dashArray.length;
    var dx = (x2 - x);
    var dy = (y2 - y);
    var xSlope = (Math.abs(dx) > Math.abs(dy));
    var slope = (xSlope) ? dy / dx : dx / dy;

    this.moveTo(x, y);
    var distRemaining = Math.sqrt(dx * dx + dy * dy);
    var dashIndex = 0;
    while(distRemaining >= 0.1){
        var dashLength = Math.min(distRemaining, dashArray[dashIndex % dashCount]);
        var step = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
        if(xSlope){
            if(dx < 0) step = -step;
            x += step
            y += slope * step;
        }else{
            if(dy < 0) step = -step;
            x += slope * step;
            y += step;
        }
        this[(dashIndex % 2 == 0) ? 'lineTo' : 'moveTo'](x, y);
        distRemaining -= dashLength;
        dashIndex++;
    }
}

5voto

jcfrei Points 588

Il existe un moyen beaucoup plus simple de le faire. D'après http://www.w3.org/TR/2dcontext/#dom-context-2d-strokestyle strokeStyle accepte les chaînes de caractères, les CanvasGradients ou les CanvasPatterns. Nous prenons donc une image comme ceci :

  <img src="images/dashedLineProto.jpg" id="cvpattern1" width="32" height="32" />

le charger dans une toile, et dessiner notre petit rectangle avec.

  var img=document.getElementById("cvpattern1");
  var pat=ctx.createPattern(img,"repeat");
  ctx.strokeStyle = pat;
  ctx.strokeRect(20,20,150,100);

qui n'aboutit pas à une ligne pointillée parfaite, mais c'est vraiment simple et modifiable. Les résultats peuvent bien sûr devenir imparfaits lorsque vous dessinez des lignes qui ne sont pas horizontales ou verticales, un motif en pointillés pourrait vous aider dans ce cas.

PS : n'oubliez pas que le SOP s'applique lorsque vous essayez d'utiliser des images provenant de sources externes dans votre code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X