2011-11-21 59 views
8

que estoy trabajando en la aplicación de mapas de concepto, que tiene un conjunto de nodos y enlaces. He conectado los enlaces a los nodos utilizando el centro del nodo como referencia. Como tengo nodos con diferentes tamaños y formas, no es aconsejable dibujar la punta de flecha para el enlace especificando la altura o el ancho de la forma. Mi enfoque es dibujar un enlace, comenzando desde un nodo, píxel por píxel hasta que se alcanza el siguiente nodo (aquí los nodos son de diferente color que el del fondo), luego accediendo al valor de píxel, quiero ser capaz de decide el punto de intersección del enlace y el nodo, que en realidad es la coordenada para dibujar la punta de flecha.Dibuje una flecha en Canvas de HTML5 entre dos objetos

Sería muy bueno, si podía obtener alguna ayuda con esto.

Código de ejemplo: http://jsfiddle.net/9tUQP/4/

Aquí los cuadrados verdes son nodos y la línea de salida de la plaza izquierda y entrar en la plaza derecha es el enlace. Quiero que la punta de flecha se dibuje en el punto de intersección del enlace y el cuadrado correcto.

Respuesta

15

He creado un ejemplo que hace esto. Uso Bresenham's Line Algorithm para recorrer la línea de píxeles de lienzo completo y verificar el alfa en cada punto; cada vez que cruza un punto 'umbral' lo registro como candidato. Luego uso el primero y el último de esos puntos para dibujar una flecha (con una punta de flecha rotada apropiadamente).

Aquí está el ejemplo: http://phrogz.net/tmp/canvas_shape_edge_arrows.html

refrescar el ejemplo para ver un nuevo caso de prueba al azar. 'Falla' si tiene otra 'forma' que ya se superpone a uno de los puntos finales. Una forma de resolver esto sería dibujar sus formas primero en un lienzo en blanco y luego copiar el resultado (drawImage) en el lienzo final.

Para la posteridad desbordamiento de pila (en caso de que mi sitio está desactivado) aquí está el código relevante:

<!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

enlace a mi trabajo: http://jsfiddle.net/emYhJ/ Puede usted pls refactorearlo para encajar mi código. –

+0

Gracias de todos modos ... Lo descubrimos :) –

+0

@ allwyn.menezes ¿por qué quieres dibujarlo a través del segundo cubo? ¿Puedes actualizar tu violín? – FutuToad