zoukankan      html  css  js  c++  java
  • 【转】JavaScript 3D图表

    文章系本人原创,转载请保持完整性并注明出自《四火的唠叨》

    在说3D图表以前,首先要明确两个概念,一个是数据的维度,一个是呈现数据载体的维度。对于数据的维度,一维的数据呈现,但是呈现的载体是二维的平面图,比如饼图:

    JavaScript 3D图表

    已经能够很清晰地观察到数据的分布情况。数据如果增加一个维度,变成二维,呈现载体依然是二维的平面图:

    JavaScript 3D图表

    数据表达依然是清晰的。但是,倘若再增加一维,这个时候就面临了两个问题:

    1. 数据的维度增加,复杂性也增大了; 
    2. 计算机发展到现在,绝大多数情况下数据载体依然是二维的平面图,如何展示三维的数据呢?

    这两个问题中,第一个问题从本质上说,无法解决。数据的维度越大,理解起来理所当然地,也越来越困难。

    但是第二个问题,我们至少有两种解决办法。一种,在当前二维图表的基础上,通过颜色、图形、数值的不同等等,来表示第三个维度的数据。例如,利用颜色不同来表示第三个维度的热图:

    JavaScript 3D图表

    在两个维度经度和维度的情况下,第三个维度温度通过颜色的不同来展示了。

    另一种,就是绘制3D的图形,把第三个维度展示出来。需要注意的是,绘制3D的图形仅仅是技术上的一种呈现形式,并不意味着它的易懂性要好于上面一种方式。实际上,我们还是需要看看具体的问题是什么。

    明确了这些概念以后,我再来介绍两则JavaScript的3D图表,它们都是为了呈现三维的数据,而不仅仅是看起来3D而已,大部分JavaScript的3D图表库都是基于Canvas的,如果你对Canvas不了解请移步参阅这篇文章;其中一些则是支持WebGL的。WebGL是一种3D的绘图标准,有了它,JavaScript就可以实现OpenGL标准能做的事情了,在HTML5 Canvas基础上,WebGL允许硬件3D加速。

    webgl-surface-plot

    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即可。

    文章系本人原创,转载请保持完整性并注明出自《四火的唠叨》

    博客地址: http://www.cnblogs.com/dwf07223,本文以学习、研究和分享为主,欢迎转载,转载请务必保留此出处。若本博文中有不妥或者错误处请不吝赐教。

  • 相关阅读:
    无线鼠标换电池了
    Jython Interactive Servlet Console YOU WILL NEVER KNOW IT EXECLLENT!!! GOOD
    Accessing Jython from Java Without Using jythonc
    jython podcast cool isnt't it?
    Python里pycurl使用记录
    Creating an Interactive JRuby Console for the Eclipse Environment
    微软为AJAX和jQuery类库提供CDN服务
    Download A File Using Cygwin and cURL
    What is JMRI?这个是做什么用的,我真没看懂但看着又很强大
    用curl 发送指定的大cookie的http/https request
  • 原文地址:https://www.cnblogs.com/dwf07223/p/3284872.html
Copyright © 2011-2022 走看看