voliuf.narod.ru

главная

друзья

помощь сайту

Flash MX Studio

Бесплатные учебники по темам

Партнерская программа

1.Представление сайта

2.Форматирование текста

3.Рисование API

4.Компоненты

5.Движемся дальше

6.Интерфейсы AсtionScript

7.Обнаружение коллизий

8.Математика и физика Flash

9.Анимация и интерактивность Drawing API

10.Реализация 3D-графики с помощью рисования API

11.Изучение SphereCage

12.Сайты с мультимедийным содержимым

13.Видеоданные

14.Аудио

15.Интеграция динамических данных

16.Динамический Flash: PHP

17.XML

18.Flash, ColdFusion и Remoting


 


Flash MX Studio
5.Движемся дальше
  
 
Внимание! Для работы с этой лекцией необходимы учебные файлы, которые Вы можете загрузить  здесь.

В этой лекции мы рассмотрим еще один интерфейс просмотра изображений. Мы научимся отображать динамическую загрузку изображений, а также сохранять список изображений отдельно от фильма Flash, чтобы изменять сайт без повторного открытия FLA.

 

Для динамической загрузки рисунков потребуется создать предзагрузчик. Мы разберемся в том, как обрабатывать рисунки различных размеров, как расширить прототип slideTo, созданный ранее, чтобы изменять размер области просмотра. Мы также научимся применять объект Stage для управления интерфейсом и использовать общие объекты так, чтобы интерфейс мог хранить имена файлов рисунков для загрузки за определенный промежуток времени, а затем создадим интерфейс просмотра фотографий.

 

Объект Stage

Объект Stage является одним из наиболее мощных дополнений во Flash MX. Он позволяет нам получать доступ к пространству вокруг рабочего места, превращать его в окно браузера или самостоятельного проигрывателя, устанавливать его разрешение и использовать его пространство. Мы можем присваивать события для реакции на любое изменение в доступном месте и соответствующим образом переорганизовывать элементы. Для использования объекта Stage необходимо настроить HTML определенным образом. Как правило, при публикации фильма есть две возможности.

 

Согласно первой из них, фильм Flash отображается в реальном размере, и размер определяется разрешением фильма, образуя четкую границу на странице HTML. Для установки этого режима откройте диалоговое окно Publish Settings (File > Publish Settings) и выберите вкладку HTML. Установите в ниспадающем меню Dimensions значение Match Movie и в меню Scale значение Default (Show All).

 

 


 

 

Вторая возможность - растянуть фильм Flash так, чтобы он заполнял все доступное место. Для этого установите Dimensions на 100%, оставив для режима Scale установки по умолчанию.

 

 


 

 

Изменение размера рабочего места с помощью объекта Stage

Flash MX имеет еще одну возможность настройки параметров публикации Publishing Settings, которая разрешает пользователю настраивать размер браузера или окна проигрывателя Flash, причем объекты на рабочем месте будут также изменять свои размеры. Разберем, как реализовать эту возможность.

 
  1. Откройте новый фильм Flash с разрешением по умолчанию (550x400) и в диалоговом окне Publish Settings установите Dimensions на 100% и режим Scale на значение No Scale.
  2. Теперь нарисуйте что-нибудь вне рабочего места, т.е. в рабочей области.

     


     

     

    Открыв фильм в браузере или во Flash Player, вы увидите, что можно просматривать не только область на рабочем месте, но и определенную часть содержимого рабочей области, в зависимости от размеров окна вашего браузера.

     

    Так настраивается HTML, чтобы использовать объект Stage.

     

    Теперь посмотрим, как можно использовать это дополнительное пространство. Объект Stage довольно примитивен с точки зрения доступных в нем параметров и методов. Мы имеем доступ к ширине и высоте рабочего места, а также можем присваивать "приемники" для получения уведомлений об изменении размера рабочего места. Очень важно понимать, что Stage.Width и Stage.Height не ссылаются на разрешение, установленное нами для фильма, а связаны с доступным нам актуальным размером: размером отдельного окна Player или размером окна браузера. Сама по себе эта информация бесполезна, если не знать, какого размера было наше рабочее место.

     
  3. Чтобы узнать эти данные, нужно временно переключить режим размера рабочего места на значение showAll. В этом режиме разрешение рабочего места будет таким, какое указано в диалоговом окне Properties. Удалите все с рабочего места фильма, который мы только что создали, и введите следующий код в новый слой scripts.
        fscommand("allowscale", "false");
        // switch to showAll mode
        Stage.scaleMode = "showAll";
        Stage.originalWidth = Stage.Width;
        Stage.originalHeight = Stage.Height;
        // switch back to noScale
        Stage.scaleMode = "noScale"

    Мы только что добавили два дополнительных параметра в объект Stage: originalWidth и originalHeight. Мы также добавили команду allowscale = false, чтобы фильм не растягивался в режиме предварительного просмотра.

     

    Когда вокруг фильма имеется дополнительное место, координаты левого верхнего угла больше не равны (0,0). Теперь исходная область (рабочее место) нашего фильма сохраняет начальные координаты и находится в середине кадра, а координаты дополнительного места вокруг него связаны с ними. На следующем рисунке это показано графически.

     

     


     

     

    Серая область является рабочим местом размером 550x400 пикселей, с соответствующими координатами каждого из углов. Больший прямоугольник вокруг границы этой области представляет собой окно, в котором находится фильм, имеющее в данный момент размер 750x500 пикселей. Это на 200 пикселей шире нашего исходного фильма, и на 100 пикселей выше. Дополнительные пиксели добавляются равномерно на каждой стороне рабочего места, поэтому левый край видимой области находится на -100 (0-100) , правый край на 650 (550+100), верхний край на -50 (0-50) и нижний край на 450 (400+50).

     

    Именно эти границы важны, если мы собираемся располагать фильмы относительно них, поэтому мы сейчас напишем несколько новых методов объекта Stage, чтобы возвращать эти значения. Прежде всего, разберемся, как будут проходить вычисления значений.

     
    • Левый край: 0 минус половина Stage.Width минус исходная ширина.
    • Верхний край: 0 минус половина Stage.Height минус исходная высота.
    • Правый край: исходная ширина плюс половина Stage.Width минус исходная ширина.
    • Нижний край: исходная высота плюс половина Stage.Height минус исходная высота.
     
 
  1. Теперь реализуем это в виде ActionScript.
        //define methods to retrieve boundaries
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth)/2;
        };
        Stage.getTop = function() {
            return -1*(this.height-this.originalHeight)/2;
        };
        Stage.getRight = function() {
            return this.originalWidth+(this.width-this.originalWidth)/2;
        };
        Stage.getBottom = function() {
            return this.originalHeight+(this.height-this.originalHeight)/2;
        };
  2. Создадим несколько фильмов для использования этих значений. Будем использовать четыре скобки в качестве углов изображения для каждого из углов рабочего места. Мы назовем их tl, tr, br и bl, и рисунки каждого из них будут размером 50х50 пикселей с точкой закрепления в левом верхнем углу. Фильмы скобок доступны в исходных файлах на компакт-диске.
  3. Перетащите четыре объекта на рабочее место, назовите инстансы именами tl, tr, br и bl с помощью Property inspector, и расположите каждый из них в соответствующих углах рабочего места. Мы также ввели некоторый текст в центре рабочего места для обозначения середины фильма. Ваше рабочее место теперь будет выглядеть примерно так.

     


     

     

    Чтобы перемещать эти фильмы на свои места при изменении размеров рабочего места, нужно создать для них приемники. Объект Stage имеет список объектов и/или фильмов, которые зарегистрированы вместе с ним для получения уведомления о том, что размер рабочего места изменен. Каждый раз при изменении рабочего места объект Stage будет вызывать событие onResize во всех объектах, которые с ним зарегистрированы. Сначала нужно зарегистрировать наши фильмы с объектом Stage и затем создать для каждого из них метод onResize для расположения их на нужных местах.

     
  4. Для добавления приемников вызовем метод addListener объекта Stage и передадим ему имена фильмов в качестве параметров. Добавьте следующий код в имеющийся ActionScript.
        // register four movie clips to receive notification of onResize
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);
  5. Далее нужно создать методы onResize. Учтите, что точки регистрации (закрепления) наших фильмов могут находиться не на той стороне, поэтому правый нижний фильм, например, нам нужно расположить по правому краю минус его ширина и по нижнему краю минус его высота.
        // top left
        tl.onResize = function() {
            this._x = Stage.getLeft();
            this._y = Stage.getTop();
        };
        // top right
        tr.onResize = function() {
            this._x = Stage.getRight()-this._width;
            this._y = Stage.getTop();
        };
        // bottom left
        bl.onResize = f unction() {
            this._x = Stage.getLeft();
            this._y = Stage.getBottom()-this._height;
        };
        // bottom right
        br.onResize = function() {
            this._x = Stage.getRight()-this._width;
            this._y = Stage.getBottom()-this._height;
        };

    Итак, получаем следующий код.

     
        fscommand("allowscale", "false") ;
        Stage. scaleMode="showAll";
        Stage.originalWidth = Stage.Width;
        Stage.originalHeight = Stage.Height;
        Stage.scaleMode="noScale"
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth)/2;
        };
        Stage.getTop = function() {
            return -1*(this.height-this.originalHeight)/2;
        };
        Stage. getRight = function() {
            return this.originalWidth+(this.width-this.originalWidth)/2;
        };
        Stage.getBottom = function() {
            return this.originalHeight+(this.height-this.originalHeight)/2;
        };
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);
        // top left
        tl.onResize = function() {
            this._x = Stage.getLeft();
            this._y = Stage.getTop();
        };
        // top right
        tr.onResize = function() {
            this._x = Stage.getRight()-this._width;
            this._y = Stage.getTop();
        };
        // bottom left
        bl.onResize = function() {
            this._x = Stage.getLeft();
            this._y = Stage.getBottorn()-this._height;
        };
        // bottom right
        br.onResize = function() {
            this._x = Stage.getRight()-this._width;
            this._y = Stage.getBottom()-this._height;
        };

    Пример 5.1.

  6. Сохраните ваш фильм в файле stageObject.fla. Запустив его, вы увидите, что фильмы располагаются в нужных углах, как и предполагалось. Полученный результат лучше наблюдать в отдельном окне проигрывателя, нежели в браузере, так как вокруг фильма Flash в браузере будет немного лишнего пространства.

     


     

     

     


     

     
     

    Все работает как нужно, но не оптимально. Каждый раз, когда надо найти левую координату рабочего места, мы вызываем функцию Stage.getLeft, тогда как это значение изменяется только при изменении размера рабочего места.

     

Более эффективное изменение размера

Намного проще иметь дело со статическими значениями, вычисляемыми только при изменении размера рабочего места. Это удобнее всего реализовать внутри самого объекта Stage, поэтому мы будем устанавливать параметры Stage.left, Stage.top, Stage.right и Stage.bottom каждый раз при изменении его размеров. Согласно словарю ActionScript, объект Stage имеет строенный управляющий элемент, которому можно присваивать функцию. К сожалению, этот способ не работает, и единственный способ заставить его работать - это добавить объект Stage самому себе в качестве приемника (это подход может показаться странным, но он имеет положительный результат).

 

Итак, для функции Stage.onResize есть код (он приведен ниже), вызывающий каждую из четырех функций get и помещающий результаты в параметры внутри объекта Stage.

 
  1. Добавьте следующий код над функциями get.
        Stage.onResize = function() {
            this.left = this.getLeft();
            this.top = this.getTop();
            this.right = this.getRight();
            this.bottom = this.getBottom();
        };
  2. В процессе работы мы внесем значительные изменения в функцию get. Так как мы сначала вычисляем левую верхнюю позицию, мы можем приравнять правую позицию к левой плюс ширина и нижнюю к верхней плюс высота.
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth)/2;
        };
        Stage.getTop = function() {
            return -1* (this.height-this.original-Height) /2;
        };
        Stage.getRight = function() {
            return this.left+this.width;
        };
        Stage.getBottom = function() {
            return this.top+this.height;
        };
  3. Затем добавляем приемник рабочего места.
        Stage.addListener(Stage);
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);

    Имейте в виду, что приемники принимают событие изменения размера в том порядке, в котором они добавлены, поэтому, в данном случае, Stage стоит на первом месте, затем идут tl, tr, bl и, наконец, br. Здесь это важно, так как нам нужно быть уверенными в том, что значения для левой, правой и т.д позиций, устанавливаются перед обращением к ним из фильмов.

     
  4. Теперь нам нужно пересоздать функции onResize фильма для использования новых значений.
        // top left
        tl.onResize = function() {
            this._x = Stage.left;
            this._y = Stage.top;
        };
        // top right
        tr.onResize = function() {
            this._x = Stage.right-this._width;
            this._y = Stage.top;
        };
        // bottom left
        bl.onResize = function() {
            this._x = Stage.left;
            this._y = Stage.bottom-this._height;
        };
        // bottom right
        br.onResize = function() {
            this._x = Stage.right-this._width;
            this._y = Stage.bottom-this._height;
        };
  5. Сохраните фильм в файле stageObject2.fla. Приведем полный код, функционирующий более "аккуратно".
        fscommand("allowscale", "false");
        Stage.scaleMode="showAll";
        Stage.originalWidth = Stage.Width;
        Stage.originalHeight = Stage.Height;
        Stage.scaleMode="noScale";
        Stage.onResize = function() {
            this.left = this.getLeft();
            this.top = this.getTop();
            this.right = this.getRight();
            this.bottom = this.getBottom();
        };
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth) /2;
        };
        Stage.getTop = function() {
            return -1* (this.height-this.original-Height) /2;
        };
        Stage.getRight = function() {
            return this.left+this.width;
        };
        Stage. getBottom = function() {
            return this.top+this.height;
        };
        Stage.addListener(Stage);
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);
        // top left
        tl.onResize = function() {
            this._x = Stage.left;
            this._y = Stage.top;
        };
        // top right
        tr.onResize = function() {
            this._x = Stage.right-this._width;
            this._y = Stage.top;
        };
        // bottom left
        bl.onResize = function() {
            this._x = Stage.left;
            this._y = Stage.bottom-this._height;
        };
        // bottom right
        br.onResize = function() {
            this._x = Stage.right-this._width;
            this._y = Stage.bottom-this._height;
        };

    Пример 5.2.

 

Добавление движения при изменении размера рабочего места

Сейчас мы продемонстрируем, как можно добавить движение на примере скольжения уголков на свои места. Для этого нам понадобится скопировать созданную нами в лекции 1 функцию slideTo.

 
  1. Добавьте следующий код над функциями onResize.
        MovieClip.prototype.slideTo = function(x, y, speed, callbackObj, callbackFunc) {
            var noo
            if (this.slideControl) {
                noo = this.slideControl;
            } else {
                noo = this.createEmptyMovieClip(<slideControl>,this.depth++);
            }
            noo.tx = x;
            noo.ty = y;
            noo.speed = speed;
            // store callback object / method (not used yet)
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnterFrame = function() {
                this._parent._x += (this.tx-this._parent._x)/this.speed;
                this._parent._y += (this.ty-this._parent._y)/this.speed;
                if (Math.abs(this.tx-this._parent._x)<0.2 && Math.abs(this.ty
                Кthis._parent ._y) <0.2) {
                    this._parent._x = this.tx;
                    this._parent._y = this.ty;
                    // execute callback (we're not using this yet)
                    this.callBackObj [this.calIBackFunc](this._parent);
                    this.removeMovieClip();
                }
            };
        };

    Пример 5.3.

  2. Измените вызовы onResize, чтобы вызывать функцию slideTo со значениями X и Y в качестве конечных точек скольжения.
        tl.onResize = function() {
            var x = Stage.left;
            var у = Stage.top;
            this.slideTo(x, y, 5);
        }
        tr.onResize = function() {
            var x = Stage.right-this._width;
            var у = Stage.top;
            this.slideTo(x, y, 5);
        };
        bl.onResize = function() {
            var x = Stage.left;
            var у = Stage.bottom-this._height;
            this.slideTo(x, y, 5);
        };
        br.onResize = function() {
            var x = Stage.right-this ._width;
            var у = Stage.bottom-this._height;
            this.slideTo(x, y, 5);
        };
  3. Сохраните фильм в файле stageObject3.fla. При его запуске вы увидите, что углы постепенно появляются и скользят на свои позиции каждый раз при изменении размеров окна браузера или проигрывателя Flash. Приведем конечный код программы.
        fscommand("allowscale", "false");
        Stage.scaleMode="showAll";
        Stage.originalWidth = Stage.Width;
        Stage.originalHeight = Stage.Height;
        Stage.scaleMode="noScale";
        Stage.onResize = function() {
            this.left = this.getLeft();
            this.top = this.getTop();
            this.right = this.getRight();
            this.bottom = this.getBottom();
        };
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth)/2;
        };
        Stage.get Top = function() {
            return -1*(this.height-this.originalHeight)/2;
        };
        Stage.getRight = function() {
            return this.left+this.width;
        };
        Stage.getBottom = function() {
            return this.top+this.height;
        };
        Stage.addListener(Stage);
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);
        MovieClip.prototype.slideTo = function(x, y, speed, callbackObj, callbackFunc) {
            var noo
            if (this.slideControl) {
                noo = this.slideControl;
            } else {
                noo = this.createEmptyMovieClip("slideControl",this.depth++);
            }
            noo.tx = x;
            noo.ty = y;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.calIBackFunc = callBackFunc;
            noo.onEnterFrame = function() {
                this._parent._x += (this.tx-this._parent._x)/this.speed;
                this._parent._y += (this.ty-this._parent._y)/this.speed;
                if (Math.abs(this.tx-this._parent._x)<0.2 &&Math.abs(this.ty
                Кthis._parent._y)<0.2) {
                    this._parent._x = this.tx;
                    this._parent._y = this.ty;
                    this.calIBackObj [this.calIBackFunc](this._parent);
                    this.removeMovieClip();
                }
            };
        };
        tl.onResize = function() {
            var x = Stage.left;
            var у = Stage.top;
            this.slideTo(x, y, 5);
        };
        tr.onResize = function() {
            var x = Stage.right-this._width;
            var у = Stage.top;
            this.slideTo(x, y, 5);
        };
        bl.onResize = function() {
            var x = Stage.left;
            var у = Stage.bottom-this._height;
            this.slideTo(x, y, 5);
        };
        br.onResize = function() {
            var x = Stage.right-this._width;
            var у = Stage.bottom-this._height;
            this.slideTo(x, y, 5);
        };

    Пример 5.4.

    Если использовать этот подход к изменению размеров рабочего места, то Flash Player придется выполнять гораздо больший объем кода. Если в проекте много движущихся объектов, в особенности с эффектами прозрачности, Flash Player может "тормозить", поэтому подумайте, стоит ли его использовать.

     
 

Изменение размеров объекта

Метод slideTo перемещает объект из одного места в другое. Теперь мы немного изменим метод slideTo для создания метода scaleTo, который будем применять с объектом Stage для создания фоновой панели изменяемого размера, которая будет изменяться с увеличением или уменьшением фильма и находиться по центру под названием.

 
  1. Откройте файл stageObject3.fla и сохраните его в файле resize001.fla. Теперь нарисуйте серый квадрат размером 100х100 пикселей и преобразуйте его в фильм с центральной точкой регистрации (закрепления).
  2. Удалите новый фильм с рабочего места, но перетащите его инстанс на новый слой с именем background panel, который размещается под слоем, содержащим заголовок "center stage".
  3. С помощью Property inspector назовите инстанс фильма именем bg и измените его размер так, чтобы он был размером 500 пикселей в ширину и 350 в высоту. С помощью панели Align расположите фильм по центру по горизонтали и по вертикали, нажав соответствующие кнопки при выделенной кнопке To Stage. Ваше рабочее место и временная диаграмма будут выглядеть так.

     


     

     
  4. Создадим код, который будет сохранять постоянное расстояние от фильма до края в 25 пикселей, независимо от размера фильма. Прежде всего, нужно изменить размер. Добавьте в фильм приемник под другими приемниками.
    Stage.addListener(bg);
  5. Затем добавьте в фильм приемник onResize под другими приемниками onResize. После этого сохраните фильм и запустите его.
        bg.onResize = function() {
            this._xscale = Stage.width-50;
            this._yscale = Stage.height-50;
        };
 

Анимация изменения размеров

Все работает корректно. Уголки скользят на свои места, и было бы неплохо, чтобы фон так же постепенно изменял размер. Мы реализуем это в нашем следующем шаге. Сохраните фильм в файле resize002.fla.

 
  1. Создадим метод scaleTo, заменив _xscale и _yscale на _x и _y в методе slideTo. Введите следующий код под функцией slideTo.
      MovieClip.prototype.scaleTo = function
        (xsc, ysc, speed,callbackObj, callbackFunc) {
          var noo;
          if (this.scaleControl) {
              noo = this.scaleControl;
          } else {
              noo = this.createEmptyMovieClip
               ("scaleControl", this. depth++);
          }
          noo.txsc = xsc;
          noo.tysc = ysc;
          noo.speed = speed;
          noo.callBackObj = callBackObj;
          noo.calIBackFunc = callBackFunc;
          noo.onEnterFrame = function() {
              this._parent._xscale +=
               (this.txsc-this._parent._xscale)/this, speed;
              this._parent._yscale +=
                (this.tysc-this._parent._yscale)/this .speed;
              if (Math.abs(this.txsc-this._parent._xscale)<0.2 &&
              КMath.abs(this.tysc-this._parent._yscale)<0.2) {
              this._parent._xscale = this.tx;
              this._parent._yscale = this.ty;
              //execute callback (not used yet)
              this.callBackObj [this.callBackFunc](this._parent);
              this.removeMovieClip();
              }
          };
      };
  2. Эта конструкция работает так же, как и slideTo, но размер объекта может изменяться. Теперь мы просто изменим функцию onResize для вызова этого метода, с передачей ей конечных значений.
        bg.onResize = function() {
            var xsc = Stage.width-50;
            var ysc = Stage.height-50;
            this.scaleTo(xsc, ysc, 5);
        };
  3. При проверке в браузере вы увидите, что серый фон постепенно изменяет размер во время увеличения или уменьшения окна браузера.

    Все работает прекрасно, но необходимость применять различные методы для изменения различных параметров раздражает. Для изменения интенсивности придется добавить еще один метод, и т.д. Изменять набор значений внутри фильма на набор конечных значений было бы лучше с помощью одного метода.

     
 

Использование простого метода изменения параметров

На самом деле это можно сделать, передав методу объект с набором всех значений, которые мы хотим изменить. После этого нужно организовать цикл для каждого значения и постепенно приближать соответствующее значение к значению в конечном объекте. Когда значения приблизятся друг к другу, значение фильма переключится на конечное значение, и затем это значение удалится из объекта targets. Для перемещения объекта к точке нужно передать объект примерно так:

 
    var obj = {_x:50, _y:100};
    this.tweenTo (obj, 5);

Начало метода будет таким же, как в случае с методом slideTo, т.е. будет создаваться управляющий фильм, если такового еще не существует, и затем внутри него будут устанавливаться значения.

 
  1. Замените предыдущие функции slideTo и scaleTo следующим кодом.
    MovieClip.prototype.tweenTo = function(targetsObj, speed,
    КcallbackObj, callbackFunc) {
    var noo;
        if (this.tweenControl) {
            noo = this.tweenControl;
         }   else   {
        noo = this.createEmptyMovieClip("tweenControl", this.depth++);
        }
        // store the object containing target properties and values
        noo.targetsObj = targetsObj;
         noo.speed = speed;
         noo.callBackObj = callBackObj;
         noo.callBackFunc = callBackFunc;
         noo.onEnterFrame = function() {
         var count;
         // as its an object we can't check length.
         }
    }
  2. Затем нужно настроить цикл на прохождение и изменение всех значений. Для итерации через значения в объекте мы используем цикл for:in следующим образом.
        for (var prop in this.targetsObj) {
            this._parent[prop]+=(this.targetsObj
             [prop]this._parent[prop] )/this, speed;
        }

    По мере работы цикла, prop будет обращаться к имени каждого параметра, и в следующей строке кода мы получим очередное значение этого параметра в фильме, приближающееся к значению в параметре объекта targets.

     
  3. Если фильм достиг конечного параметра, нужно переключить его на этот конечный параметр и затем удалить его из объекта targets. Новый код выделен жирным шрифтом.
        for (var prop in this.targetsObj) {
            this._parent[prop] += (this.targetsObj
             [prop] this ._parent[prop]) /this.speed;
            // if property has reached target value
            if (Math.abs(this.targetsObj[prop]-
             this._parent[prop])<0.4) {
                this._parent[prop] = this.targetsObj[prop];
                delete this.targetsObj[prop];
            }
        }
  4. Добавим проверку того, является ли объект targets пустым. В отличие от объекта массива, объект класса не имеет параметра длины, поэтому нам нужно знать, сколько параметров пройдено циклом. Так как параметр каждого фильма достигает соответствующего конечного параметра, конечный параметр удаляется из targetsObj. Когда все параметры фильма достигают конечных параметров, в targetsObj не останется параметров, и значением count будет ноль вследствие отсутствия параметров для обработки циклом. Когда count равен нулю, мы можем уничтожить управляющий фильм и вызвать функцию обратной связи.
        MovieClip.prototype.tweenTo = function
           (targetsObj, speed, callbackObj, calIbackFunc) {
            var noo;
            if (this.tweenControl) {
                noo = this.tweenControl;
            } else {
                noo = this.createEmptyMovieClip
                 ("tweenControl", this.depth++);
            }
            noo.targetsObj = targetsObj;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnterFrame = function() {
                var count;
                // as it's an object we can't check length.
                for (var prop in this. targetsObj) {
                    this._parent[prop] += (this.targetsObj[prop] -
                    Кthis._parent [prop]) /this.speed;
                    if (Math.abs (this.targetsObj
                      [prop] this._parent [prop])<0.4) {
                        this._parent[prop] = this.targetsObj[prop];
                        delete this.targetsObj[prop];
                    }
                    count++;
                }
            if (!count) {
                this.callBackObj[this.calIBackFunc](this._parent);
                this.removeMovieClip();
                }
            };
        };

    Пример 5.5.

  5. Для применения этого метода управления движением нужно изменить приемники onResize. Вот один из них для правого угла, влияющий на _x и _y.
        br.onResize = function() {
            // define targets
            var obj = (_x:Stage.right-this._width,
               _y:Stage.bottom this ._height};
            this.tweenTo(obj, 5);
        };
            :а вот фоновый приемник, влияющий на
              значения _xscale и _yscale.
        bg.onResize = function() {
            var obj = (_xscale:Stage.width-50, _yscale:Stage.height-50};
            this.tweenTo(obj, 5);
        };

    Ниже приведен целиком код, в котором также были изменены функции onResize.

     
        fscommand("allowscale", "false");
        Stage.scaleMode="showAll";
        Stage.originalWidth = Stage.Width;
        Stage.originalHeight = Stage.Height;
        Stage.scaleMode="noScale";
        Stage.onResize = function() {
            this.left = this.getLeft();
            this.top = this.getTop();
            this.right = this.getRight();
            this.bottom = this.getBottom();
        };
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth)/2;
        };
        Stage.getTop = function() {
            return -1* (this.height-this.originalHeight)/2;
        };
        Stage.getRight = function() {
            return this.left+this.width;
        };
        Stage.getBottom = function() {
            return this.top+this.height;
        };
        Stage.addListener(Stage);
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);
        Stage.addListener(bg);
        MovieClip.prototype.tweenTo = function(targetsObj, speed, callbackObj, callbackFunc) {
            var noo;
            if (this.tweenControl) {
                noo = this.tweenControl;
            } else {
                noo = this.createEmptyMovieClip("tweenControl",this.depth++);
            }
            noo.targetsObj = targetsObj;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnterFrame = function() {
                var count;
                // as its an object we can't check length,
                for (var prop in this.targetsObj) {
                    this._parent[prop] += (this.targetsObj[prop]- this._parent [prop] ) /
                    Кthis. speed;
                    if (Math.abs(this.targetsObj [prop]- this._parent[prop])<0.4) {
                            this._parent [prop] = this.targetsObj[prop];
                            delete this.targetsObj [prop];
                    }
                    count++;
                }
                if (! count) {
                    this.callBackObj [this.callBackFunc](this._parent);
                    this.removeMovieClip();
                }
            };
        };
        tl.onResize = function() {
            var obj = (_x:Stage.left, _y:Stage.top};
            this.tweenTo(obj, 5);
        };
        tr.onResize = function() {
            var obj = (_x:Stage.right-this._width, _y:Stage.top};
            this.tweenTo(obj, 5);
        };
        bl.onResize = function() {
            var obj = (_x:Stage.left, _y:Stage.bottom-this._height};
            this.tweenTo(ob j, 5);
        };
        br.onResize = function() {
            var obj = (_x:Stage.right-this._width, _y:Stage.bottom thi s._height};
            this.tweenTo(obj, 5);
        };
        bg.onResize = function() {
            var obj = (_xscale:Stage.width-50, _yscale:Stage.height-50};
            thi s.tweenTo(obj, 5);
        };

    Пример 5.6.

  6. Сохраните фильм в файле resize003.fla и запустите его. Он работает точно так же, как и в предыдущем файле, но его код более компактен.

    Можно сделать еще больше - например, поставить интенсивность фона в зависимость от размера рабочего места.

     
        bg.onResize = function() {
            var obj = {_alpha:100*
              (Stage.Width/Stage.originalWidth),
            К_xscale:Stage.width-50, _yscale:Stage.height-50};
            this.tweenTo(obj, 5);
        };

    Эффект будет лучше заметен, если изменять цвет квадрата в фильме с серого на красный или синий. Если вы сделаете рабочее место совсем небольшим, фон практически полностью исчезнет (resize004.fla).

     

    Нужно иметь в виду, что вместо создания tweenTo в виде метода объекта MovieClip можно было бы создать отдельный класс tween, унаследовав его из класса MovieClip. Это удобно, если большое количество фильмов требует доступ к этим методам. Реализовать это можно так.

     
        function tweenable() {
        }
        tweenable.prototype = new Movieclip();
        Object.registerClass("tweenableMc", tweenable);
        tweenable.tweenTo = function() {
            var noo;
            if (this.tweenControl) {
                noo = this.tweenControl;
            } else {
                noo = this.createEmptyMovieClip("tweenControl", this.depth++);
            }
            noo.targetsObj = targetsObj;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnter Frame = function() {
                var count;
                // as it's an object we can't check length,
                for (var prop in this.targetsObj) {
                    this._parent [prop] += (this.targetsObj [prop]
                    Кthis._parent [prop] ) /this. speed;
                    if (Math.abs (this.targetsObj [prop] this._parent [prop] ) <0.4) {
                        this._parent[prop] = this.targetsObj [prop];
                        delete this.targetsObj [prop];
                    }
                    count++;
                }
                if (!count) {
                    this.callBackObj [this.callBackFunc](this._parent);
                    this.removeMovieClip();
                }
            };
        };

    Пример 5.7.

    Можно использовать Object.registerClass для связывания любого отдельного символа фильма с данным классом. Тогда вы могли бы добавить дополнительные методы к этому классу для добавления параметров к tween.

     
    tweenable.prototype.addToTween = function(obj) {
        //loop through and add properties to targetsObj
        for (var prop in obj) {
          this.tweenControl.targetsObj [prop] = obj [prop];
       }
    };

    Также можно присвоить каждому параметру свою скорость, свои обратные связи для использования по достижении цели, или передавать аргумент с именем параметра и достигнутым значением. Все это зависит от того, как вы хотите использовать эти параметры. Можно было бы вернуться к подходу, с помощью которого мы установили точку наблюдения для события rollOver с компонентом всплывающей подсказки, и придумать в данном случае нечто аналогичное, чтобы обычные события onEnterFrame выполнялись в одно и то же время, что и функция tweenTo, и чтобы не нужно было добавлять управляющий фильм.

     
 

XML

Теперь мы приступим к компиляции окончательной версии нашего сайта. Если мы хотим сделать представление изображений динамическим, имеет смысл сохранять список рисунков отдельно от фильма Flash и загружать рисунки по мере надобности.

 

XML является самым удобным способом работы с параметрами изображений, такими как ширина, высота и заголовок. В разрабатываемом здесь приложении мы сконцентрируемся на загрузке данных XML для реализации наших целей. В лекции 17 более подробно рассказывается об использовании XML совместно с Flash MX; в ней вы также изучите некоторые из правил и решений, важных при работе с данными XML. Если вы впервые столкнулись с XML, вам будет лучше ознакомиться с несколькими первыми страницами лекции 17 перед изучением данной темы.

 

Можно очень просто описать список рисунков с помощью XML. Каждое изображение будет иметь свой собственный узел, содержащий атрибуты для своего имени файла и названия. Каждый узел будет выглядеть примерно так.

 
<picture file="denim001.jpg" name="whatever"/>

Приведенный выше код XML содержит информацию об имени файла изображения, его ширине и высоте, а также о назначенном изображению названии, если таковое имеется. Знак " означает начало узла, так же, как и в HTML, а его окончание обозначается знаком /". picture означает тип данного узла, аналогично тому, как b означает жирный шрифт в HTML.

 

Полный код XML будет состоять из нескольких таких элементов, объединенных в корневой элемент pictures. Введите этот текст в текстовый файл и сохраните его под именем pictures.xml.

 
    <pictures>
        <picture file="denim001.jpg" name="whatever"/>
        <picture fiie="denim002.jpg" name="whatever"/>
        <picture file="denim003.jpg" name="whatever"/>
        <picture file="denim004.jpg" name="whatever"/>
        <picture file="denim005.jpg" name="whatever"/>
        <picture file="denim006.jpg" name="whatever"/>
        <picture file="denim007.jpg" name="whatever"/>
        <picture file="denim008.jpg" name="whatever"/>
    </pictures>

Вы только что создали простой файл XML. Если вы откроете файл pictures.xml в браузере, вы увидите иерархическое описание информации.

 

 


 

 

Заметьте, что здесь есть значок +/-, на котором вы можете щелкать для открытия или закрытия структуры документа и вывода связанной информации. Сам по себе этот документ не представляет особого интереса. Данные XML становятся полезными лишь тогда, когда они обрабатываются каким-либо другим приложением.

 

Разберемся, как можно использовать эти данные во Flash.

 

Добавление данных XML во Flash

Структуру XML нужно импортировать во Flash и затем преобразовать информацию в данные, которые можно использовать, т.е. в массив объектов изображений.

 
  1. Создадим новый объект, в который будем загружать документ XML.
        myXml = newXml();
        myXml.load ("pictures.xml");

    Это действие добавит документ XML, но после полной загрузки нам необходимо вызывать функцию.

     
  2. Для вызова функции по завершении загрузки документа XML мы можем использовать управляющий элемент onLoad объекта XML. Как и в случае с управляющими элементами событий фильма, мы можем определить функцию для ее вызова при возникновении данного события.
        myXml = new Xml();
        // call parseMe once xml has loaded
        myXml.onLoad = parseMe;
        myXml.load("pictures.xml");
        function parseMe() {
        }
  3. Перед созданием функции parseMe нужно добавить одну или более строк кода для обеспечения игнорирования всех пустых мест в исходном файле XML (к примеру, возврат каретки или табуляция).
        myXml = new Xml();
        myXml.ignoreWhite = true;
        myXml.onLoad = parseMe;
        myXml.load("pictures.xml");
        function parseMe() {
        }
  4. Функция parseMe должна раскрывать соответствующую информацию из каждого узла изображения и сохранять его, поэтому мы также создадим массив для хранения в нем данных.
        pictureObjects = [];
        myXml = new Xml();
        myXml.ignoreWhite = true;
        myXml.onLoad = parseMe;
        myXml.load("pictures.xml");
        function parseMe() {
        }
  5. При вызове функции parseMe наша цель находится внутри объекта XML, поэтому, если мы используем this, то получим список всего документа. Введите этот код под имеющимся кодом.
        function parseMe() {
            trace(this);
        }

    Если вы сохраните фильм в той же папке, где сохранили pictures.xml, и запустите его, то увидите строку в окне Output, содержащую всю информацию внутри pictures.xml.

     

     

     

     

    Однако в объекте XML имеется гораздо больше возможностей. При импортировании документа XML во Flash последний обрабатывает документ и создает из него структуру объекта, причем каждый узел ссылается на свои дочерние узлы, на братьев и на родителей, равно как и на атрибуты, которые могут иметь узлы.

     
 
  1. Чтобы увидеть все это, создадим цикл, проходящий все параметры объекта.
        function parseMe() {
        }
        function parseMe() {
            for (var i in this) {
                trace (property - "+i+" : value - "+this[i]");
            }
        }

    Этот цикл будет возвращать в окне Output следующий результат.

     

     


     

     

    Итак, с помощью функции parseMe нам нужно перейти к узлу pictures и пройти циклом через его дочерние узлы (узлы picture), выбирая атрибуты каждого изображения и сохраняя их в массиве.

     

    При вызове функции parseMe мы находимся внутри документа XML в корне документа, т.е. на уровень выше узла pictures.

     

    Для обращения к узлу изображений вводим следующее.

     
    this.firstChild;

    Это выражение ссылается на первый дочерний узел главного узла. Теперь узлы каждого отдельного изображения сохраняются внутри массива childNodes узла pictures - это узлы, существующие в иерархии внутри узла pictures. Для обращения к этому массиву вводим следующее. Это выражение ссылается на первый дочерний узел главного узла. Теперь узлы каждого отдельного изображения сохраняются внутри массива childNodes узла pictures - это узлы, существующие в иерархии внутри узла pictures. Для обращения к этому массиву вводим следующее.

     
    this.firstChild.childNodes;
  2. Это и есть массив, который мы будем обрабатывать циклом, поэтому нужно настроить сам цикл примерно так.
        function parseMe()  {
            var pictures = this.firstChild.childNodes;
            // loop through child nodes
            for (var i in pictures) {
                populate the array
            }
        }
  3. Внутри цикла каждым отдельным узлом рисунка будет pictures[i]. Информация, которую мы хотим получить, содержится внутри объекта attributes узла picture. Этот объект является стандартным объектом с параметром для каждого из атрибутов, поэтому мы можем просто копировать его в массив с использованием Array.push, чтобы он добавлялся в конец массива.
        function parseMe() {
            var pictures = this.firstChild.childNodes;
            for (var i in pictures) {
                var obj = pictures[i].attributes;
                pictureObjects.push(obj);
            }
        }
  4. Можно сократить.
        function parseMe() {
            var pictures = this.firstChild.childNodes;
            for (var i in pictures) {
                pictureObjects.push(pictures[i].attributes);
            }
        }

    Проблема заключается в том, что мы не создаем новый объект в массиве, а просто создаем ссылку на объект attributes в объекте XML. Если объект attributes в узле XML изменится, то же самое произойдет и с объектом в нашем массиве.

     
  5. Посмотрите на этот код и приведите ваш код в соответствие.
        function parseMe(){
            var pictures = this.firstChild.childNodes;
            for (var i in pictures) {
                pictureObjects.push(pictures[i] .attributes);
            }
            // add an attribute "hello" to the first childNode
            this.firstChild.childNodes[0].attributes.hello = true;
        }
  6. Теперь запустите код и выберите Debug > List Variables. В нашем массиве отобразится значение hello.

     


     

     
  7. Чтобы предотвратить это, будем обрабатывать объект attributes и копировать все параметры.
        function parseMe() {
            // this is the entire document
            // this.firstChild is the first node, ie our pictures node
            // this firstChiId.childNodes is the list of
              individual documents
            var pictures = this.firstChild.childNodes;
            for (var i in pictures) {
                var obj = {};
                // loop through and copy attributes
                for (var j in pictures[i].attributes) {
                    obj [j] = pictures [i] .attributes [j];
                }
                pictureObjects.push(obj);
            }
            this.firstChild.childNodes[0].attributes.hello = true;
        }
  8. Сохраните файл под именем bringInXML.fla и при его запуске выберите List Variables. hello больше не отображается в массиве.

     


     

     

    В данном случае это не очень важно, так как мы не собираемся в дальнейшем осуществлять управление документом XML, но нужно понимать, что происходит, когда объекты определяются посредством ссылки на другие объекты, а не в своих собственных терминах. Наш исходный массив содержал только указатель на объект атрибутов в узле XML, так что мы просто скопировали в него все параметры. Другой способ - удалить объект myXml, чтобы разрушить исходный объект attributes и оставить значение в массиве в виде единственной ссылки на этот объект.

     

Загрузчик XML

Интерфейс, создаваемый нами, будет составной частью сайта, поэтому добавим загрузчик данных XML. Мы создадим простой текстовый индикатор состояния, который будет отображать процент загрузки данных, а также выводить сообщение в случае неудавшейся загрузки XML. Нам нужно добавить код для метода tweenTo, установить метод setBrightness из предыдущей лекции и созданный нами объект Stage.

 

Вместо добавления всего этого кода вручную, сохраним код отдельно в файлах .as и используем выражения include для их включения.

 
    #include "tweento.as"
    #include "brightness.as"
    #include "stage.as"

Хорошей практикой считается использование таких фрагментов кода при работе с объектами. Когда Flash доходит до выражения include при компиляции SWF, то добавляет содержимое указанного в include файла. Последняя строка файла AS обязательно должна заканчиваться точкой с запятой! Одной из новых возможностей во Flash MX является глобальный путь include. Обычно при использовании выражения include нужно убедиться в том, что файлы AS находятся в той же директории, что и включающий их файл Flash. Глобальный путь позволяет сохранять любые файлы AS и предоставлять к ним доступ всем фильмам. На компьютере этот путь выглядит так: C:\Program Files\Macromedia\Flash MX\Configuration\ Include - папку include вы создаете сами. Когда Flash дойдет до выражения include, сначала будет осуществлен поиск в локальной директории, и если файл AS не будет найден в этой папке, то его поиск будет продолжен в глобальной папке include.

 

Здесь нужно включить три файла, для каждого из которых ниже указан ActionScript. Если вы не хотите вводить их заново или копировать из предыдущих файлов, возьмите их из исходных файлов для этой лекции.

 

Приведем содержимое каждого из трех файлов.

 

Подключение внешнего кода: tweenTo.as

 
    MovieClip.prototype.tweenTo = function(targetsObj, speed, callbackObj,callbackFunc) {
        var noo
        if (this.tweenControl) {
            noo = this.tweenControl;
        } else {
            noo = this.createEmptyMovieClip("tweenControl",this.depth++);
        }
        noo.targetsObj = targetsObj;
        noo.speed = speed;
        noo.callBackObj = callBackObj;
        noo.callBackFunc = callBackFunc;
        noo.onEnterFrame = function() {
            var count;
            // as its an object we can't check length,
            for (var prop in this.targetsObj) {
                this._parent[prop] += (this.targetsObj [prop]-
                Кthis._parent [prop] ) /this. speed;
                if (Math.abs(this.targetsObj [prop]-this._parent [prop] ) <0.9) {
                    this._parent[prop] = this.targetsObj [prop];
                    delete this.targetsObj [prop];
                }
                count++;
            }
            if (!count) {
                this.callBackObj [this.callBackFunc](this._parent);
                this.removeMovieClip();
            }
        };
    };

Пример 5.8.

Подключение внешнего кода: brightness.as

 
    Color.prototype.setBrightness = function(bright) {
        var aNum = 100-Math.abs(bright);
        var bNum = bright<0 ? 0 : Math.ceil(255*bright/100);
        this.setTransform({ra:aNum, ga:aNum, ba:aNum, aa:100,
        Кrb:bNum, bb:bNum, ab:0});
    };

Подключение внешнего кода: stage.as

 
    fscommand("allowscale", "false");
    Stage.scaleMode="showAll";
    Stage.originalWidth = Stage.Width;
    Stage.originalHeight = Stage.Height;
    Stage.scaleMode="noScale"
    Stage.onResize = function() {
        this.left = this.getLeft();
        this.top = this.getTop();
        this.right = this.getRight();
        this.bottom = this.getBottom();
    };
    Stage.getLeft = function() {
        return -1*(Stage.width-this.originalWidth)/2;
    };
    Stage. getTop = function() {
        return -1*(Stage.height-this.originalHeight)/2;
    };
    Stage. getRight = function() {
        return this.left+this.width;
    };
    Stage. getBottom = function() {
        return this.top+this.height;
    };
    Stage.addListener(Stage);
    // ensure onResize is called at start
    Stage.onResize();

Пример 5.9.

Создание загрузчика XML

Теперь внешние файлы ActionScript включены, и мы займемся кодом для фильма.

 
  1. Добавим новый слой scripts. Прежде всего мы создадим функцию для текстового отображения состояния фильма. Мы начнем с объекта текста TextFormat, который добавим под нашими выражениями include.
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
            Текущий код будет выглядеть так.
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"

        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
  2. На другом слое добавим динамическое текстовое поле сразу за верхней частью рабочего места. С помощью ActionScript укажем его местоположение. Выделим текстовое поле и добавим все символы Arial (или любого другого шрифта), нажав кнопку Character: в Property inspector. В диалоговом окне Character Options выберем опцию All Characters и нажмем кнопку Done.

     


     

     
  3. В Property inspector назовем текстовое поле embedder и введем следующий выделенный код, чтобы сделать поле невидимым.
        embedder._visible = 0;
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
  4. Мы также добавим переменную filename (выделено жирным шрифтом) для указания файла XML, нужного для загрузки. Здесь нам не понадобится использовать переменную, однако это упростит изменение имени файла при необходимости.
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
  5. Теперь мы добавим функцию createStatusMovie для создания текстового поля, установим формат текста и затем установим текст на значение, которое передается функции.
        function createStatusMovie(tex) {
            _root.createEmptyMovieClip("statusClip", 1);
            statusClip.createTextField
               ("statusText", 1, 0, 0, 550, 100);
          // set properties of textfield
            statusClip.statusText.embedFonts = true;
            statusClip.statusText.selectable = false;
            statusClip.statusText.setNewTextFormat(statusTf);
            statusClip.statusText.text = tex;
            statusClip._x = 0;
            statusClip._y = (Stage.originalHeight-
              statusClip.statusText.textHeight)/2-50;
        }

    Мы используем объект Stage для расположения текстового поля довольно далеко от центра по вертикали, а для горизонтального центрирования используем настройку выравнивания текстового поля. Функция createStatus будет вызываться при первом импорте XML. Мы можем использовать такую же функцию для создания загрузчика отдельных изображений.

     
  6. Для создания предзагрузчика XML мы используем методы getBytesLoaded и getBytesTotal объекта XML. Если поделить getBytesLoaded на getBytesTotal и затем умножить на 100, получим результат в процентах, представляющий собой загруженный XML. Функция updateXmlStatus будет вычислять процент и отображать результат в текстовом поле. Используем setInterval для регулярного вызова данной функции. Некоторая часть следующего кода функции importXml будет аналогична коду предыдущего раздела, где мы сначала импортировали наши данные XML во Flash. Новый код выделен жирным шрифтом.
        function importXml() {
            pictureObjects = [];
            myXml = new XML();
            myXml. ignoreWhite = true;
            // method to update display
            myXml.updateXmlStatus = function() {
                var percent = Math.round(this.getBytesLoaded()/
                Кthis.getBytesTotal()*100);
                if (percent<=0) {
                    percent = "0";
                }
                _root.statusClip.statusText.text = "PICTURE DATA LOADING
                К\n" percent+"%";
            };
            // use setlnterval to call updateXmlStatus every 20
            //milliseconds
            myXml.updater = setlnterval(myXml, "updateXmlStatus", 20);
            myXml.onLoad = parseMe;
            myXml.load(_root.filename);
            _root.createStatusMovie("PICTURE DATA LOADING");
        }

    Рассмотрим функцию updateXmlStatus.

     
        myXml.updateXmlStatus = function() {
            var percent = Math.round
              (this.getBytesLoaded()/this.getBytesTotal()*100);
            if (percent<=0) {
                percent = "0";
            }
            _root.statusClip.statusText.text =
               "PICTURE DATA LOADING \n"+percent+"%";
        };

    Прежде всего, мы вычисляем процентное значение и округляем его, чтобы избавиться от десятичной части. Когда вызов загрузки XML происходит в первый раз (перед тем, как Flash свяжется с сервером или примет любую информацию о файле), getBytesTotal возвращает значение undefined. Тогда процентное значение будет равно нулю, деленному на undefined, что, естественно, не даст никакого результата, и будет возвращено значение NaN (не число).

     

    Чтобы предотвратить отображение этого значения в виде процентов, мы выполняем проверку на percent. Так как NaN воспринимается Flash как значение, меньшее нуля, мы проверяем, является ли процентное значение меньшим, чем ноль и, если это так, просто устанавливаем percent на значение ноль. В последней строке мы обновляем отображаемый текст, добавляя новую строку после PICTURE DATA LOADING.

     
  7. Теперь рассмотрим, как отображать сообщение, если что-то происходит неправильно. Это можно реализовать, значительно изменив функцию parseMe. Когда функция присваивается управляющему элементу onLoad объекта XML, ей передается один параметр при происхождении события onLoad. Если XML загружен успешно, передается значение "истина", в противном случае - "ложь". Итак, мы изменяем нашу предыдущую функцию parseMe для проверки этого значения и выполнения действий с его использованием. Новый код выделен жирным шрифтом.
        function parseMe(success) {
            // if the xml has loaded successfully
            if (success) {
                var pictures = this.firstChild.childNodes;
                for (var i = 0; i<pictures.length; i++) {
                    var obj = {};
                    for (var j in pictures[i] .attributes) {
                        obj [j] = pictures [i] .attributes [j];
                    }
                    pictureObjects.push(obj);
                }
                // stop calling the display update function
                clearInterval(this.updater);
                _root.pictureDataComplete();
                this.updateXmlStatus();
                //statusClip.removeMovieClip()
            } else {
            _root.statusClip.statusText.text = "FAILED TO LOAD DATA";
            clearInterval(this.updater);
            }
        }

    Если загрузка не удалась, мы изменяем statusText для чтения FAILED TO LOAD DATA. Независимо от того, была загрузка успешной или нет, вызывается интервал updateXmlStatus. При непосредственном использовании кода мы будем удалять клип состояния сразу по завершении загрузки, однако сейчас мы оставим его, чтобы убедиться в правильности функционирования вызова статуса, т.к. в противном случае сообщение будет исчезать практически мгновенно.

     
  8. Добавим функцию pictureDataComplete, которая будет вызываться после загрузки XML, и функцию init для начала загрузки XML. Приведем окончательный код. Жирным шрифтом выделены функции pictureDataComplete и init.
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
        function createStatusMovie(tex) {
            _root.createEmptyMovieClip("statusClip", 1);
            statusClip.createTextField("statusText", 1, 0, 0, 550, 100);
            statusClip.statusText.embedFonts = true;
            statusClip.statusText.selectable = false;
            statusClip.statusText.setNewTextFormat(statusTf);
            statusClip.statusText.text = tex;
            statusClip._x = 0;
            statusClip._y = (Stage.originalHeight- statusClip.statusText.textHeight)/2-50;
        }
        function importXml() {
            pictureObjects - [];
            myXml = new XML();
            myXml.ignoreWhite = true;
            myXml.updateXmlStatus = functionO {
                var percent = Math.round(this.getBytesLoaded() / this.getBytesTotal()*100);
                if (percent<=0) {
                    percent = "0";
                }
                _root.statusClip.statusText.text = "PICTURE DATA LOADING \n"+percent+"%";
            };
            myXml.updater = setInterval(myXml, "updateXmlStatus", 20);
            myXml.onLoad = parseMe;
            myXml.load(_root.filename);
            _root.createStatusMovie("PICTURE DATA LOADING");
        }
        function parseMe(success) {
            if (success) {
                var pictures = this.firstChild.childNodes;
                for (var i = 0; i<pictures.length; i++) {
                    var obj = {};
                    for (var j in pictures[i].attributes) {
                        obj [j] = pictures [i] .attributes [j];
                    }
                    pictureObjects.push(obj);
                }
                clearlnterval(this.updater);
                _root.pictureDataComplete();
                this.updateXmlStatus();
                //statusClip.removeMovieClip()
            } else {
                _root.statusClip.statusText.text = "FAILED TO LOAD DATA";
                clearlnterval(this.updater);
            }
        }
        function pictureDataComplete() {
            trace("picture data loaded");
        }
        function init() {
            importXml () ;
        }
        init();

    Пример 5.10.

    Если вы запустите файл без его сохранения, вы получите сообщение FAILED TO LOAD DATA, т.к. FLA и pictures.xml не сохранены в той же папке. Сохраните фильм в файле xmlLoader.fla и запустите его снова. На этот раз, как мы и планировали, будет выведено сообщение PICTURE DATA LOADING 100%:

     

     


     

     
 

Локальное сохранение XML

Одной из прекрасных возможностей, связанных с общими объектами, является возможность сохранять внутри них любые данные. Благодаря этому можно не импортировать каждый раз XML, содержащий имена файлов изображений, а сохранить массив рисунков локально. Мы также можем установить срок обновления для общего объекта, после которого будет выполняться повторный импорт XML в случае его изменения.

 

Методология этого подхода очень проста. Перед импортом XML с помощью sharedObject.getLocal мы проверяем, создан ли общий объект для фильма. Если не создан, или общий объект является более старшим, чем определенная дата, мы продолжим работу и импортируем XML. После импорта и обработки XML мы будем сохранять массив pictureObjects и текущее время в общем объекте. Если у нас уже есть общий объект, мы получим массив pictureObjects из общего объекта, а не из XML.

 
  1. Сначала создадим функцию для сохранения массива в общем объекте. Мы добавим вызов этой функции после успешной загрузки XML, а также уберем комментарий со строки кода для удаления statusClip.
        function parseMe(success) {
            if (success) {
                var pictures = this.firstChild.childNodes;
                for (var i = 0; i<piсtures.length; i++) {
                    var obj = {};
                    for (var j in pictures[i].attributes) {
                        obj [j] = pictures [i] .attributes [j];
                    }
                    pictureObjects.push(obj);
                }
                _root.refreshSharedObj();
                clearlnterval (this.updater);
                statusClip.removeMovieClip();
                _root.pictureDataComplete ();
            } else {
                _root.statusClip.statusText.text = "FAILED TO LOAD DATA";
                clearlnterval(this.updater);
            }
        }
  2. В функции refreshSharedObj нам нужно сначала получить общий объект с помощью sharedObject.getLocal. Затем мы поместим наш массив pictureObjects в общий объект.
        mySharedObj = sharedobject.getLocal("denim");
        mySharedObj.data.pictureObjects = pictureObjects;
  3. Затем нам нужно создать дату. Для этого можно использовать метод getTime объекта Date. Этот метод возвращает число миллисекунд, прошедших с 1 января 1970 года, что дает значение, с которым мы будем работать. Для этого сначала создаем новый инстанс объекта Date, а затем вызываем его метод getTime, сохраняя значение в качестве timeStamp в общем объекте.
        var dat = new Date();
        mySharedObj.data.timeStamp = dat.getTime();
  4. Окончательная функция включает весь код из шагов 2 и 3 плюс метод flush общего объекта для сохранения информации. Расположите функцию refreshSharedObj под функцией parseMe.
        function refreshsharedobj() {
            mySharedObj = sharedobject.getLocal("denim");
            mySharedObj.data.pictureObjects = pictureObjects;
            var dat = new Date();
            // store the timestamp in the shared object
            mySharedObj.data.timeStamp = dat.getTime();
            mySharedObj.flush();
        }
  5. Следующая функция - checkShared. Мы будем вызывать эту функцию из функции init и использовать возвращаемое значение функции для определения того, вызываем или нет функцию importXml. Если функция возвращает значение "истина", это будет означать, что данные были найдены в общем объекте, и нам не требуется импортировать XML; если же возвращается значение "ложь", приступаем к импорту XML. Наша функция лишь возвращает значение "истина", если она находит общий объект с массивом рисунков внутри него, а разница между текущим временем и временем его создания меньше определенного значения. Вот как сейчас примерно будет выглядеть наша функция init.
        function init() {
            // if the checkshared function returns true
            if (!checkshared()) {
                importXml();
            }
        }
  6. Первое, что нужно сделать в checkShared (это будет под функцией refreshSharedObj), это получить общий объект.
        function checkshared() {
            mySharedObj = sharedobject.getLocal("denim");
        }
  7. Затем мы проверяем, содержит ли mySharedObj массив с именем pictureObjects в объекте data.
        function checkshared() {
            mySharedObj = sharedobject.getLocal("denim");
            if (mySharedObj.data.pictureObjects) {
            . . .
            }
        }
  8. Если это так, то мы сразу получаем нужные нам данные, и нам требуется просто проверить даты, поэтому мы создаем объект new Date.
        function checkshared() {
            mySharedObj = sharedobject.getLocal("denim");
            if (mySharedObj.data.pictureObjects) {
                var dat = new Date();
            }
        }
  9. Для сравнения текущей даты с датой сохранения общего объекта мы можем сделать следующее.
    dat.getTime () -mysharedObj.data.timeStamp;

    Это определит количество миллисекунд между текущим моментом и моментом установки общего объекта. Наилучший период для новой загрузки XML - примерно раз в неделю, поэтому мы проверяем, что значение меньше, чем 1000*60*60*27*7 = 604800000.

     

    Если оно меньше, возвращается "истина", если нет, ничего не будет возвращено. Мы так же вызываем функцию pictureDataComplete, которую создали к моменту окончания загрузки XML. Новый код выделен жирным шрифтом.

     
        function checkShared() {
            mySharedObj = sharedobject.getLocal("denim");
            if (mySharedObj.data.pictureObjects) {
                var dat = new Date();
                if (dat.getTime()-mysharedObj.data.timeStamp<604800000) {
              // retrieve the array from the sharedObject
                    _root.pictureObjects = mySharedObj.data.pictureObjects;
                    pictureDataComplete();
                    return true;
                }
            }
        }

    Приведем окончательный код.

     
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.filename = "pictures .xml";
        embedder._visible = 0;
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
        function createStatusMovie(tex) {
            _root.createEmptyMovieClip("statusClip", 1);
            statusClip.createTextField("statusText", 1, 0, 0, 550, 100);
            statusClip.statusText.embedFonts = true;
            statusClip. statusText. selectable = false;
            statusClip.statusText.setNewTextFormat(statusTf);
            statusClip.statusText.text = tex;
            statusClip._x = 0;
            statusClip._y = (Stage. original Height- statusClip.statusText.textHeight)/2-50;
        }
        function importXml() {
            trace("data imported from xml");
            pictureObjects = [];
            myXml = new XML();
            myXml.ignoreWhite = true;
            myXml.updateXmlStatus = function() {
                var percent = Math.round(this.getBytesLoaded()/ this.getBytesTotal()*100);
                if (percent<=0) {
                    percent = "0";
                }
                _root.statusClip.statusText.text = "PICTURE DATA LOADING \n"+percent+"%" ;
            };
            myXml.updater = setInterval(myXml, "updateXmlStatus", 20);
            myXml.onLoad = parseMe;
            myXml.load(_root.filename);
            _root.createStatusMovie("PICTURE  DATA  LOADING");
        }
        function parseMe(success) {
            if (success) {
                var pictures = this.firstChild.childNodes;
                for (var i = 0; i<pictures. length; i++) {
                    var obj = {};
                    for (var j in pictures[i] .attributes) {
                        obj[j] = pictures [i] .attributes [j];
                    }
                    pictureObjects.push(obj);
                }
                _root.refreshSharedObj();
                clearInterval(this.updater);
                statusClip.removeMovieClip();
                _root.pictureDataComplete();
            } else {
                _root.statusClip.statusText.text = "FAILED TO LOAD DATA";
                clearInterval(this.updater);
            }
        }
        function refreshSharedObj() {
            mySharedObj = sharedobject.getLocal("denim");
            mySharedObj.data.pictureObjects = pictureObjects;
            var dat = new Date();
            mySharedObj.data.timestamp = dat.getTime();
            mySharedObj.flush();
        }
        function checkShared() {
            mySharedObj = sharedobject.getLocal("denim" );
            if (mySharedObj.data.pictureObjects) {
                var dat = new Date();
                if (dat.getTime()-mysharedObj.data.timeStamp<604800000) {
                    trace("data found in shared object");
                    _root.pictureObjects = mySharedObj.data.pictureObj ects;
                    pictureDataComplete();
                    return true;
                }
            }
        }
        function pictureDataComplete() {
            trace("picture data loaded");
        }
        function init() {
            importXml();
        }
        function init() {
            if (!checkShared()) {
                importXml();
            }
        }
        init();

    Пример 5.11.

  10. Сохраните ваш файл под именем xmlInShared.fla и запустите его. Вот результат, который вы получите в окне Output.

     


     

     

    Мы добавили два выражения trace (выделены жирным шрифтом) для проверки того, откуда загружаются данные - из XML или из общего объекта. Можно поэкспериментировать с ними, чтобы понять, как они работают. Попробуйте изменить число миллисекунд даты окончания общего объекта. Таким же способом можно полностью удалить общий объект.

     
        function checkShared() {
            mySharedObj = sharedobject.getLocal("denim");
            // loop through properties and delete them
            for (var i in mySharedObj .data) {
                delete mySharedObj.data[i];
            }
        }

    В этом случае в окне Output отобразится, что данные были импортированы из XML.

     

     


     

     

    Этот способ сохранения XML в виде объектной структуры может быть особенно полезен при работе с большими структурами или использовании сложных систем анализа. В этих обстоятельствах сохранение результатов посредством анализа XML позволяет нам сэкономить время и пропустить загрузку данных и ее представление посредством локального сохранения XML и представления его в виде данных, которые в обычном порядке распознаются Flash.

     
 

Предварительная загрузка изображений

После загрузки данных для рисунков нужно выполнить предварительную загрузку изображений, одно за другим. Мы реализуем это в функции pictureDataComplete, которая будет выполняться посредством поочередной загрузки рисунков в пустой фильм, расположенный вне рабочего места. Лучше делать это именно так, нежели загружать рисунки все сразу, так как множественные вызовы loadMovie в один и тот же момент времени вызывают проблемы в некоторых браузерах.

 
  1. В pictureDataComplete создадим новый фильм состояния, а также фильм, в который будут загружаться изображения. Установим enterFrame, принадлежащий _root, на значение checkPreload, которое будет обновлять состояние и проверять загрузку каждого изображения. Наконец, мы вызовем loadNext для начала загрузки первого изображения. Переменная picLoading служит для выяснения того, какое изображение загружается в данный момент. Мы заменим выражение trace, располагавшееся прежде в функции pictureDataComplete, следующим кодом.
        function pictureDataComplete() {
            _root.createStatusMovie("PICTURES LOADING");
            _root.createEmptyMovieClip("picturePlacebo", 2);
            picturePlacebo._x = 1000;
            picLoading = 0;
            // check how much is loaded on enterFrame
            this.onEnterFrame = checkPreload;
            loadNext();
        }
  2. loadNext будет проверять, имеются ли изображения, которые еще должны быть загружены, в массиве pictureObjects (если picLoading меньше, чем длина массива). Если еще остался рисунок для загрузки, он будет загружен в фильм, расположенный вне рабочего места; в противном случае этот фильм будет удален, а statusClip постепенно исчезнет с использованием tweenTo.

    После плавного исчезновения фильма будет вызвана setUpStage - функция, устанавливающая интерфейс для просмотра рисунков. Приведем код, который мы ввели под нашей функцией pictureDataComplete.

     
        function loadNext() {
            if (picLoading<pictureObjects.length) {
            // Load the next picture using the file property
            picturePlacebo.loadMovie(pictureObjects[picLoading].file);
            } else {
                delete this.onEnterFrame;
                var obj = {_alpha:0};
                picturePlacebo.removeMovieClip();
                _root.statusClip.tweenTo(obj, 9, _root, "setUpStage");
            }
        }
  3. Функция checkPreload работает во многом так же, как и загрузчик XML. Она создает переменную percent и устанавливает ее по getBytesLoaded внешнего (находящегося вне рабочего места) фильма, а затем отображает процентное значение в фильме status. После полной загрузки рисунка (когда процент равен 100) она сначала сохраняет ширину и высоту фильма (которые равны ширине и высоте рисунка внутри фильма) в нашем массиве pictureObjects. Затем она увеличивает переменную picLoading и вызывает loadNext. Мы расположили эту функцию под loadNext.
        function checkPreload() {
            var percent = Math.round(picturePlacebo.getBytesLoaded()
            К/picturePlacebo.getBytesTotal()*100);
            if (percent<=0) {
                percent = "0";
            }
            _root.statusClip.statusText.text =
              "PICTURE"+(picLoading+1)+"
            КLOADING \n"+percent+"%";
            if (percent == 100) {
            // store picture's width and height
                _root.pictureObjects[picLoading].width =
                  _root.picturePlacebo._width;
                _root.pictureObjects[picLoading].height =
                  _root.picturePlacebo._height;
                picLoading++;
                loadNext();
            }
        }

    Приведем окончательный код.

     
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
        function createStatusMovie(tex) {
            _root.createEmptyMovieClip("statusClip", 1);
            statusClip.createTextField("statusText", 1, 0, 0, 550, 100);
            statusClip.statusText.embedFonts = true;
            statusClip.statusText.selectable = false;
            statusClip.statusText.setNewTextFormat(statusTf);
            statusClip.statusText.text = tex;
            statusClip._x = 0;
            statusClip._y = (Stage.originalHeight statusClip.statusText.textHeight)/2-50;
        }
        function importXml() {
            trace("data imported from xml");
            pictureObjects = [];
            myXml = new Xml();
            myXml. ignoreWhite = true;
            myXml.updateXmlStatus = function() {
                var percent = Math.round(this.getBytesLoaded()/this.getBytesTotal()*100);
                if (percent<=0) {
                    percent = "0";
                }
                _root.StatusClip.statusText.text = "PICTURE DATA LOADING \n"+percent+"%";
            };
            myXml.updater = setInterval(myXml, "updateXmlStatus", 20);
            myXml.onLoad = parseMe;
            myXml.load(_root.filename);
            _root.createStatusMovie("PICTURE DATA LOADING");
        }
        function parseMe(success) {
            if (success) {
                var pictures = this.firstChild.childNodes;
                for (var i = 0; i<pictures.length; i++) {
                    var obj = {};
                    for (var j in pictures[i].attributes) {
                        obj[j] = pictures [i].attributes [j];
                    }
                    pictureObjects.push(obj);
                }
                _root.refreshSharedObj();
                clearlnterval(this.updater);
                statusClip.removeMovieClip();
                _root.pictureDataComplete();
            } else {
                _root.StatusClip.statusText.text = "FAILED TO LOAD DATA";
                clearlnterval(this.updater);
            }
        }
        function refreshSharedObj() {
            mySharedObj = sharedobject.getLocal("denim");
            mySharedObj.data.pictureObjects = pictureObject s;
            var dat = new Date();
            mySharedObj.data.timeStamp = dat.getTime();
            mySharedObj.flush();
        }
        function checkShared() {
            mySharedObj - sharedobject.getLocal("denim");
            if (mySharedObj.data.pictureObjects) {
                var dat = new Date();
                if (dat.getTime()-mysharedObj.data.timeStamp<604800000) {
                    trace("data found in shared object");
                    _root.pictureObjects = mySharedObj.data.pictureObjects;
                    pictureDataComplete();
                    return true;
                }
            }
        }
        function pictureDataComplete() {
            _root.createStatusMovie("PICTURES LOADING");
            _root.createEmptyMovieClip("picturePlacebo", 2);
            picturePlacebo._x = 1000;
            picLoading = 0;
            this.onEnterFrame = checkPreload;
            loadNext();
        }
        function loadNext() {
            if (picLoading<pictureObjects.length) {
                picturePlacebo.loadMovie(pictureObjects[picLoading].file);
            } else {
                delete this.onEnterFrame;
                var obj = {_alpha:0};
                picturePlacebo.removeMovieClip();
                _root.statusClip.tweenTo(obj , 9, _root, "setUpStage");
            }
        }
        function checkPreload() {
            var percent = Math.round(picturePlacebo.getBytesLoaded()/
            КpicturePlacebo.getBytesTotal()*100);
            if (percent<=0) {
                percent = "0";
            }
            _root.statusClip.statusText.text = "PICTURE "+(picLoading+1)+"
            КLOADING \n"+percent+"%";
            if (percent == 100) {
                _root.pictureObjects[picLoading].width = _root.picturePlacebo._width;
                _root.pictureObjects[picLoading].height = _root.picturePlacebo._height ;
                picLoading++;
                load Next();
            }
        }
        function init() {
            if (!checkShared()) {
                importXml();
            }
        }
        init();

    Пример 5.12.

  4. Сохраните ваш файл под именем preloadPictures.fla. При его запуске вы увидите следующее сообщение.

    В дополнение к этому, если вы выберете Debug > List Variables, в окне Output также отобразится, что все ваши рисунки загружены.

     

     


     

     

    Внесем последние добавления к нашему интерфейсу - настроим рабочее место таким образом, чтобы могли отображаться фотографии, а потом определим, как именно они будут отображаться.

     
 

Настройка рабочего места

Мы реализуем отображение каждой фотографии по центру рабочего места, при этом маска будет перемещаться слева направо, постепенно показывая изображение. Как только маска одной фотографии переместится и откроет ее, маска для предыдущей фотографии также переместится и в тот же момент скроет эту фотографию, что создаст эффект двигающейся пленки.

 
  1. Первое, что нужно сделать при вызове setUpStage - это удалить statusClip. После этого мы создадим строку кнопок для вызова нужных фотографий.
        function setUpStage() {
            _root.statusClip.removeMovieClip();
            // create the buttons
            createButtons();
            // trigger the first photo
            triggerPhoto(0);
        }
  2. Для создания кнопок мы будем использовать компонент nooButton, созданный в предыдущей лекции, поэтому убедитесь, что в Library имеется его копия (вы можете заимствовать ее из полной версии этого упражнения в файле с именем finalVersion.fla). Мы добавим объект textFormat для кнопок в верхней части нашего кода. Приведем новую строку кода, выделенную жирным шрифтом.
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        buttonTf = new TextFormat("Arial", 20, 0x4375A6);
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
  3. Функция createButtons (расположенная нами под setUpStage) знакома вам из предыдущей лекции. Мы создаем объект для установки параметров новой кнопки, ее внешнего вида и действия. На этот раз мы присваиваем функцию triggerPhoto управляющему элементу события press, которая будет передавать функции номер фотографии.
        function createButtons(imageArr, tF) {
            _root.createEmptyMovieClip("buttonHolder", 100000);
            var currx;
            for (var i = 0; i<pictureObjects.length; i++) {
                _root.buttonHolder.depth = i + 1;
                var caption = (i+1).toString().length<2 ? "00"+(i +1) : "0"+(i +1);
                var obj = {myText:caption, _x:currx, obj:_root, defaultBright:0, rollOverBright:30,
                КvisitedBright:60, activeBright:-30, pressFunction:"triggerPhoto",
                КpressArgs:i, tf:buttonTf, embedFonts:true};
                var nooButton = buttonHolder.attachMovie("nooButtonMc", "noob"+i, i, obj);
                currX += nooButton.width+5;
            }
            // set the first button to active
            buttonHolder.noob().setActive();
            buttonHolder._x = (Stage.originalWidth-buttonHolder._width)/2;
            buttonHolder._y = Math.round(Stage.bottom)-buttonHolder._height;
            // move to the bottom of the stage onResize
            buttonHolder.onResize = function() {
                var у = Math.round(Stage.bottom)-30;
                this.tweenTo({_y:y}, 3);
            };
            Stage.addListener(buttonHolder);
            Stage.onResize();
            buttonHolder.onResize();
        }

    Пример 5.13.

    Если на данном этапе запустить фильм, кнопки загрузятся в нижней части рабочего места.

     

     


     

     

    Мы использовали несколько новых элементов во второй части функции createButtons и сейчас рассмотрим их поподробнее.

     

    Прежде всего, мы вызываем метод setActive первой кнопки. Это кнопка, соответствующая первой загруженной фотографии, поэтому она должна быть отключена в начале.

     
    buttonHolder.noob0.setActive();

    Затем мы используем объект Stage для установки позиции фильма buttonHolder таким образом, что он отцентрирован по горизонтали и расположен прямо над нижнем краем.

     
        buttonHolder._x = (Stage.originalWidth-buttonHolder._width)/2;
        buttonHolder._y = Math.round (Stage.bottom)-buttonHolder._height;

    Мы хотим, чтобы кнопки оставались внизу окна браузера или проигрывателя, поэтому добавляем функцию onResize для перемещения кнопки на нужное место.

     
        buttonHolder.onResize = function() {
            var у = Math.round(Stage.bottom)-30;
            this.tweenTo({_y:у}, 3);
        };
        Stage.addListener(buttonHolder);

    Наконец, добавляем вызовы Stage.onResize и buttonHolder.onResize для проверки того, что даты были корректны в момент создания кнопок. Это необязательно, но без обеспечения этой возможности значения Stage не будут корректно обновляться, и позиционирование будет работать неправильно.

     

    Теперь мы готовы приступить к созданию последней части нашего интерфейса и настроить его так, чтобы можно было просматривать фотографии на рабочем месте, а также выбирать способ их отображения.

     
 

Отображение фотографий

Для применения механизма маски при отображении фотографий создадим пары фильмов. При вызове новой фотографии мы создаем фильм, в котором будет содержаться фотография, а также маску, которая будет на ней. При вызове фотографии маска будет полностью открывать фотографию. В тот же момент маска, которая была расположена над верхней границей предыдущей фотографии, переместится через рабочее место для ее сокрытия. Когда маска будет целиком вне рабочего места, а фотография полностью скрыта, старые маска и фотография будут удалены.

 
  1. Каждая пара фотографий будет создаваться под предыдущей парой, поэтому мы добавляем переменную depth после выражений include, которая будет начинаться со значения 1000 и будет постепенно уменьшаться.
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.depth = 1000;
        _root.filename = "pictures.xml";
  2. Теперь мы создаем фильм, который будет использоваться для маски. Дайте ему имя mask и внутри него нарисуйте квадрат 100х100 пикселей.
  3. Щелкните правой кнопкой мыши на mask в Library и выберите Linkage: из меню для отображения диалогового окна Linkage Properties. Выберите опцию Export for ActionScript и в поле Identifier введите mask.

     


     

     
  4. Функция triggerPhoto обеспечит несколько возможностей.
    function triggerPhoto (currentPicture) {

    Во-первых, она будет определять объект рисунка, который будет использоваться, путем поиска в массиве pictureObjects значения, переданного функции.

     
        function triggerPhoto(currentPicture) {
            var nextPicObj = pictureObjects[currentPicture];

    Затем она создаст пустой фильм для содержания в нем рисунка. Далее внутри него будет создан другой фильм, в который будет непосредственно загружаться рисунок. Это делается потому, что когда фильм содержит загруженный рисунок или иной SWF, удаляются многие элементы, такие как элементы управления onEnterFrame и (что более подходит к нашему случаю) маскирование данных.

     

    Располагаем фильм по центру рабочего места с использованием данных о ширине и высоте при предварительной загрузке изображений, и далее значительно изменяем размер фильма для обеспечения развертывания изображения.

     
        _root.depth--;
        var noopic = createEmptyMovieClip("picClip"+depth, depth);
        noopic.createEmptyMovieClip("inner", 1);
        noopic.inner.loadMovie(nextPicObj.file);
        nooPic._xscale = nooPic._yscale = 101;
        nooPic.inner._x = (Stage.originalWidth-nextPicObj.width)/2;
        nooPic.inner._y = (Stage.originalHeight-nextPicObj.height)/2;

    После этого создаем максу, которая будет располагаться по левому краю рабочего стола и растягиваться по высоте фильма. Внутри маски мы устанавливаем ссылку на соответствующий фильм с рисунком, чтобы при удалении маски изображение также могло быть удалено.

     
        _root.depth--;
        var nooMask = _root.attachMovie("mask", "mask"+depth, depth);
        nooMask._x = 0;
        nooMask._yscale = Stage.originalHeight;
        nooMask._xscale = 1;
        nooMask.myPic = nooPic;
        nooPic.setMask(nooMask);

    Мы будем постепенно изменять размер маски для покрытия всего рабочего места.

     
    noMask.tweenTo ({_xscale:Stage.originalWidth+200}, 15);

    Следующим шагом выясним, находится ли уже рисунок на рабочем месте, и вызовем функцию maskOut, если это так.

     
        if (_root.latestMask) {
            maskOut();
        }

    После этого мы устанавливаем latestMask на текущую маску, указывая, что она будет удалена следующей.

     
    _root.latestMask = nooMask;

    Наконец, проверяем, опустилось ли значение depth ниже величины 900. Если да, то возвращаем значение на 1000 для предотвращения перезаписи каких-либо элементов на рабочем столе.

     
        if (_root.depth<900) {
                _root.depth = 1000;
            }

    Приведем полный код функции.

     
        function triggerPhoto(currentPicture) {
            var nextPicObj = pictureObjects[currentPicture];
            _root.depth--;
            var noopic = createEmptyMovieClip("picClip"+depth, depth);
            noopic.createEmptyMovieClip("inner", 1);
            noopic.inner.loadMovie(nextPicObj.file);
            nooPic._xscale = nooPic._yscale=101;
            nooPic.inner._x = (Stage.originalWidth-nextPicObj.width)/2;
            nooPic.inner._y = (Stage.originalHeight-nextPicObj.height)/2;
            _root.depth--;
            var nooMask = _root.attachMovie("mask", "mask"+depth, depth);
            nooMask._x = 0;
            nooMask._yscale = Stage.originalHeight;
            nooMask._xscale = 1;
            nooMask.rayPic = nooPic;
            nooPic.setMask(nooMask);
            nooMask.tweenTo((_xscale:Stage.originalWidth+200}, 15);
            if (_root.latestMask) {
                maskOut();
            }
            _root.latestMask = nooMask;
            if (_root.depth<900) {
                _root.depth = 1000;
            }
        }
  5. Теперь нам нужно создать функцию maskOut, которая будет перемещать предыдущую маску за пределы рабочего места. Имейте в виду, что мы перемещаем этот фильм на ту же самую позицию (Stage.originalWidth+200), на которую была перемещена первая маска. При этом открывающая и скрывающая маски появляются и исчезают примерно с одинаковой скоростью.
        function maskOut() {
            _root.latestMask.tweenTo({_x:Stage.originalWidth+200},
               15, _root, "remove");
        }
  6. По достижении фильмом конечной точки вызывается функция remove, которая удаляет его вместе с соответствующим рисунком.
        function remove(maskMc) {
            maskMc.myPic.removeMovieClip();
            maskMc.removeMovieClip();
        }

    Создание кода завершено, однако он слишком велик, чтобы приводить его целиком в этой книге, поэтому ниже мы приведем только основные дополнения, сделанные в двух последних параграфах. Они выделены жирным шрифтом.

     
        #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.depth = 1000;
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        buttonTf = new textFormat("Arial", 20, 0x4375A6);
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        //rest of code goes here

        function createButtons(imageArr, tF) {
            _root.createEmptyMovieClip("buttonHolder", 100000);
            var currx;
            for (var i = 0; i<pictureObjects.length; i++) {
                _root.buttonHolder.depth = i+1;
                var caption = (i+1) .toString().length<2 ? "00"+(i+1) : "0"+(i+1);
                var obj = {myText:caption, _x:currx, obj:_root,
                КdefaultBright:0, rollOverBright:30, visitedBright:60,
                КactiveBright:-30, pressFunction:"triggerPhoto",
                К-pressArgs:i, tf:buttonTf, embedFonts:true};
                var nooButton = buttonHolder.attachMovie ("nooButtonMc",
                К"noob"+i, i, obj);
                currX += nooButton.width+5;
            }
            buttonHolder.noob().setActive();
            buttonHolder._x = (Stage.originalWidth-buttonHolder._width)/2;
            buttonHolder._y = Math.round(Stage.bottorn)-buttonHolder._height;
            buttonHolder.onResize = function() {
                var у = Math.round (Stage.bottom) -30;
                this.tweenTo({_y:y}, 3);
            };
            Stage.addListener(buttonHolder);
            Stage.onResize();
            buttonHolder.onResize();
        }
        function triggerPhoto(currentPicture) {
            var nextPicObj = pictureObjects[currentPicture];
            _root.depth--;
            var noopic = createEmptyMovieClip("picClip"+depth, depth);
            noopic.createEmptyMovieClip("inner", 1);
            noopic.inner.loadMovie(nextPicObj.file);
            nooPic._xscale = nooPic._yscale=101;
            nooPic.inner._x = (Stage.originalWidth-nextPicObj.width)/2;
            nooPic.inner._y = (Stage.originalHeight-nextPicObj.height)/2;
            _root.depth--;
            var nooMask = _root.attachMovie("mask", "mask"+depth, depth);
            nooMask._x = 0;
            nooMask._yscale = Stage.originalHeight;
            nooMask._xscale = 1;
            nooMask.myPic = nooPic;
            nooPic.setMask(nooMask);
            nooMask.tweenTo((_xscale:Stage.originalWidth+200}, 15);
            if (_root.latestMask) {
                maskOut();
            }
            _root.latestMask = nooMask;
            if (_root.depth<900) {
                _root.depth = 1000;
            }
        }
        function maskOut() {
            _root.latestMask.tweenTo({_x:Stage.originalWidth+200}, 15, _root,
            К"remove");
        }
        function remove(maskMc) {
            maskMc.myPic.removeMovieClip();
            maskMc.removeMovieClip();
        }
        function init() (
            if (!checkShared()) {
                importXml(};
            }
        }
        init();

    Пример 5.14.

  7. Сохраните файл с именем finalVersion.fla и запустите его. Вы сначала увидите сообщение о загрузке рисунков. Затем оно исчезнет перед появлением кнопок при отображении первой картинки.

     

    Загрузка рисунка завершена

    Загрузка рисунка завершена

     

     

     

    Рисунок 1 появляется во время перемещения кнопок на их места

    Рисунок 1 появляется во время перемещения кнопок на их места

     

     

     

    Настройка рабочего места почти завершена

    Настройка рабочего места почти завершена

     

     

     

    Рисунок 1 исчезает, а рисунок 3 появляется

    Рисунок 1 исчезает, а рисунок 3 появляется

     

     
     

    Таким образом, при создании этого интерфейса вы изучили намного больше, чем при работе с двумя предыдущими версиями. Здесь рисунки загружаются динамически, а с использованием XML можно выбирать рисунки для загрузки без изменения FLA. Мы также минимизировали время инициализации, использовав sharedObjects для кэширования созданного при обработке XML массива. Интерфейс может работать с массивами различного размера, хотя массивы, с которыми мы работали, были одинаковы по величине. Даже если вы будете быстро щелкать на разных кнопках, фотографии по-прежнему будут плавно скользить через экран. При помощи системы обратных связей можно изменить работу масок так, чтобы фотографии появлялись только после исчезновения других. Данные заголовка, которые мы включили в XML, можно использовать для добавления названий рисунков.

     
 

источник: http://www.INTUIT.ru 


 

13 центов(0,13$) за клик, выплаты через WebMoney каждый вторник +10% с рефералов

Мы выкупаем 100% трафа! $12 за 1000 хостов (РФ), и до $4 за 1000 хостов (зарубежный траф) + 10% с дохода Ваших рефералов!
 Выплаты через
WebMoney

~80-100$ за1000 хостов 2.5$ за 1 смс.
реф. процент - 10 %Выплаты происходят раз в неделю, в четверг на
WebMoney
 
 
 

 

____________________________

Посмотреть порно видео в онлайне »

_______________________________

 

   
   
Сайт управляется системой uCoz