我有一个在坐标网格上绘制线性图的函数,如下面的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/)中找到了下面的代码,但是我无法弄清楚如何将它合并到我现有的代码中......或者如果这确实是我应该怎么做的。
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();
}
是否有某种简单的方法将线的端点转换为箭头?谢谢!
答案 0 :(得分:1)
您必须找到(无限)绘图线退出画布的任何点(矩形)。
它可能会在0,1或2点退出画布。如果绘图线在0或1点退出画布矩形,则不需要箭头。如果绘图线在2点退出画布矩形,则使用箭头小提琴在两个出口点放置箭头。
要测试出口点,您可以将画布矩形视为形成矩形的4条线。然后测试绘图线和4个矩形线中的每一个之间的交点。
此脚本返回2行的任意交集:
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
}
查找绘图线和4个画布矩形线的任何交点:
// 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);
然后将2个退出点输入箭头绘图脚本:
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; }
&#13;
<canvas id="canvas" width=300 height=300></canvas>
&#13;
/////////////
//
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)
});
}
&#13;
[添加:将答案代码添加到提问者的代码中]
body{ background-color: ivory; }
canvas{border:1px solid red; }
canvas{left:0; position: absolute; top: 0; }
&#13;
<div class="relative">
<canvas id="axes"></canvas>
<canvas id="plot"></canvas>
&#13;
//set up your Bitmap and WritableBitmap as you see fit
Bitmap colorBitmap = new Bitmap(..);
WriteableBitmap colorWB = new WriteableBitmap(..);
//choose appropriate bytes as per your pixel format, I'll cheat here an just pick 4
int bytesPerPixel = 4;
//rectangles will be used to identify what bits change
Rectangle colorBitmapRectangle = new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height);
Int32Rect colorBitmapInt32Rect = new Int32Rect(0, 0, colorWB.PixelWidth, colorWB.PixelHeight);
&#13;
答案 1 :(得分:0)
jsFiddle的最后4行显示用法:
// create a new line object
var line=new Line(50,50,250,275);
// draw the line
line.drawWithArrowheads(context);
(但您还需要jsFiddle顶部的Line
定义。)
无论如何,代码所做的是弄清线条前进的角度,然后在该角度绘制一个三角形。
到目前为止最棘手的一点是找到定向箭头的角度。 由于你有一个多点线,大概你只能使用最后两点。