【轉】JavaScript 3D圖表

文章系本人原創,轉載請保持完整性並註明出自《四火的嘮叨》html

在說3D圖表之前,首先要明確兩個概念,一個是數據的維度,一個是呈現數據載體的維度。對於數據的維度,一維的數據呈現,可是呈現的載體是二維的平面圖,好比餅圖:web

JavaScript 3D圖表

已經可以很清晰地觀察到數據的分佈狀況。數據若是增長一個維度,變成二維,呈現載體依然是二維的平面圖:canvas

JavaScript 3D圖表

數據表達依然是清晰的。可是,假若再增長一維,這個時候就面臨了兩個問題:瀏覽器

  1. 數據的維度增長,複雜性也增大了; 
  2. 計算機發展到如今,絕大多數狀況下數據載體依然是二維的平面圖,如何展現三維的數據呢?

這兩個問題中,第一個問題從本質上說,沒法解決。數據的維度越大,理解起來理所固然地,也愈來愈困難。svn

可是第二個問題,咱們至少有兩種解決辦法。一種,在當前二維圖表的基礎上,經過顏色、圖形、數值的不一樣等等,來表示第三個維度的數據。例如,利用顏色不一樣來表示第三個維度的熱圖:webgl

JavaScript 3D圖表

在兩個維度經度和維度的狀況下,第三個維度溫度經過顏色的不一樣來展現了。google

另外一種,就是繪製3D的圖形,把第三個維度展現出來。須要注意的是,繪製3D的圖形僅僅是技術上的一種呈現形式,並不意味着它的易懂性要好於上面一種方式。實際上,咱們仍是須要看看具體的問題是什麼。lua

明確了這些概念之後,我再來介紹兩則JavaScript的3D圖表,它們都是爲了呈現三維的數據,而不單單是看起來3D而已,大部分JavaScript的3D圖表庫都是基於Canvas的,若是你對Canvas不瞭解請移步參閱這篇文章;其中一些則是支持WebGL的。WebGL是一種3D的繪圖標準,有了它,JavaScript就能夠實現OpenGL標準能作的事情了,在HTML5 Canvas基礎上,WebGL容許硬件3D加速。spa

webgl-surface-plot.net

JavaScript 3D圖表

 

主頁點此。特性列表:

  • 純JavaScript實現,不須要Flash; 
  • 鼠標左鍵拖拽能夠翻轉圖像; 
  • 按住Shift鍵能夠縮放; 
  • Web GL不可用的時候,能夠直接使用Canvas繪製; 
  • 自定義座標軸名稱; 
  • 自定義顏色梯度和漸變; 
  • 包裝爲Google Visualization API的一部分。

在IE下,藉助excanvas能夠在VML下獲得同樣的效果。

對於這個例子,簡單過一下重點代碼,首先這部分是着色器的代碼(片斷着色器和頂點着色器),包括座標軸和紋理:

<script id="shader-fs" type="x-shader/x-fragment">    
    #ifdef GL_ES    precision highp float;    
    #endif    varying vec4 vColor;    
    varying vec3 vLightWeighting;    
    void main(void)    {    
        gl_FragColor = vec4(vColor.rgb * vLightWeighting, vColor.a);    
    }
</script>

<script id="shader-vs" type="x-shader/x-vertex">    
    attribute vec3 aVertexPosition;    
    attribute vec3 aVertexNormal;   
    attribute vec4 aVertexColor;    
    uniform mat4 uMVMatrix;   
    uniform mat4 uPMatrix;    
    uniform mat3 uNMatrix;    
    varying vec4 vColor;    
    uniform vec3 uAmbientColor;    
    uniform vec3 uLightingDirection;    
    uniform vec3 uDirectionalColor;    
    varying vec3 vLightWeighting;    
    void main(void)    {    
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);    
        vec3 transformedNormal = uNMatrix * aVertexNormal;    
        float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);    
        vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;    
        vColor = aVertexColor;    
    }
</script>

<script id="axes-shader-fs" type="x-shader/x-fragment">    
    precision mediump float;    
    varying vec4 vColor;    void main(void)    {    
        gl_FragColor = vColor;    
    }
</script>

<script id="axes-shader-vs" type="x-shader/x-vertex">    
    attribute vec3 aVertexPosition;    
    attribute vec4 aVertexColor;    
    uniform mat4 uMVMatrix;    
    uniform mat4 uPMatrix;    
    varying vec4 vColor;    
    uniform vec3 uAxesColour;    
    void main(void)    {    
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);    
        vColor =  vec4(uAxesColour, 1.0);    
    }
</script>

<script id="texture-shader-fs" type="x-shader/x-fragment">    
    #ifdef GL_ES   
    precision highp float;    
    #endif    
    varying vec2 vTextureCoord;    
    uniform sampler2D uSampler;    
    void main(void)    {    
        gl_FragColor = texture2D(uSampler, vTextureCoord);    
    }
</script>

<script id="texture-shader-vs" type="x-shader/x-vertex">    
    attribute vec3 aVertexPosition;    
    attribute vec2 aTextureCoord;    
    varying vec2 vTextureCoord;    
    uniform mat4 uMVMatrix;    
    uniform mat4 uPMatrix;    
    void main(void)    {    
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);    
        vTextureCoord = aTextureCoord;    
    }
</script>

這個方法用於保持兩圖步調一致:

function coordinateCharts(){   
     // Link the two charts for rotation.         
    plot1 = surfacePlot.getChart();    
    plot2 = surfacePlot2.getChart();         
    if (!plot1 || !plot2)         
        return;         
    plot1.otherPlots = [plot2];    
    plot2.otherPlots = [plot1];
}

每發生變化須要重繪的時候,調用:

surfacePlot.draw(data, options, basicPlotOptions, glOptions);
surfacePlot2.draw(data2, options, basicPlotOptions2, glOptions2);

Demoparse主要用來根據用戶輸入的公式f(x,y)計算z的值:

function Demoparse(ID_result, ID_code, valueArray, toolTips){    
    var el, expr;    
    el = document.getElementById(ID_result);    
    expr = document.getElementById(ID_code).value;    
    expr = Parser.parse(expr);    
    var result;    
    var idx = 0;    
    var d = 360 / numRows;         
    for (var x = 0; x < numRows; x++) {             
        valueArray[x] = new Array();                 
        for (var y = 0; y < numCols; y++) {                    
            result = expr.simplify({                
                x: x * d,                
                y: y * d            
            });                         
            result = result.evaluate();                         
            valueArray[x][y] = result / 4.0 + 0.25;                         
            toolTips[idx] = "x:" + x + ", y:" + y + " = " + result;            
            idx++;                     
        }             
    }     
}

Canvas 3D Graph

相比前者,Canvas 3D Graph真是太簡單了,若是你須要這種風格的柱狀圖:

JavaScript 3D圖表

demo的代碼很是簡單:

//Initialise Graph  
var g = new canvasGraph('graph');             

//define some data  gData=new Array();             
gData[0]={x:500,y:500,z:500};  
gData[1]={x:500,y:400,z:600};  
gData[2]={x:500,y:300,z:700};  
gData[3]={x:500,y:200,z:800};  
gData[4]={x:500,y:100,z:900};   

// sort data - draw farest elements first         
gData.sort(sortNumByZ);            

 //draw graph   
g.drawGraph(gData);

PS:若是你遇到沒法顯示WebGL圖形的問題——它不只對瀏覽器,還對硬件有要求。若是你使用Opera瀏覽器,在地址欄輸入about:gpu,以查看你的顯卡是否被支持。若是是FireFox,地址欄輸入about:config,尋找webgl.force-enabled,雙擊,將該值改成true便可。

文章系本人原創,轉載請保持完整性並註明出自《四火的嘮叨》

相關文章
相關標籤/搜索