我有一个在坐标网格上绘制线性图的函数,如下面的JsFiddle所示:https://jsfiddle.net/zje14n92/1/
绘制线性图(与轴相反)的代码组件如下:
if (canvas1.getContext) {
canvas1.width = x_axis * 2;
canvas1.height = y_axis * 2;
var ctx1 = canvas1.getContext("2d");
ctx1.font = "10px sans-serif";
ctx1.strokeText(' ', x_axis+50, 50);
ctx1.lineWidth = 1;
ctx1.beginPath();
ctx1.strokeStyle = 'black';
x = -x_max;
y = 4*x + 5; // FIRST THING TO CHANGE TO CHANGE EQUATION (MUST USE * FOR MULTIPLICATION)
ctx1.moveTo(offsetX(x), offsetY(y));
while (x < x_max) { // INCLUDE CODE FOR BROKEN LINE IN HERE
x += 0.1;
y = 4*x+5; // SECOND THING TO CHANGE TO CHANGE EQUATION (MUST USE * FOR MULTIPLICATION)
ctx1.lineTo(offsetX(x), offsetY(y));
}
ctx1.stroke();
ctx1.closePath();我希望线性图(我已经计算出轴)以箭头结尾,但我不知道如何做到这一点。我在下面的JsFiddle (http://jsfiddle.net/m1erickson/Sg7EZ/)中找到了下面的代码,但我不知道如何将它合并到我现有的code...or中,如果这确实是我应该如何做的话。
var startRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
startRadians+=((this.x2>this.x1)?-90:90)*Math.PI/180;
this.drawArrowhead(ctx,this.x1,this.y1,startRadians);
// draw the ending arrowhead
var endRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
endRadians+=((this.x2>this.x1)?90:-90)*Math.PI/180;
this.drawArrowhead(ctx,this.x2,this.y2,endRadians);
}
Line.prototype.drawArrowhead=function(ctx,x,y,radians){
ctx.save();
ctx.beginPath();
ctx.translate(x,y);
ctx.rotate(radians);
ctx.moveTo(0,0);
ctx.lineTo(5,20);
ctx.lineTo(-5,20);
ctx.closePath();
ctx.restore();
ctx.fill();
}有没有什么简单的方法可以把线条的端点变成箭头?谢谢!
发布于 2015-12-31 10:56:18
您必须找到(无限)绘制线离开画布(矩形)的任何点。
它可能会在0、1或2点退出画布。如果绘制线从画布矩形的0点或1点退出,则不需要箭头。如果绘制线从画布矩形的两个点退出,则使用箭头小提琴在两个退出点处放置箭头。
要测试出口点,您可以将画布矩形视为构成该矩形的4条线。然后测试绘制线和4条矩形线中的每一条之间的交点。
此脚本返回任意两行的交集:
// Attribution: http://paulbourke.net/geometry/pointlineplane/
// p0 & p1 are points on a first line
// p2 & p3 are points on a second line
// returns the intersection point (or null if the lines don't intersect)
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(null);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return null;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(null);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}查找地图线和4条画布矩形线的任何交点:
var exitTop=line2lineIntersection(
{x:0,y:0}, { x:canvas.width, y:0},
yourLinePoint0, yourLinePoint1
);
var exitRight=line2lineIntersection(
{x:canvas.width,y:0}, { x:canvas.width, y:canvas.height},
yourLinePoint0, yourLinePoint1
);
var exitBottom=line2lineIntersection(
{x:0,y:canvas.height}, { x:canvas.width, y:canvas.height},
yourLinePoint0, yourLinePoint1
);
var exitLeft=line2lineIntersection(
{x:0,y:0}, { x:0, y:canvas.height},
yourLinePoint0, yourLinePoint1
);
var intersections=[];
if(exitTop){ intersections.push(exitTop); }
if(exitRight){ intersections.push(exitRight); }
if(exitBottom){ intersections.push(exitBottom); }
if(exitLeft){ intersections.push(exitLeft); }
if(intersections.length==2){
// feed your 2 exit points into your arrow drawing script
}然后,将两个出口点输入到箭头绘制脚本中:
// create a new line object
var line=new Line(
intersections[0].x, intersections[0].y,
intersections[1].x, intersections[1].y
);
// draw the line
line.drawWithArrowheads(context);示例代码和演示
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function Line(x1,y1,x2,y2){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
}
Line.prototype.drawWithArrowheads=function(){
// arbitrary styling
ctx.strokeStyle="blue";
ctx.fillStyle="blue";
ctx.lineWidth=1;
// draw the line
ctx.beginPath();
ctx.moveTo(this.x1,this.y1);
ctx.lineTo(this.x2,this.y2);
ctx.stroke();
// draw the starting arrowhead
var startRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
startRadians+=((this.x2>this.x1)?-90:90)*Math.PI/180;
this.drawArrowhead(ctx,this.x1,this.y1,startRadians);
// draw the ending arrowhead
var endRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
endRadians+=((this.x2>this.x1)?90:-90)*Math.PI/180;
this.drawArrowhead(ctx,this.x2,this.y2,endRadians);
}
Line.prototype.drawArrowhead=function(ctx,x,y,radians){
ctx.save();
ctx.beginPath();
ctx.translate(x,y);
ctx.rotate(radians);
ctx.moveTo(0,0);
ctx.lineTo(5,20);
ctx.lineTo(-5,20);
ctx.closePath();
ctx.restore();
ctx.fill();
}
////////////////////////////////////
var x0=22.375;
var y0=678.625;
var x1=330.8125;
var y1=-555.125;
var exitTop=line2lineIntersection(
{x:0,y:0}, { x:canvas.width, y:0},
{x:x0,y:y0},{x:x1,y:y1}
);
var exitRight=line2lineIntersection(
{x:canvas.width,y:0}, { x:canvas.width, y:canvas.height},
{x:x0,y:y0},{x:x1,y:y1}
);
var exitBottom=line2lineIntersection(
{x:0,y:canvas.height}, { x:canvas.width, y:canvas.height},
{x:x0,y:y0},{x:x1,y:y1}
);
var exitLeft=line2lineIntersection(
{x:0,y:0}, { x:0, y:canvas.height},
{x:x0,y:y0},{x:x1,y:y1}
);
var intersections=[];
if(exitTop){ intersections.push(exitTop); }
if(exitRight){ intersections.push(exitRight); }
if(exitBottom){ intersections.push(exitBottom); }
if(exitLeft){ intersections.push(exitLeft); }
if(intersections.length==2){
// feed your 2 exit points into your arrow drawing script
for(var i=0;i<intersections.length;i++){
ctx.beginPath();
ctx.arc(intersections[i].x,intersections[i].y,3,0,Math.PI*2);
//ctx.fill();
}
}
// create a new line object
var line=new Line(
intersections[0].x, intersections[0].y,
intersections[1].x, intersections[1].y
);
// draw the line
line.drawWithArrowheads();
// Attribution: http://paulbourke.net/geometry/pointlineplane/
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(null);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return null;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(null);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }<canvas id="canvas" width=300 height=300></canvas>
添加:将答案代码添加到提问者的代码中

/////////////
//
function Line(x1,y1,x2,y2){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
}
Line.prototype.drawWithArrowheads=function(color){
// arbitrary styling
ctx.strokeStyle=color || "black";
ctx.fillStyle=color || "black";
ctx.lineWidth=1;
// draw the line
ctx.beginPath();
ctx.moveTo(this.x1,this.y1);
ctx.lineTo(this.x2,this.y2);
ctx.stroke();
// draw the starting arrowhead
var startRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
startRadians+=((this.x2>this.x1)?-90:90)*Math.PI/180;
this.drawArrowhead(ctx,this.x1,this.y1,startRadians);
// draw the ending arrowhead
var endRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
endRadians+=((this.x2>this.x1)?90:-90)*Math.PI/180;
this.drawArrowhead(ctx,this.x2,this.y2,endRadians);
}
//
Line.prototype.drawArrowhead=function(ctx,x,y,radians){
ctx.save();
ctx.beginPath();
ctx.translate(x,y);
ctx.rotate(radians);
ctx.moveTo(0,0);
ctx.lineTo(5,20);
ctx.lineTo(-5,20);
ctx.closePath();
ctx.restore();
ctx.fill();
}
/////////////
var x_axis = 175;
var y_axis = 175;
var x_max = 7; // THIS CHANGES RANGE OF X-AXIS
var y_max = 7; // THIS CHANGES RANGE OF Y-AXIS
var x_scale = x_axis / (x_max + 1);
var y_scale = y_axis / (y_max + 1);
var x_offset = x_axis + 0.5; // location on canvas
var y_offset = y_axis + 0.5; // of graph's origin
var canvas1 = document.getElementById("plot");
var ctx1 = canvas1.getContext("2d");
var canvas = document.getElementById("axes");
var ctx = canvas.getContext("2d");
canvas.width = canvas1.width = x_axis * 2;
canvas.height = canvas1.height = y_axis * 2;
drawAxes(ctx);
plotline(-x_max,function(x){return(4*x+5);},'purple');
plotline(-x_max,function(x){return(3*x-1);},'blue');
function drawAxes(ctx) {
ctx.font = "20px";
ctx.font = "14px";
ctx.strokeText('Y', x_axis - 25, 10); //CHANGES LABEL OF Y-AXIS
ctx.strokeText('X', x_axis * 2 - 10, y_axis + 20); //CHANGES LABEL OF X-AXIS
ctx.font = "10px sans-serif";
ctx.lineWidth = 1;
// draw x-axis
ctx.beginPath();
ctx.moveTo(0, y_offset);
ctx.lineTo(x_axis*2, y_offset);
ctx.stroke();
ctx.closePath();
// draw arrow
ctx.beginPath();
ctx.moveTo(10 - 8, y_axis+0.5);
ctx.lineTo(10, y_axis+0.5 - 3);
ctx.lineTo(10, y_axis+0.5 + 3);
ctx.stroke();
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(x_axis*2+0.5, y_axis+0.5);
ctx.lineTo(x_axis*2+0.5 - 8, y_axis+0.5 - 3);
ctx.lineTo(x_axis*2+0.5 - 8, y_axis+0.5 + 3);
ctx.stroke();
ctx.closePath();
ctx.fill();
// draw x values
j = -x_max;
while (j <= x_max) {
x = j * x_scale;
ctx.strokeStyle = '#aaa';
ctx.beginPath();
ctx.moveTo(x + x_offset, y_offset);
ctx.lineTo(x + x_offset, y_offset + 10);
ctx.stroke();
ctx.closePath();
ctx.strokeStyle = '#666';
ctx.strokeText(j, x + x_offset - 10, y_offset + 20);
j++;
if (j == 0) { j++; }
}
// draw y-axis
ctx.beginPath();
ctx.moveTo(x_offset, 0);
ctx.lineTo(x_offset, y_axis*2);
ctx.stroke();
ctx.closePath();
// draw arrow
ctx.beginPath();
ctx.moveTo(x_axis+0.5, 0.5);
ctx.lineTo(x_axis+0.5 - 3, 0.5 + 8);
ctx.lineTo(x_axis+0.5 + 3, 0.5 + 8);
ctx.stroke();
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(x_axis+0.5, y_axis*2);
ctx.lineTo(x_axis+0.5 - 3, y_axis*2 -8);
ctx.lineTo(x_axis+0.5 + 3, y_axis*2 - 8);
ctx.stroke();
ctx.closePath();
ctx.fill();
// draw y values
j = -y_max;
while (j <= y_max) {
y = j * y_scale;
ctx.strokeStyle = '#aaa';
ctx.beginPath();
ctx.moveTo(x_offset, y + y_offset);
ctx.lineTo(x_offset - 10, y + y_offset);
ctx.stroke();
ctx.closePath();
ctx.strokeStyle = '#666';
ctx.strokeText(-j, x_offset - 25, y + y_offset + 5);
j++;
if (j == 0) { j++; }
}
}
function offsetX(v) {
return x_offset + (v * x_scale);
}
function offsetY(v) {
return y_offset - (v * y_scale);
}
/////////////////////////
function plotline(x,yFn,strokecolor){
ctx1.font = "10px sans-serif";
ctx1.strokeText(' ', x_axis+50, 50);
ctx1.lineWidth = 1;
ctx1.strokeStyle=strokecolor;
drawLineWithArrowheads(
offsetX(x),
offsetY(yFn(x)),
offsetX(x_max),
offsetY(yFn(x_max)),
strokecolor
);
}
//
function drawLineWithArrowheads(x0,y0,x1,y1,color){
var exitTop=line2lineIntersection(
{x:0,y:0}, { x:canvas.width, y:0},
{x:x0,y:y0},{x:x1,y:y1}
);
var exitRight=line2lineIntersection(
{x:canvas.width,y:0}, { x:canvas.width, y:canvas.height},
{x:x0,y:y0},{x:x1,y:y1}
);
var exitBottom=line2lineIntersection(
{x:0,y:canvas.height}, { x:canvas.width, y:canvas.height},
{x:x0,y:y0},{x:x1,y:y1}
);
var exitLeft=line2lineIntersection(
{x:0,y:0}, { x:0, y:canvas.height},
{x:x0,y:y0},{x:x1,y:y1}
);
//
var intersections=[];
if(exitTop){ intersections.push(exitTop); }
if(exitRight){ intersections.push(exitRight); }
if(exitBottom){ intersections.push(exitBottom); }
if(exitLeft){ intersections.push(exitLeft); }
//
if(intersections.length==2){
// create a new line object
var line=new Line(
intersections[0].x, intersections[0].y,
intersections[1].x, intersections[1].y
);
// draw the line
line.drawWithArrowheads(color);
}
}
// Attribution: http://paulbourke.net/geometry/pointlineplane/
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(null);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return null;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(null);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}body{ background-color: ivory; }
canvas{border:1px solid red; }
canvas{left:0; position: absolute; top: 0; }<div class="relative">
<canvas id="axes"></canvas>
<canvas id="plot"></canvas>
发布于 2015-12-31 10:33:42
该jsFiddle的最后4行显示了用法:
// create a new line object
var line=new Line(50,50,250,275);
// draw the line
line.drawWithArrowheads(context);(但您还需要从jsFiddle顶部定义Line )。
无论如何,代码所做的就是找出直线的角度,然后在这个角度上画一个三角形。
到目前为止,最棘手的一点是找到指向箭头的角度。由于您有一条多点直线,因此您可能只需要使用最后两个点。
https://stackoverflow.com/questions/34539904
复制相似问题