[英]The correct way to graph of a function on html5-canvas
出於自我教育的目的,我試圖在 html5-canvas 上繪制數學函數。
我知道有些圖書館可以做到這一點,但正如我所說:教育目的。
所以問題是:如何繪制函數圖,例如: f(x) = 1/x 或 f(x) = tan(x)
我嘗試這樣做的方式:
如果有人可以:給我一些偽代碼或步驟如何檢測函數在給定點是否連續,然后正確繪制它,我將不勝感激!
PS:在問這個問題之前我已經搜索了很長時間的答案,但我找不到任何答案,如果這個問題是重復的那么我真的很抱歉,請把我鏈接到原始問題。
您需要在邊界處裁剪函數。 當您逐步執行離散步驟時,您將跳過 x 值,其中 y 在頂部和底部被剪裁。
您可以求解 f(x) = graphTop 和 f(x) = graphBottom 或為每個垂直漸近線找到 x,但對於更復雜的函數,這可能變得非常困難。
進行近似的最簡單方法,除非您使用帶有標尺的圖形並從中獲取數據,否則近似與真實情況一樣好。
要做的只是減少循環步驟。 你有 -100 到 100,我猜你是步進 1 個單位。 而不是第 1 步單位步長的 1/10 或更小。 不要繪制每個步驟,只需繪制每個單元。 但是在子步驟中檢查 y 值是否在 y 范圍之外。
從一個子步驟到下一個子步驟,您有多種可能性。
對於 1,2 我們可以在發生這種情況時開始一條新路徑,對於 4 只是正常繪制。
最大的問題是 3,除了消除這種情況發生的可能性之外,真的沒有解決方案。 要做到這一點,您可以減少子步驟,但您永遠無法將它們做得足夠小。 考慮 f(x) = tan(x ^ 2) 來捕獲所有情況 3 需要一個 subStep 以對數方式變小,當您的 CPU 資源有限時,這不是一件好事。 所以我們只能做一個最合適的人。
如果漸近線左側和右側的 y 剪輯在 x 軸(縮放像素)上相距2 / subStepCount
( 2 / subStepCount
請參閱代碼以了解詳細信息)像素,則以下將起作用,但如果它們靠得更近,它將失敗。 要增加子步驟設置var subStepCount = ?
. 我添加了一個檢查,看看最后兩個圖之間的差異是否大於圖高度的 1/3,以捕捉一些不好的圖。
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>
您需要考慮radians
和degrees
之間的差異。 轉換比較簡單:
//instead of y = Math.tan(x) , use :
y = Math.tan(x * Math.PI / 180);
這是一個小提琴。 您可以通過更改xAxisPI
變量以弧度為單位設置x-Axis
的起點/終點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.