Оптимизация 3D мира анимации Javascript - PullRequest
2 голосов
/ 21 апреля 2010

Недавно у меня возникла идея создать облако тегов, похожее на анимацию в форме земли.Я извлек координаты береговой линии из ngdc.noaa.gov и написал небольшой скрипт, который отображал его в моем браузере.Теперь, как вы можете себе представить, вся береговая линия состоит из примерно 48919 точек, которые мой скрипт будет отображать отдельно (каждая координата представлена ​​одним пролетом).Очевидно, что ни один браузер не способен отображать это бегло, но было бы неплохо, если бы я мог отображать столько, сколько, скажем, 200 интервалов (в два раза больше, чем сейчас) на моем старом p4 2,8 ГГц (в качестве репрезентативного теста).Могу ли я использовать какие-либо оптимизации 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 МБ, поэтому вы можете рассмотреть возможность использования ZIP-файла для локального тестирования:

metaroulette.com/files/31218.zip

metaroulette.com / files / 31218.js

PS 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 ]

1 голос
/ 21 апреля 2010

Ну, я вижу одну простую оптимизацию:

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 для массива, попробуйте вместо этого использовать объект с целочисленными «ключами».

Я никогда лично не проводил тесты для поиска объектов и массивов, но у меня есть друзья, которые настаивают на том, что в некоторых случаях объекты работают намного быстрее (хотя теоретически они должны быть сопоставимы).

Это очень быстрый и простой мод вашего кода, так почему бы не попробовать его?

1 голос
/ 21 апреля 2010

Вы всегда можете использовать элемент <canvas> . Он отображает намного быстрее в браузерах, которые его поддерживают.

Вам придется использовать обходной путь для Internet Explorer, пока не выйдет версия 9. Вы можете использовать ExplorerCanvas для эмуляции поддержки холста для IE. Однако просто знайте, что это очень медленно - возможно, даже медленнее, чем ваш алгоритм. Если поддержка IE важна для вас, вы можете попросить пользователей установить Google Chrome Frame , если они хотят получить лучший опыт при использовании браузера Internet Explorer; но кроме этого, вы не можете многое сделать, чтобы ускорить подобные вещи в IE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...