2011-11-21 87 views
8

Tôi đang làm việc trên ứng dụng bản đồ khái niệm, có một tập hợp các nút và liên kết. Tôi đã kết nối các liên kết đến các nút bằng cách sử dụng trung tâm của nút làm tham chiếu. Vì tôi có các nút có kích thước và hình dạng khác nhau, không nên vẽ đầu mũi tên cho liên kết bằng cách chỉ định chiều cao hoặc chiều rộng của hình dạng. Cách tiếp cận của tôi là vẽ một liên kết, bắt đầu từ một nút, điểm ảnh bằng pixel cho đến khi nút tiếp theo đạt được (ở đây các nút có màu khác với màu nền), sau đó bằng cách truy cập giá trị pixel, tôi muốn có thể quyết định điểm giao nhau của liên kết và nút, mà thực sự là phối hợp để vẽ đầu mũi tên.Vẽ mũi tên trên Canvas HTML5 giữa hai đối tượng

Thật tuyệt vời nếu tôi có thể nhận được trợ giúp về vấn đề này.

Sample Code: http://jsfiddle.net/9tUQP/4/

đây các ô vuông màu xanh lá cây là các nút và dòng bắt đầu từ vuông bên trái và nhập vào ô vuông bên phải là liên kết. Tôi muốn đầu mũi tên được vẽ tại điểm giao nhau của liên kết và hình vuông bên phải.

Trả lời

15

Tôi đã tạo một ví dụ thực hiện việc này. Tôi sử dụng Bresenham's Line Algorithm để đi bộ đường thẳng của toàn bộ pixel pixel và kiểm tra alpha tại mỗi điểm; bất cứ khi nào nó đi qua một điểm 'ngưỡng' tôi ghi lại đó là một ứng cử viên. Sau đó tôi sử dụng điểm đầu tiên và cuối cùng để vẽ mũi tên (với đầu mũi tên xoay đúng).

Đây là ví dụ: http://phrogz.net/tmp/canvas_shape_edge_arrows.html

Làm mới ví dụ để xem trường hợp thử nghiệm ngẫu nhiên mới. Nó 'thất bại' nếu bạn có một 'hình dạng' khác chồng lên nhau một trong những điểm kết thúc. Một cách để giải quyết vấn đề này là vẽ hình dạng của bạn trước tiên lên một khung trống và sau đó sao chép kết quả (drawImage) vào canvas cuối cùng.

Đối với Stack Overflow hậu thế (trong trường hợp trang web của tôi là xuống) đây là đoạn code liên quan:

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

liên kết đến công việc của tôi: http://jsfiddle.net/emYhJ/ Bạn có thể xin refactor nó để phù hợp với ma cua toi. –

+0

Cảm ơn anyway .. Đã tìm ra :) –

+0

@ allwyn.menezes tại sao bạn muốn vẽ nó qua khối lập phương thứ 2? Bạn có thể cập nhật fiddle của bạn? – FutuToad

Các vấn đề liên quan