admin管理员组文章数量:1426957
For self-educational purposes I'm trying to graph math functions on html5-canvas.
I know that there are libraries that can do exactly that, but as I said: educational purpose.
So the question is: how do I draw a graph of a function for example : f(x) = 1/x or f(x) = tan(x)
The way I tried to do it:
- loop from (for ex. x = -100 to x == 100)
- calculate value at x
- draw a line from (x, valueAtX) to (x+1, valueAtX_plus1)
Result:
What I want:
If someone could: give me some pseudocode or steps how to detect if function is continuous at a given point, and then correctly draw it I would appreciate it a lot!
P.S: I've searched for answer for a long time before asking this question, but I couldn't find any, if this question is a duplicate then I'm really sorry, and please link me to the original.
For self-educational purposes I'm trying to graph math functions on html5-canvas.
I know that there are libraries that can do exactly that, but as I said: educational purpose.
So the question is: how do I draw a graph of a function for example : f(x) = 1/x or f(x) = tan(x)
The way I tried to do it:
- loop from (for ex. x = -100 to x == 100)
- calculate value at x
- draw a line from (x, valueAtX) to (x+1, valueAtX_plus1)
Result:
What I want:
If someone could: give me some pseudocode or steps how to detect if function is continuous at a given point, and then correctly draw it I would appreciate it a lot!
P.S: I've searched for answer for a long time before asking this question, but I couldn't find any, if this question is a duplicate then I'm really sorry, and please link me to the original.
Share Improve this question asked Apr 13, 2017 at 9:39 Tomasz RadwaskiTomasz Radwaski 1922 silver badges10 bronze badges 6- This is cool - a very well asked question so +1 for that. To make life even easier, could you perhaps provide a fiddle of what you're doing so that we can interact with your code? – Frits Commented Apr 13, 2017 at 9:41
- My code is a plete spaghetti + I'm relatively new to the site, I don't know how to add fiddles and such. But I'll try explain everything I can – Tomasz Radwaski Commented Apr 13, 2017 at 9:49
- I did put it on free hosting, so you can check it out here: ensigntrojan.cba.pl/wykresTest.html – Tomasz Radwaski Commented Apr 13, 2017 at 9:58
- 1 It should normally not happen that for a "sensible" function the value difference is larger than 100 times the x difference. If you detect such a jump, leave out the line for that segment. – Lutz Lehmann Commented Apr 13, 2017 at 12:48
-
@LutzL, actually, in this case, that is exactly what should happen. The value of
tan(x)
jumps from negative infinity to positive infinity around those points. – Ozan Commented Apr 13, 2017 at 13:46
2 Answers
Reset to default 4Dealing with vertical asymptotes.
You need to clip the function at the boundaries. As you are stepping in discrete steps you will skip over the x value where y is clipped at the top and the bottom.
You could solve for f(x) = graphTop and f(x) = graphBottom or find x for each vertical asymptote, but that can bee very difficult for more plex functions.
The easiest way it to do a approximation, unless you are using the graph with a rulers and getting data from it the approximation is as good as the real thing.
To do just reduce the loop step. You had -100 to 100 and I presume you are stepping 1 unit. Rather than step 1 unit step 1/10th or smaller. Don't plot each step, just plot the each unit. But in the sub steps check if the y value is outside the y range.
You have several possibilities from one sub step to the next.
- Y moving from inside to outside plot
- y moving from outside to inside plot
- y moved from outside to outside across plot
- y moved from inside to inside
For 1,2 we can begin a new path when that happens, for 4 just plot as normal.
The big problem is 3 and there really is no solution apart from eliminating the chance of that happening. To do that you reduce the sub steps, but you can never make them small enough. Consider f(x) = tan(x ^ 2) to catch all case 3's would need a subStep that gets smaller logarithmically, not a good thing when you have a finite CPU resource. So we are left but to do a best fit.
The following will work if the y clip to the left and right of the asymptotes are around 2/10th (2 / subStepCount
see code for details) pixel apart in the x axis (scaled pixel) but if they get closer it will fail. To increase the sub steps set var subStepCount = ?
. I added a check to see if the difference between the last two plots is greater than 1/3 of the plots height to catch some of the bad plots.
var ctx = canvas.getContext("2d");
var h = canvas.height;
var w = canvas.width;
var cw = w / 2; // centers
var ch = h / 2;
var subStepCount = 10; // number of sub setps
var scale = 10; // scale of the plot
function plot(func,col,lineWidth){
var invScale = 1 / scale; // inverted scale is the size of a pixel
var top = ch * invScale; // get top and bottom
var bottom = -ch * invScale;
var subStep = invScale / subStepCount; // get the sub steps between pixels
var x,y,yy,xx,subX; // xx,yy are the coords of prev point
var start = (-cw - 1) * invScale; // get the start and end
var end = (cw + 1) * invScale;
// set render styles
ctx.strokeStyle = col;
ctx.lineWidth = lineWidth * invScale; // scale line to be constant size
ctx.beginPath();
for(x = start; x < end; x += invScale){ // pixel steps
for(subX = 0; subX < invScale; subX += subStep){ // sub steps
y = func(x+subX); // get y for x
if(yy !== undefined){ // is this not the first point
if(y > top || y < bottom){ // this y outside ?
if(yy < top && yy > bottom){ // last yy inside?
ctx.lineTo(x + subX,y);
}
} else { // this y must be inside
if(yy > top || yy < bottom){ // was last yy outside
ctx.moveTo(xx,yy); // start a new path
}
if(subX === 0){ // are we at a pixel
if(y > bottom && y < top){ // are we inside
// if the step is large then might be a line break
if(Math.abs(yy-y) > (top - bottom) * (1/3)){
ctx.moveTo(x,y);
}else{
ctx.lineTo(x,y);
}
}
}
}
}else{
if(subX === 0){
ctx.moveTo(x,y);
}
}
yy = y;
xx = x+ subX;
}
}
ctx.stroke();
}
// set the plot scale and orientation
ctx.setTransform(scale,0,0,-scale,cw, ch);
// two example function plots
plot((x)=>Math.tan(Math.cos(x/2) * 10),"#F88",1)
plot((x)=>Math.tan(x),"blue",2)
canvas {
border : 1px solid black;
}
<canvas id=canvas width = 512 height = 256></canvas>
You need to consider the difference between radians
and degrees
. Conversion is relatively simple:
//instead of y = Math.tan(x) , use :
y = Math.tan(x * Math.PI / 180);
Here is a fiddle. You can set the starting/ending point of the x-Axis
in radians by changing the xAxisPI
variable.
本文标签: javascriptThe correct way to graph of a function on html5canvasStack Overflow
版权声明:本文标题:javascript - The correct way to graph of a function on html5-canvas - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745459918a2659276.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论