2009-04-30 21 views
34

Chcę narysować strzałkę za pomocą tagu canvas, javascript. Zrobiłem to za pomocą funkcji kwadratowej, ale mam problem z obliczeniem kąta obrotu strzałki ...Rysuj strzałkę na płótnie tag

Ktoś ma o tym pojęcia?

Dziękuję

Odpowiedz

1

można wypchnąć matrycy, obróć go, zwracamy strzałkę, a następnie pop matrycy.

7

można zrobić:

ctx.save(); 
ctx.translate(xOrigin, yOrigin); 
ctx.rotate(angle); 
// draw your arrow, with its origin at [0, 0] 
ctx.restore(); 
1
function RTEShape() 
{ 
    this.x = 50; 
    this.y = 50; 
    this.w = 100; // default width and height? 
    this.h = 100; 
    this.fill = '#444444'; 
    this.text = "Test String"; 
    this.type; 
    this.color; 
    this.size = 6;  

    // The selection color and width. Right now we have a red selection with a small width 
    this.mySelColor = '#CC0000'; 
    this.mySelWidth = 2; 
    this.mySelBoxColor = 'darkred';// New for selection boxes 
    this.mySelBoxSize = 6; 
} 

RTEShape.prototype.buildArrow = function(canvas) 
{ 
    this.type = "arrow"; 

    // Make sure we don't execute when canvas isn't supported 
    if (canvas.getContext){ 

    // use getContext to use the canvas for drawing 
    var ctx = canvas.getContext('2d');   

    var oneThirdX = this.x + (this.w/3);    
    var twoThirdX = this.x + ((this.w*2)/3); 

    var oneFifthY = this.y - (this.y/5);  
    var twoFifthY = this.y - ((this.y*3)/5); 

    /**/ 
    //ctx.beginPath(); 
    ctx.moveTo(oneThirdX,this.y); // 125,125 
    ctx.lineTo(oneThirdX,oneFifthY); // 125,105 

    ctx.lineTo(this.x*2,oneFifthY); // 225,105  
    ctx.lineTo(this.x*2,twoFifthY); // 225,65 

    ctx.lineTo(oneThirdX,twoFifthY); // 125,65  
    ctx.lineTo(oneThirdX,(this.y/5)); // 125,45 

    ctx.lineTo(this.x,(this.y+(this.y/5))/2); // 45,85 

     ctx.fillStyle = "green"; 
    ctx.fill(); 

    ctx.fillStyle = "yellow"; 
    ctx.fillRect(this.x,this.y,this.w,this.h); 

    } else { 
    alert('Error on buildArrow!\n'+err.description); 
    } 
} 
63

Tak proste, jak mogę go dostać. Będziesz musiał poprzedzić context.beginPath() i dołączyć context.stroke() siebie:

function canvas_arrow(context, fromx, fromy, tox, toy){ 
    var headlen = 10; // length of head in pixels 
    var angle = Math.atan2(toy-fromy,tox-fromx); 
    context.moveTo(fromx, fromy); 
    context.lineTo(tox, toy); 
    context.lineTo(tox-headlen*Math.cos(angle-Math.PI/6),toy-headlen*Math.sin(angle-Math.PI/6)); 
    context.moveTo(tox, toy); 
    context.lineTo(tox-headlen*Math.cos(angle+Math.PI/6),toy-headlen*Math.sin(angle+Math.PI/6)); 
} 

Oto przykład: http://stuff.titus-c.ch/arrow.html

+1

który wytwarza dziwny kształt, chcesz pozbyć się tej ostatniej akcji i dodać na koniec lineTo (tox, zabawki) – owook

+1

funkcja nie działa dobrze, gdy lineWidth nie jest == 1 –

+0

działa dobrze z 2: P '+ 1' –

2

Biorąc pod uwagę wielkość i pozycję wyjściową, następujący kod zwróci strzała dla ciebie.

<!DOCTYPE HTML> 
<html> 
    <head> 
     <style> 
      body { 
       margin: 0px; 
       padding: 0px; 
      } 

      #myCanvas { 
       border: 1px solid #9C9898; 
      } 
     </style> 
     <script> 
      function draw_arrow(context, startX, startY, size) 
      { 
       var arrowX = startX + 0.75*size; 
       var arrowTopY = startY - 0.707*(0.25*size); 
       var arrowBottomY = startY + 0.707*(0.25*size); 
       context.moveTo(startX, startY); 
       context.lineTo(startX+size, startX); 
       context.lineTo(arrowX, arrowTopY); 
       context.moveTo(startX+size, startX); 
       context.lineTo(arrowX, arrowBottomY); 
       context.stroke(); 
      } 
      window.onload = function(){ 
       var canvas = document.getElementById("myCanvas"); 
       var context = canvas.getContext("2d"); 
       var startX = 50; 
       var startY = 50; 
       var size = 100; 
       context.lineWidth = 2; 
       draw_arrow(context, startX, startY, size); 
      }; 
     </script> 
    </head> 
    <body onmousedown="return false;"> 
     <canvas id="myCanvas" width="578" height="200"> 
     </canvas> 

    </body> 
</html> 
16

Ok, więc pierwsza odpowiedź na tej stronie pomógł mi ogromnie, kiedy starałem się zrozumieć ten problem się sam, choć jak ktoś już wspomniano, jeśli linia szerokość większą niż 1px masz śmieszne kształty . Poprawka, którą ktoś zasugerował, prawie zadziałała, ale nadal miałem pewne problemy, gdy próbowałem uzyskać grubszą strzałkę szerokości. Po kilku godzinach grania z nim udało mi się połączyć powyższe rozwiązanie z odrobiną mojego majsterkowania, by wymyślić następujący kod, który narysuje strzałkę przy dowolnej grubości, bez zniekształcania kształtu strzałki.

function drawArrow(fromx, fromy, tox, toy){ 
       //variables to be used when creating the arrow 
       var c = document.getElementById("myCanvas"); 
       var ctx = c.getContext("2d"); 
       var headlen = 10; 

       var angle = Math.atan2(toy-fromy,tox-fromx); 

       //starting path of the arrow from the start square to the end square and drawing the stroke 
       ctx.beginPath(); 
       ctx.moveTo(fromx, fromy); 
       ctx.lineTo(tox, toy); 
       ctx.strokeStyle = "#cc0000"; 
       ctx.lineWidth = 22; 
       ctx.stroke(); 

       //starting a new path from the head of the arrow to one of the sides of the point 
       ctx.beginPath(); 
       ctx.moveTo(tox, toy); 
       ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7)); 

       //path from the side point of the arrow, to the other side point 
       ctx.lineTo(tox-headlen*Math.cos(angle+Math.PI/7),toy-headlen*Math.sin(angle+Math.PI/7)); 

       //path from the side point back to the tip of the arrow, and then again to the opposite side point 
       ctx.lineTo(tox, toy); 
       ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7)); 

       //draws the paths created above 
       ctx.strokeStyle = "#cc0000"; 
       ctx.lineWidth = 22; 
       ctx.stroke(); 
       ctx.fillStyle = "#cc0000"; 
       ctx.fill(); 
      } 

To jest teraz kod, którego używam w moim programie. To, co odkryłem jako klucz do wyeliminowania problemu zniekształceń, to kontynuowanie uderzenia od wierzchołka strzały do ​​jednego punktu bocznego, do drugiego punktu bocznego, z powrotem do wierzchołka i z powrotem do pierwszego punktu bocznego, a następnie wykonanie napełnić. Poprawiło to kształt strzałki.

Mam nadzieję, że to pomoże!

+0

dzięki, to działa świetnie! – satnam

+0

Przybiłeś to człowieku! – Exception

1

Oto kolejna metoda rysowania strzałek. Używa metody trójkąta stąd: https://stackoverflow.com/a/8937325/1828637

Mała funkcja pomocnika.

funkcja canvas_arrow (kontekst, odx, fromy, tox, zabawka, r) ​​{ var x_center = tox; var y_center = zabawka;

var angle; 
var x; 
var y; 

context.beginPath(); 

angle = Math.atan2(toy-fromy,tox-fromx) 
x = r*Math.cos(angle) + x_center; 
y = r*Math.sin(angle) + y_center; 

context.moveTo(x, y); 

angle += (1/3)*(2*Math.PI) 
x = r*Math.cos(angle) + x_center; 
y = r*Math.sin(angle) + y_center; 

context.lineTo(x, y); 

angle += (1/3)*(2*Math.PI) 
x = r*Math.cos(angle) + x_center; 
y = r*Math.sin(angle) + y_center; 

context.lineTo(x, y); 

context.closePath(); 

context.fill(); 

}

I tu jest demonstracją nim rysować strzałki na początku i na końcu linii.

var can = document.getElementById('c'); 
 
var ctx = can.getContext('2d'); 
 

 
ctx.lineWidth = 10; 
 
ctx.strokeStyle = 'steelblue'; 
 
ctx.fillStyle = 'steelbllue'; // for the triangle fill 
 
ctx.lineJoin = 'butt'; 
 

 
ctx.beginPath(); 
 
ctx.moveTo(50, 50); 
 
ctx.lineTo(150, 150); 
 
ctx.stroke(); 
 

 
canvas_arrow(ctx, 50, 50, 150, 150, 10); 
 
canvas_arrow(ctx, 150, 150, 50, 50, 10); 
 

 
function canvas_arrow(context, fromx, fromy, tox, toy, r){ 
 
\t var x_center = tox; 
 
\t var y_center = toy; 
 
\t 
 
\t var angle; 
 
\t var x; 
 
\t var y; 
 
\t 
 
\t context.beginPath(); 
 
\t 
 
\t angle = Math.atan2(toy-fromy,tox-fromx) 
 
\t x = r*Math.cos(angle) + x_center; 
 
\t y = r*Math.sin(angle) + y_center; 
 

 
\t context.moveTo(x, y); 
 
\t 
 
\t angle += (1/3)*(2*Math.PI) 
 
\t x = r*Math.cos(angle) + x_center; 
 
\t y = r*Math.sin(angle) + y_center; 
 
\t 
 
\t context.lineTo(x, y); 
 
\t 
 
\t angle += (1/3)*(2*Math.PI) 
 
\t x = r*Math.cos(angle) + x_center; 
 
\t y = r*Math.sin(angle) + y_center; 
 
\t 
 
\t context.lineTo(x, y); 
 
\t 
 
\t context.closePath(); 
 
\t 
 
\t context.fill(); 
 
}
<canvas id="c" width=300 height=300></canvas>

1

Kod ten jest podobny do rozwiązania Titus Cieślewski za, być może strzała jest nieco ładniejszy:

function canvasDrawArrow(context, fromx, fromy, tox, toy) { 
    var headlen = 10.0; 
    var back = 4.0; 
    var angle1 = Math.PI/13.0; 
    var angle2 = Math.atan2(toy - fromy, tox - fromx); 
    var diff1 = angle2 - angle1; 
    var diff2 = angle2 + angle1; 
    var xx = getBack(back, fromx, fromy, tox, toy); 
    var yy = getBack(back, fromy, fromx, toy, tox); 

    context.moveTo(fromx, fromy); 
    context.lineTo(tox, toy); 

    context.moveTo(xx, yy); 
    context.lineTo(xx - headlen * Math.cos(diff1), yy - headlen * Math.sin(diff1)); 

    context.moveTo(xx, yy); 
    context.lineTo(xx - headlen * Math.cos(diff2), yy - headlen * Math.sin(diff2)); 
} 

function getBack(len, x1, y1, x2, y2) { 
    return x2 - (len * (x2 - x1)/(Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2)))); 
} 

to działa dobrze z lineWidth > 1. To może się przydać, gdy rysunek x i y

0

var canvas = document.getElementById('canvas'); 
 
var ctx = canvas.getContext('2d'); 
 

 
ctx.clearRect(0, 0, canvas.width, canvas.height); \t 
 
arrow({x: 10, y: 10}, {x: 100, y: 170}, 10); 
 
arrow({x: 40, y: 250}, {x: 10, y: 70}, 5); 
 

 

 
function arrow (p1, p2, size) { 
 
    var angle = Math.atan2((p2.y - p1.y) , (p2.x - p1.x)); 
 
    var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)); 
 

 
    ctx.save(); 
 
    ctx.translate(p1.x, p1.y); 
 
    ctx.rotate(angle); 
 

 
    // line 
 
    ctx.beginPath(); \t 
 
    ctx.moveTo(0, 0); 
 
    ctx.lineTo(hyp - size, 0); 
 
    ctx.stroke(); 
 

 
    // triangle 
 
    ctx.fillStyle = 'blue'; 
 
    ctx.beginPath(); 
 
    ctx.lineTo(hyp - size, size); 
 
    ctx.lineTo(hyp, 0); 
 
    ctx.lineTo(hyp - size, -size); 
 
    ctx.fill(); 
 

 
    ctx.restore(); 
 
}
<canvas id = "canvas" width = "300" height = "400"></canvas>