zoukankan      html  css  js  c++  java
  • AutoCAD 命令统计魔幻球的实现过程(2)

    第一部分中介绍了如何使用ASP.net Web API和Entity Framework实现服务器端程序,这篇博客将讲述如何使用JQuery从服务器获取数据并利用WebGL/Three.Js来实现浏览器端魔幻球的渲染。

    本文地址:http://www.cnblogs.com/junqilian/archive/2013/03/14/2958698.html

    这部分比较简单,就是一个html页面,为了方便,我就利用服务器端ASP.NET MVC中的view – index.cshtml好了。在这个文件中我要添加一些Javascript代码来以REST的方式从服务器获取数据,然后渲染魔幻球。Web页面中利用JavaScript与服务器进行通信,JQuery是很好的选择,实际上JQuery也已经包含在了ASP.NET MVC里面。对于WebGL的渲染,我选用了一个流行的类库Three.Js。类库和源码都可以从GitHub上下载。 里面包含好多示例,是理解和应用Three.Js很好的学习资料。

    大家也看到了,这个程序的界面非常简单,就是一个下拉框用来选择用户,还有一个div标签作为魔幻球的渲染容器:

    <div id="body">
        <section class="featured">
            <div class="content-wrapper">
                <div>
                    <select id="sel_userName" >
                        <option value="All_Users">Select a User Name</option>
                    </select>
               
                 
    </div>
            </div>

           
       
    </section>
        <section class="content-wrapper main-content clear-fix">
     
           
         
    >
            <div id="Containner" style="height:500px; width:800px;
     
    background-color:black;" ></div>
           

        </section>
       
    </div
    >

    首先在document Ready的时候从服务器请求可用的用户列表。这里我使用JQuery发送Ajax请求到“api/AcadCommands”来获取所有的用户命令统计数据,然后从中选择用户名。当然这样效率是不高的,更好的应该是在服务器端实现一个action只返回可用的用户列表就行了。如果你感兴趣,可以自己实现这部分做练习。

        $(document).ready(function () {
           
    // Send an AJAX request
            $.getJSON("api/AcadCommands/"
    ,
                   
    function
    (data) {
                       
    // On success, 'data' contains a list of UserCommandsHits.
                        $.each(data, function
    (key, val) {
                            $(
    "select"
    ).append(
                               
    '<option value="' + val.UserName + '">'
                                    + val.UserName +
                               
    '</option>');
                        });
                    });
     
            var container = document.getElementById('Containner');
            initThree(container);
    animate();


    });

    在document ready的时候还要初始化ThreeJs,这部分一会儿再说。先说说当用户从下列框中选择一个用户后,我们需要获取指定用户的命令统计信息。使用JQuery发送Ajax请求到 api/AcadCommands?username=" + username:

    代码如下:

            $("#sel_userName").change(this, function () {

               
    var username = $(this).children('option:selected'
    ).val();
                $(
    '#txt_userName'
    ).text = username;

               
    var commandHitDic = new
    Array();

                $.getJSON(
    "api/AcadCommands?username="
    + username,
                       
    function
    (data) {
                           
    var str = data.UserName + ': $'
    + data.CommandHits;
                            cmdHits = data.CommandHits;
     
                           
    //add 3D objects to WebGL scene
                            addObjectsToScene(cmdHits);


                        })
                    .fail(
                       
    function
    (jqXHR, textStatus, err) {
                            alert(err);
                            $(
    '#txt_userName').text('Error: '
    + err);
                        });



            });
    //$("#sel_userName").change

    获取到用户命令统计数据后,就可以用ThreeJs来渲染了,我把这部分放在一个单独的javascript文件中。直接上代码:


    var mouseX = 0, mouseY = 0,



        SEPARATION = 200,
        AMOUNTX = 10,
        AMOUNTY = 10,



        camera, scene, renderer;

    var magicBall = new
    THREE.Object3D();
       

    var targetRotation = 0;
    var
    targetRotationOnMouseDown = 0;

    var mouseX = 0;
    var
    mouseXOnMouseDown = 0;

    ///////////////////////////////
    var MIN_TEXT_FONT_SIZE = 10;
    var
    MAX_TEXT_FONT_SIZE = 80;

    var MIN_LINE_LENGTH = 50;
    var
    MAX_LINE_LENGTH = 450;

    var
    PARTICLE_BALL_RADIUS = 850;

    ///////////////////////////////

    //initThree();
    //animate();


       
    var
    minHitNumber = 0;
       
    var
    maxHitNumber = 0;

       
    function
    computeMinMaxHitNum(cmdHits) {

           
    //get min and max hit number
            for (var i in
    cmdHits) {
               
    var
    hitNum = cmdHits[i].HitNumber;
               
    var
    cmd = cmdHits[i].CommandName;

               
    if
    (hitNum > maxHitNumber) maxHitNumber = hitNum;
               
    if
    (hitNum < minHitNumber) minHitNumber = hitNum;
            }

        }

    function
    getLineLength(hitNumber) {

       
    var
    ratio = (hitNumber - minHitNumber) / (maxHitNumber - minHitNumber);

       
    var
    lineLength = MIN_LINE_LENGTH + ratio * (MAX_LINE_LENGTH - MIN_LINE_LENGTH);

       
    return
    lineLength;

    }

    function
    getTextFontSize(hitNumber) {

       
    var
    ratio = (hitNumber - minHitNumber) / (maxHitNumber - minHitNumber);

       
    var
    textSize = MIN_TEXT_FONT_SIZE + ratio * (MAX_TEXT_FONT_SIZE - MIN_TEXT_FONT_SIZE);

       
    return
    textSize;

    }


    function
    initThree(container) {




       
    var
    separation = 100, amountX = 50, amountY = 50,
                    particles, particle;


        camera =
    new
    THREE.PerspectiveCamera(75,
                container.clientWidth / container.clientHeight, 1, 10000);
        camera.position.z = 1000;

        scene =
    new
    THREE.Scene();

        renderer =
    new
    THREE.CanvasRenderer(); //WebGLRenderer()
        renderer.setSize(container.clientWidth, container.clientHeight);
        container.appendChild(renderer.domElement);

       
    //add particles just for visual effect

       
    var
    PI2 = Math.PI * 2;
       
    var material = new
    THREE.ParticleCanvasMaterial({

            color: 0xffffff,
            program:
    function
    (context) {

                context.beginPath();
                context.arc(0, 0, 1, 0, PI2,
    true
    );
                context.closePath();
                context.fill();

            }

        });

       
    for (var
    i = 0; i < 1000; i++) {

            particle =
    new
    THREE.Particle(material);
            particle.position.x = Math.random() * 2 - 1;
            particle.position.y = Math.random() * 2 - 1;
            particle.position.z = Math.random() * 2 - 1;
            particle.position.normalize();
            particle.position.multiplyScalar(Math.random() * 10 + PARTICLE_BALL_RADIUS);
            scene.add(particle);

        }






        container.addEventListener(
    'mousedown', onContainerMouseDown, false
    );
        container.addEventListener(
    'touchstart', onContainerTouchStart, false
    );
        container.addEventListener(
    'touchmove', onContainerTouchMove, false
    );

      


    }

    function
    addObjectsToScene(cmdHits){

       
    //prepartion
        computeMinMaxHitNum(cmdHits);
       
       
    if
    (magicBall.children.length > 0){
           
           
    var
    obj, i;
           
    for
    ( i = magicBall.children.length - 1; i >= 0 ; i -- ) {
                obj = magicBall.children[ i ];
               
                magicBall.remove(obj);
               
            }

            scene.remove(magicBall);
        }
       
    // add line and text

       
    for (var i in
    cmdHits) {

           
    var
    hitNum = cmdHits[i].HitNumber;
           
    var
    cmdName = cmdHits[i].CommandName;

           
    //draw line and text 3d object
            var
    lineLength = getLineLength(hitNum);
           
    var
    textSize = getTextFontSize(hitNum);

           
    var
    lineAndText = creatLineAndText(lineLength, cmdName, textSize);
            magicBall.add(lineAndText);
        }



        magicBall.rotation.x = 0;
        magicBall.rotation.y = Math.PI * 2;
                               
        scene.add(magicBall);
       
    }

    function
    creatLineAndText(lineLength, textString, textSize) {

       
    var lineAndText = new
    THREE.Object3D();
       
       
    //draw line

       
    var startVector = new THREE.Vector3(0, 0, 0);// always start from center of ball.

       
    var
    endX = Math.random() * 2 - 1;
       
    var
    endY = Math.random() * 2 - 1;
       
    var
    endZ = Math.random() * 2 - 1;
       
    var endVector = new
    THREE.Vector3(endX, endY, endZ);
        endVector = endVector.normalize();
        endVector.multiplyScalar(lineLength);

       
    var geomLine = new
    THREE.Geometry();
        geomLine.vertices.push(startVector);
        geomLine.vertices.push(endVector);

       
    var line = new THREE.Line(geomLine, new
    THREE.LineBasicMaterial(
                { color: Math.random() * 0xffffff, opacity: 0.5 }));

        lineAndText.add(line);

       
    //draw text
       
           
    //inline function
            function
    creatTextAt(textPosition, textString, textSize) {

               
    var text3d = new
    THREE.TextGeometry(textString, {

                    size: textSize,
                    height: 5,
    //thickness of the text
                    curveSegments: 2,
                    font:
    "helvetiker"

                });

                text3d.computeBoundingBox();
               
    var
    centerOffset = -0.5 * (text3d.boundingBox.max.x - text3d.boundingBox.min.x);

               
    var textMaterial = new
    THREE.MeshBasicMaterial(
                    { color: Math.random() * 0xffffff,
                        overdraw:
    true
    });
                text =
    new
    THREE.Mesh(text3d, textMaterial);

                text.position.x = textPosition.x + centerOffset;
                text.position.y = textPosition.y;
                text.position.z = textPosition.z;
                               

                       

               
    return
    text;
            };

       
    var
    text3D = creatTextAt(endVector, textString, textSize);
        lineAndText.add(text3D);

       

       
    return
    lineAndText;
    }





    function
    onContainerMouseDown(event) {
       
        event.preventDefault();

       
    var
    container = event.srcElement;
       
        container.addEventListener(
    'mousemove', onContainerMouseMove, false
    );
        container.addEventListener(
    'mouseup', onContainerMouseUp, false
    );
        container.addEventListener(
    'mouseout', onContainerMouseOut, false
    );

       
    var
    windowHalfX = container.clientWidth / 2;
       
        mouseXOnMouseDown = event.clientX - windowHalfX;
        targetRotationOnMouseDown = targetRotation;

    }

    function
    onContainerMouseMove(event) {

       
    var
    container = event.srcElement;
       
    var
    windowHalfX = container.clientWidth / 2;

        mouseX = event.clientX - windowHalfX;

        targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;

    }

    function
    onContainerMouseUp(event) {

       
    var
    container = event.srcElement;

        container.removeEventListener(
    'mousemove', onContainerMouseMove, false
    );
        container.removeEventListener(
    'mouseup', onContainerMouseUp, false
    );
        container.removeEventListener(
    'mouseout', onContainerMouseOut, false
    );

    }

    function
    onContainerMouseOut(event) {

       
    var
    container = event.srcElement;

        container.removeEventListener(
    'mousemove', onContainerMouseMove, false
    );
        container.removeEventListener(
    'mouseup', onContainerMouseUp, false
    );
        container.removeEventListener(
    'mouseout', onContainerMouseOut, false
    );

    }

    function
    onContainerTouchStart(event) {

       
    if
    (event.touches.length == 1) {

            event.preventDefault();

           
    var
    container = event.srcElement;
           
    var
    windowHalfX = container.clientWidth / 2;
       
            mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
            targetRotationOnMouseDown = targetRotation;

        }

    }

    function
    onContainerTouchMove(event) {

       
    if
    (event.touches.length == 1) {

            event.preventDefault();

           
    var
    container = event.srcElement;
           
    var
    windowHalfX = container.clientWidth / 2;
           
            mouseX = event.touches[0].pageX - windowHalfX;
            targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;

        }

    }

    //

    function
    animate() {

        requestAnimationFrame(animate);

        render();

    }

    function
    render() {

        camera.position.x += (mouseX - camera.position.x) * .05;
        camera.position.y += (-mouseY + 200 - camera.position.y) * .05;
        camera.lookAt(scene.position);


       
    //self rotate
        magicBall.rotation.y += ( targetRotation - magicBall.rotation.y ) * 0.05;
       
    //magicBall.rotation.y += 0.05;
        renderer.render(scene, camera);

    }

    好了,到目前为止已经完成了,最后给大家提一下用到的JavaScript文件,注意这个 helvetiker_regular.typeface.js 因为我要把命令名字渲染成文本,使用了 helvetiker_regular字体,所以需要这个文件。这个文件可以在ThreeJS的下载包中找到。

    <script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
    <script type="text/javascript" src="../../Scripts/Three/three.js"></script>
    <
    script type="text/javascript" src="../../Scripts/Three/Detector.js"></script
    >
    <
    script type="text/javascript" src="../../Scripts/Three/fonts/helvetiker_regular.typeface.js"></script
    >
    <
    script type="text/javascript" src="../../Scripts/ACV_MagicBall.js"></script
    >

    好了,打完收工。不过到目前为止,这个程序还是运行在本机的一个aspnet站点,下一步就是把他搬到windows Azure云端去了。下回再说。

  • 相关阅读:
    JS-记住用户名【cookie封装引申】
    JS-cookie封装
    JS-比较函数中嵌套函数,可以排序【对象数组】
    JS-随机div颜色
    JS-过滤敏感词【RegExp】
    JS-提取字符串—>>普通方法VS正则表达式
    CSS- ie6,ie7,ie8 兼容性写法,CSS hack写法
    JS-【同页面多次调用】轮播特效封装-json传多个参数
    JS-【同页面多次调用】tab选项卡封装
    Redis主从同步
  • 原文地址:https://www.cnblogs.com/junqilian/p/2958698.html
Copyright © 2011-2022 走看看