Я хочу нарисовать стрелку, используя тег canvas, javascript. Я сделал это, используя квадратичную функцию, но у меня возникают проблемы для вычисления угла поворота стрелки...
У кого есть ключ к этому?
Спасибо
Я хочу нарисовать стрелку, используя тег canvas, javascript. Я сделал это, используя квадратичную функцию, но у меня возникают проблемы для вычисления угла поворота стрелки...
У кого есть ключ к этому?
Спасибо
Так просто, как я могу это получить. Вы должны будете предварительно добавить context.beginPath() и добавить context.stroke() самостоятельно:
ctx = document.getElementById("c").getContext("2d");
ctx.beginPath();
canvas_arrow(ctx, 10, 30, 200, 150);
canvas_arrow(ctx, 100, 200, 400, 50);
canvas_arrow(ctx, 200, 30, 10, 150);
canvas_arrow(ctx, 400, 200, 100, 50);
ctx.stroke();
function canvas_arrow(context, fromx, fromy, tox, toy) {
var headlen = 10; // length of head in pixels
var dx = tox - fromx;
var dy = toy - fromy;
var angle = Math.atan2(dy, dx);
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));
}
<html>
<body>
<canvas id="c" width="500" height="500"></canvas>
</body>
Итак, первый ответ на этой странице очень помог мне, когда я пытался понять эту проблему самостоятельно, хотя, как уже сказал кто-то, если у вас ширина линии больше 1px, вы получаете забавные формы. Исправление, которое предложил кто-то другой, почти сработало, но у меня все еще были проблемы при попытке использовать более толстую стрелку ширины. После нескольких часов игры с ним я смог объединить вышеупомянутое решение с некоторыми из моих собственных мастеров, чтобы придумать следующий код, который будет рисовать стрелу любой нужной толщины без искажения формы стрелки.
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();
}
Теперь это код, который я использую в своей программе. То, что я считал ключом к устранению проблемы с искажениями, заключалось в продолжении хода от кончика стрелки до одной боковой точки, к другой стороне, назад к кончику и обратно к первой боковой точке, а затем выполнению заполнить. Это скорректировало форму стрелки.
Надеюсь, это поможет!
Вы можете сделать:
ctx.save();
ctx.translate(xOrigin, yOrigin);
ctx.rotate(angle);
// draw your arrow, with its origin at [0, 0]
ctx.restore();
Вот еще один способ рисовать стрелки. Здесь используется метод треугольника: fooobar.com/questions/166870/...
Маленькая вспомогательная функция.
function canvas_arrow(context, fromx, fromy, tox, toy, r){
var x_center = tox;
var y_center = toy;
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();
}
И вот демонстрация того, как рисовать стрелки в начале и в конце линии.
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){
var x_center = tox;
var y_center = toy;
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();
}
<canvas id="c" width=300 height=300></canvas>
Учитывая размер и начальную позицию, следующий код нарисует стрелку для вас.
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);
};
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
<!DOCTYPE HTML>
<html>
<body onmousedown="return false;">
<canvas id="myCanvas" width="578" height="200"></canvas>
</body>
</html>
Этот код похож на решение Titus Cieslewski, возможно, стрелка немного приятнее:
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))));
}
это хорошо работает с lineWidth > 1
. Это может пригодиться при рисовании оси x
и y
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
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();
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>
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);
}
}
Вы можете нажать свою матрицу, повернуть ее, нарисовать стрелку, а затем поместить матрицу.
Я боролся с этим уже довольно давно. Мне нужно было это как в JavaScript, так и в С#. Для javascript я нашел хорошую библиотеку jCanvas.
Моей главной проблемой было рисование красиво выглядящих наконечников стрел, что отлично делает jCanvas. Для моего проекта на С# я разработал код jCanvas.
Надеюсь, это кому-нибудь поможет
Вот рабочее решение
function draw_arrow(ctx,fx,fy,tx,ty){ //ctx is the context
var angle=Math.atan2(ty-fy,tx-fx);
ctx.moveTo(fx,fy); ctx.lineTo(tx,ty);
var w=3.5; //width of arrow to one side. 7 pixels wide arrow is pretty
ctx.strokeStyle="#4d4d4d"; ctx.fillStyle="#4d4d4d";
angle=angle+Math.PI/2; tx=tx+w*Math.cos(angle); ty=ty+w*Math.sin(angle);
ctx.lineTo(tx,ty);
//Drawing an isosceles triangle of sides proportional to 2:7:2
angle=angle-1.849096; tx=tx+w*3.5*Math.cos(angle); ty=ty+w*3.5*Math.sin(angle);
ctx.lineTo(tx,ty);
angle=angle-2.584993; tx=tx+w*3.5*Math.cos(angle); ty=ty+w*3.5*Math.sin(angle);
ctx.lineTo(tx,ty);
angle=angle-1.849096; tx=tx+w*Math.cos(angle); ty=ty+w*Math.sin(angle);
ctx.lineTo(tx,ty);
ctx.stroke(); ctx.fill();
}