2012-09-09 29 views
2

我對複雜功能繪圖儀有以下代碼。它創建複數函數f(z)= z *(z + 5)(z-v)的相位圖,其中v是鼠標指向的位置。正如你所看到的,它非常緩慢。有什麼辦法可以加快速度並獲得流暢的動畫效果嗎?只要把我指向正確的方向將是有益的。加速我的複雜功能繪圖儀(canvas + javascript)

<html> 
<head> 
<script type="text/javascript" src="jquery-1.8.1.js"></script> 
<script type="application/javascript"> 
function draw() { 
var canvas = document.getElementById("canvas"); 
var ctx;// = canvas.getContext("2d"); 

//The following functions convert pixel Xs and Ys to real and imaginary 
//parts of a complex number, and back again 
var pixToReal = function(n){return n/15.0-10.0}; 
var pixToImag = function(n){return - n/15.0+10} 
var realToPix = function(x){return Math.round((x+10.0)*15)} 
var imagToPix = function(y){return Math.round((-y+10.0)*15)} 

//Storing the complex number a+bi as [a,b], the following functions add, 
//multiply, and find the modulus of the complex number 
var add = function(z1,z2){return [z1[0]+z2[0],z1[1] + z2[1]]} 
var mult = function(z1,z2){return [z1[0]*z2[0]-z1[1]*z2[1],z1[0]*z2[1]+z1[1]*z2[0]]} 
var modulus = function(z){ 
    if (z[1]>0){return Math.atan2(z[1],z[0])} 
    else {return Math.atan2(z[1],z[0])+2*Math.PI} 
    }; 

//Takes a complex number and returns the RGB value of the corresponding 
//point on the color wheel. 
var complexToRGB = function(z){ 
var theta = modulus(z)%(2*Math.PI) 
var Hp = (theta/(2*Math.PI))*6 
var X = Math.abs(Math.round((1 - Math.abs(Hp%2 -1))*255)) 
var C = "rgb(0,0,0)" 
if (Hp>=0 && Hp<1){ 
    C = "rgb("+255+","+X+",0)" 
    }; 
if (1<=Hp && Hp<2){ 
    C = "rgb("+X+","+255+",0)"} 
if (2<=Hp && Hp<3){ 
    C = "rgb("+0+","+255+","+X+")"} 
if (3<=Hp && Hp<4){ 
    C = "rgb("+0+","+X+","+255+")"} 
if (4<=Hp && Hp<5){ 
    C = "rgb("+X+","+0+","+255+")"} 
if (5<=Hp && Hp<6){ 
    C = "rgb("+255+","+0+","+X+")"} 
return C 

} 

//a complex number 
var v = [0,4] 

//the function f(z) = z*(z+5)*(z+v) 
var f = function(z){return mult(add(mult(z,z),mult([5,5],z)),add(z,v))} 

//makes v the opposite complex number your mouse is pointing at, 
//i.e. your mouse points at a root of f 
function onMouseMove(evt) { 
v = [-pixToReal(evt.pageX), -pixToImag(evt.pageY)]; 
} 

$(document).mousemove(onMouseMove); 

makeFrame = function(){ 
ctx.clearRect(0,0,300,300); 
for (var n =0;n<300;n++){ 
    for (var m=0;m<300;m++){ 
     var x = pixToReal(n) 
     var y = pixToImag(m) 
     var z = [x,y] 
     var w = f(z) 
     ctx.fillStyle = complexToRGB(w) 
     ctx.fillRect(n,m,1,1) 
     } 
     } 
    } 

function animate() { 
ctx = canvas.getContext("2d"); 
return setInterval(makeFrame, 1); 
} 

animate(); 

} 
</script> 
</head> 
<body onload="draw()"> 
    <canvas id="canvas" width="300" height="300"></canvas> 
</body> 

回答

3

我已經取得了一些快速的優化,其加速大約500%。我認爲你可以進一步加快速度,但這需要更多的工作。

我所做的是:

  • 而不是設置使用填充樣式和fillRect的像素值的,所有像素值被作爲陣列(的imageData),然後makeFrame(檢索)操縱的imageData數組,然後使用putImageData()一次設置所有像素。
  • 以上更改要求complexToRGB()使用紅色,綠色和藍色顏色值而不是字符串回退數組。
  • 在complexToRGB()函數中,if-cases的列表已被更改爲if-else的鏈(由於不會評估真實條件之後的條件,所以速度更快)。
  • 將setInterval從1000 fps更改爲25.算法無法跟上該幀速率,因此最好將其設置爲更實際的幀速率。

Here's the code as a jsFiddle

下一步:我也想嘗試刪除儘可能多的函數調用成爲可能,比如內聯pixToReal()和pixToImag()公式內的循環:

for (var m = 0; m < 300; m++) { 
    var x = n/15.0 - 10.0; 
    var y = -m/15.0 + 10; 

,然後優化代碼在complexToRGB()中,並考慮對該函數執行相同的操作以刪除該函數調用。

+0

太棒了,謝謝。我對編程非常陌生,以前沒有必要考慮性能問題。偉大的事情要考慮。 –

+0

我只注意到函數f()多次調用mult()和add()。雖然它創建了很好的可讀代碼,但您可以獲得大量的函數調用。考慮重寫f()以不進行任何函數調用。另外,maenu建議的requestAnimationFrame是個好主意。 – Strille

+0

我最終希望能夠讓用戶添加額外的零(或極點),然後能夠拖動它們。所以我覺得這個功能很難「硬編碼」。這絕對讓我有很多想法。只是我應該避免函數調用的想法是新的。 –

3

我做了一個小提琴here,使用​​和繪圖ImageData。工作得很好,也許你可以用我的方法合併我的。