优化3D世界Javascript动画

时间:2010-04-20 22:11:30

标签: javascript optimization animation 3d

我最近提出了创建像地球一样的动画标签云的想法。我从ngdc.noaa.gov中提取了海岸线坐标,并编写了一个在我的浏览器中显示它的小脚本。现在你可以想象,整个海岸线由大约48919个点组成,我的脚本将单独渲染(每个坐标由一个跨度表示)。显然没有浏览器能够流畅地呈现这一点 - 但是如果我可以在旧的p4 2.8 Ghz(作为代表性基准)上渲染尽可能多的200跨度(现在的两倍),那就太好了。我是否可以使用javascript优化来加快这些跨度的显示?

一个'坐标':

<div id="world_pixels">
<span id="wp_0" style="position:fixed; top:0px; left:0px; z-index:1; font-size:20px; cursor:pointer;cursor:hand;" onmouseover="magnify_world_pixel('wp_0');" onmouseout="shrink_world_pixel('wp_0');" onClick="set_askcue_bar('', 'new york')">new york</span>
</div>

剧本:

$(document).ready(function(){

        world_pixels = $("#world_pixels span");

        world_pixels.spin();

        setInterval("world_pixels.spin()",1500);

});


z = new Array();

$.fn.spin = function () {

    for(i=0; i<this.length; i++) {

            /*actual screen coordinates: x/y/z --> left/font-size/top
                  300/13/0  300/6/300
                         | /
                         |/
            0/13/300 ----|----  600/13/300
                        /|
                       / |
              300/20/300    300/13/600
            */

            /*scale font size*/
        var resize_x = 1;
            /*scale width*/
        var resize_y = 2.5;
            /*scale height*/
        var resize_z = 2.5;

        var from_left = 300;
        var from_top = 20;

            /*actual math coordinates:

                        1  -1
                         | /
                         |/
                  1  ----|---- -1
                        /|
                       / |
                      1  -1 
            */

         //var get_element = document.getElementById();
         //var font_size = parseInt(this.style.fontSize);
         var font_size = parseInt($(this[i]).css("font-size"));

         var left = parseInt($(this[i]).css("left"));




         if (coast_line_array[i][1]) {

         } else {

            var top = parseInt($(this[i]).css("top"));

            z[i] = from_top + (top - (300 * resize_z)) / (300 * resize_z);
            //global beacause it's used in other functions later on 

            var top_new = from_top + Math.round(Math.cos(coast_line_array[i][2]/90*Math.PI) * (300 * resize_z) + (300 * resize_z));

            $(this[i]).css("top", top_new);

            coast_line_array[i][3] = 1;

         }


         var x = resize_x * (font_size - 13) / 7;

         var y = from_left + (left- (300 * resize_y)) / (300 * resize_y);




         if (y >= 0) {

             this[i].phi = Math.acos(x/(Math.sqrt(x^2 + y^2)));

         } else {

             this[i].phi = 2*Math.PI - Math.acos(x/(Math.sqrt(x^2 + y^2)));
             i
         }

         this[i].theta = Math.acos(z[i]/Math.sqrt(x^2 + y^2 + z[i]^2));

         var font_size_new = resize_x * Math.round(Math.sin(coast_line_array[i][4]/90*Math.PI) * Math.cos(coast_line_array[i][0]/180*Math.PI) * 7 + 13);

         var left_new = from_left + Math.round(Math.sin(coast_line_array[i][5]/90*Math.PI) * Math.sin(coast_line_array[i][0]/180*Math.PI) * (300 * resize_y) + (300 * resize_y));



         //coast_line_array[i][6] = coast_line_array[i][7]+1;

         if ((coast_line_array[i][0] + 1) > 180) {

            coast_line_array[i][0] = -180;

         } else {

            coast_line_array[i][0] = coast_line_array[i][0] + 0.25;

         }

         $(this[i]).css("font-size", font_size_new);

         $(this[i]).css("left", left_new);




    }

}

resize_x = 1;

function magnify_world_pixel(element) {

    $("#"+element).animate({
        fontSize: resize_x*30+"px"
                    }, {
        duration: 1000  
                    });

}

function shrink_world_pixel(element) {

    $("#"+element).animate({
        fontSize: resize_x*6+"px"
                    }, {
        duration: 1000  
                    });



}

我很欣赏任何优化我的脚本的建议,也许甚至有一个完全不同的方法来解决这个问题。 我的页面上提供了存储所有坐标数组的整个.js文件,该文件大约为2.9 MB,因此您可以考虑将.zip拉为本地测试:

metaroulette.com/files/31218.zip

metaroulette.com/files/31218.js

P.S。我用来创建跨度的php:

<?php

                //$arbitrary_characters = array('a','b','c','ddsfsdfsdf','e','f','g','h','isdfsdffd','j','k','l','mfdgcvbcvbs','n','o','p','q','r','s','t','uasdfsdf','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9',);
                $arbitrary_characters = array('cat','table','cool','deloitte','askcue','what','more','less','adjective','nice','clinton','mars','jupiter','testversion','beta','hilarious','lolcatz','funny','obama','president','nice','what','misplaced','category','people','religion','global','skyscraper','new york','dubai','helsinki','volcano','iceland','peter','telephone','internet', 'dialer', 'cord', 'movie', 'party', 'chris', 'guitar', 'bentley', 'ford', 'ferrari', 'etc', 'de facto');


                    for ($i=0; $i<96; $i++) {

                        $arb_digits = rand (0,45);

                        $arbitrary_character = $arbitrary_characters[$arb_digits];
                        //$arbitrary_character = ".";

                        echo "<span id=\"wp_$i\" style=\"position:fixed; top:0px; left:0px; z-index:1; font-size:20px; cursor:pointer;cursor:hand;\" onmouseover=\"magnify_world_pixel('wp_$i');\" onmouseout=\"shrink_world_pixel('wp_$i');\" onClick=\"set_askcue_bar('', '$arbitrary_character')\">$arbitrary_character</span>\n";

                    }

                ?>

2 个答案:

答案 0 :(得分:1)

您可以随时使用<canvas> element。它会在支持它的浏览器上更快地呈现更多

但是,在版本9发布之前,您必须使用Internet Explorer的解决方法。您可以使用ExplorerCanvas来模拟IE的画布支持。但是,只知道它非常慢 - 甚至可能比你的算法慢。如果IE支持对您很重要,您可以要求用户安装Google Chrome Frame,如果他们想要在使用Internet Explorer浏览器时获得更好的体验;但除此之外,你无法在IE中加快这种速度。

答案 1 :(得分:1)

我看到一个简单的优化:

for(i=0;i<this.length; i++) {

每次循环迭代时,都在检查this.length。这是昂贵的,除非你期望改变长度,否则不必要。

尝试:

for(i=0,ii=this.length;i<ii; i++) {

代替。

我在JS中没有做太多关键的工作,所以我只能提供一些初步的建议。

您可以将一些繁重的计算移动到WebWorker,但我不确定您的情况是否会从中获益很多。

在这里查看:https://developer.mozilla.org/En/Using_web_workers

此外,如果您没有对阵列使用任何Array对象的函数,请尝试使用带有整数“keys”的对象。

我从来没有亲自完成对象与数组查找的基准测试,但我有朋友坚持认为在某些情况下对象速度要快得多(尽管理论上它们应该具有可比性)。

这是一个非常快速简单的代码模型,为什么不尝试呢?