2011-11-21 6 views
8

Je travaille sur l'application de cartes conceptuelles, qui a un ensemble de nœuds et de liens. J'ai connecté les liens aux nœuds en utilisant le centre du nœud comme référence. Comme j'ai des nœuds de tailles et de formes différentes, il n'est pas conseillé de dessiner une flèche pour le lien en spécifiant la hauteur ou la largeur de la forme. Mon approche consiste à dessiner un lien, en partant d'un nœud, pixel par pixel, jusqu'à ce que le nœud suivant soit atteint (ici les nœuds sont de couleurs différentes de l'arrière plan), puis en accédant à la valeur du pixel, je veux pouvoir Décidez du point d'intersection du lien et du nœud, qui est en fait la coordonnée pour dessiner la tête de flèche.Dessiner une flèche sur le canevas HTML5 entre deux objets

Ce serait génial, si je pouvais obtenir de l'aide avec cela.

Exemple de code: http://jsfiddle.net/9tUQP/4/

Ici, les carrés verts sont des noeuds et la ligne de départ de la place gauche et entrer dans le carré de droite est le lien. Je veux que la tête de flèche soit dessinée au point d'intersection du lien et du carré droit.

Répondre

15

J'ai créé un exemple qui fait cela. J'utilise Bresenham's Line Algorithm pour parcourir la ligne des pixels de la toile entière et vérifier l'alpha à chaque point; chaque fois qu'il franchit un seuil, je l'enregistre comme candidat. J'utilise ensuite le premier et le dernier de ces points pour dessiner une flèche (avec une pointe de flèche correctement tournée).

Voici l'exemple: http://phrogz.net/tmp/canvas_shape_edge_arrows.html

Actualiser l'exemple pour voir un nouveau cas de test aléatoire. Il échoue si vous avez une autre forme qui chevauche déjà l'un des points finaux. Une façon de résoudre ce problème consiste à dessiner vos formes d'abord sur un canevas vierge, puis à copier le résultat (drawImage) dans le canevas final.

Pour Stack Overflow postérité (dans le cas où mon site est en panne), voici le code correspondant:

<!DOCTYPE html> 
<html><head> 
    <meta charset="utf-8"> 
    <title>HTML5 Canvas Shape Edge Detection (for Arrow)</title> 
    <style type="text/css"> 
    body { background:#eee; margin:2em 4em; text-align:center; } 
    canvas { background:#fff; border:1px solid #666 } 
    </style> 
</head><body> 
    <canvas width="800" height="600"></canvas> 
    <script type="text/javascript"> 
    var ctx = document.querySelector('canvas').getContext('2d'); 

    for (var i=0;i<20;++i) randomCircle(ctx,'#999'); 

    var start = randomDiamond(ctx,'#060'); 
    var end = randomDiamond(ctx,'#600'); 
    ctx.lineWidth = 2; 
    ctx.fillStyle = ctx.strokeStyle = '#099'; 
    arrow(ctx,start,end,10); 

    function arrow(ctx,p1,p2,size){ 
     ctx.save(); 

     var points = edges(ctx,p1,p2); 
     if (points.length < 2) return 
     p1 = points[0], p2=points[points.length-1]; 

     // Rotate the context to point along the path 
     var dx = p2.x-p1.x, dy=p2.y-p1.y, len=Math.sqrt(dx*dx+dy*dy); 
     ctx.translate(p2.x,p2.y); 
     ctx.rotate(Math.atan2(dy,dx)); 

     // line 
     ctx.lineCap = 'round'; 
     ctx.beginPath(); 
     ctx.moveTo(0,0); 
     ctx.lineTo(-len,0); 
     ctx.closePath(); 
     ctx.stroke(); 

     // arrowhead 
     ctx.beginPath(); 
     ctx.moveTo(0,0); 
     ctx.lineTo(-size,-size); 
     ctx.lineTo(-size, size); 
     ctx.closePath(); 
     ctx.fill(); 

     ctx.restore(); 
    } 

    // Find all transparent/opaque transitions between two points 
    // Uses http://en.wikipedia.org/wiki/Bresenham's_line_algorithm 
    function edges(ctx,p1,p2,cutoff){ 
     if (!cutoff) cutoff = 220; // alpha threshold 
     var dx = Math.abs(p2.x - p1.x), dy = Math.abs(p2.y - p1.y), 
      sx = p2.x > p1.x ? 1 : -1, sy = p2.y > p1.y ? 1 : -1; 
     var x0 = Math.min(p1.x,p2.x), y0=Math.min(p1.y,p2.y); 
     var pixels = ctx.getImageData(x0,y0,dx+1,dy+1).data; 
     var hits=[], over=null; 
     for (x=p1.x,y=p1.y,e=dx-dy; x!=p2.x||y!=p2.y;){ 
     var alpha = pixels[((y-y0)*(dx+1)+x-x0)*4 + 3]; 
     if (over!=null && (over ? alpha<cutoff : alpha>=cutoff)){ 
      hits.push({x:x,y:y}); 
     } 
     var e2 = 2*e; 
     if (e2 > -dy){ e-=dy; x+=sx } 
     if (e2 < dx){ e+=dx; y+=sy } 
     over = alpha>=cutoff; 
     } 
     return hits; 
    } 

    function randomDiamond(ctx,color){ 
     var x = Math.round(Math.random()*(ctx.canvas.width - 100) + 50), 
      y = Math.round(Math.random()*(ctx.canvas.height - 100) + 50); 
     ctx.save(); 
     ctx.fillStyle = color; 
     ctx.translate(x,y); 
     ctx.rotate(Math.random() * Math.PI); 
     var scale = Math.random()*0.8 + 0.4; 
     ctx.scale(scale,scale); 
     ctx.lineWidth = 5/scale; 
     ctx.fillRect(-50,-50,100,100); 
     ctx.strokeRect(-50,-50,100,100); 
     ctx.restore(); 
     return {x:x,y:y}; 
    } 

    function randomCircle(ctx,color){ 
     ctx.save(); 
     ctx.beginPath(); 
     ctx.arc(
     Math.round(Math.random()*(ctx.canvas.width - 100) + 50), 
     Math.round(Math.random()*(ctx.canvas.height - 100) + 50), 
     Math.random()*20 + 10, 
     0, Math.PI * 2, false 
    ); 
     ctx.fillStyle = color; 
     ctx.fill(); 
     ctx.lineWidth = 2; 
     ctx.stroke(); 
     ctx.restore(); 
    } 

    </script> 
</body></html> 
+0

lien vers mon travail: http://jsfiddle.net/emYhJ/ Pouvez-vous svp factoriser pour l'adapter mon code. –

+0

Merci quand même .. Je l'ai trouvé :) –

+0

@ allwyn.menezes pourquoi voulez-vous le dessiner à travers le 2ème cube? Pouvez-vous mettre à jour votre violon? – FutuToad

Questions connexes