Внимание!
Для работы с этой лекцией необходимы учебные файлы,
которые Вы можете загрузить
здесь.
Одной из
прекрасных возможностей Flash MX является широкий спектр
средств управления параметрами текста. Если раньше для
того, чтобы изменить шрифт в текстовом поле, нужно было
присвоить тексту формат HTML, то теперь для этого есть
объект textFormat. С
помощью него можно избежать присутствия тегов среди
переменных, если нужно отобразить их не как обычный
текст.
Теперь мы
можем указать определенную часть текста и установить
формат независимо от самого текста. Также можно
настраивать высоту и ширину определенных фрагментов
текста, что позволяет лучше контролировать расположение
и структуру текста. Теперь текстовое поле может
интерпретироваться во многом аналогично фильму: отныне
можно динамически создавать текстовые поля,
устанавливать их позиции X
и Y, а также присваивать
им приемники, чтобы события происходили при изменении их
содержимого.
В этой
лекции мы будем работать с упражнениями, охватывающими
большой спектр вопросов. В первую очередь мы обратим
внимание на объекты textField
и textFormat, познакомимся
с их действием и с эффектами, которые можно достичь с их
помощью. Некоторые результаты будут полезны в
практическом применении. Другие упражнения помогут
проиллюстрировать возможности этих объектов. Затем мы
рассмотрим возможность определения ширины и высоты
текстового содержимого для создания динамических
текстовых эффектов с нужным позиционированием без
применения дополнительных средств.
Создание ваших
собственных текстовых эффектов
Первым
эффектом, который мы рассмотрим, является стандартный
эффект пишущей машинки, заключающийся в том, что текст в
текстовом поле отображается так, будто он напечатан
вручную. Мы рассмотрим два различных способа создания
эффекта пишущей машинки. Прежде всего, мы изучим
основные принципы работы данного эффекта.
Нам нужно,
чтобы с каждым кадром в текстовом поле появлялась все
большая часть строки текста. Этого можно добиться, введя
переменную-счетчик и увеличивая ее значение с каждым
кадром, и затем располагать текст в текстовом поле,
используя этот счетчик для задания длины текста в каждом
новом кадре. Во Flash 5 мы могли бы отображать текст в
текстовом поле, присваивая ему переменную. Каждый раз
при обновлении этой переменной текстовое поле также
обновлялось бы соответствующим образом. Во Flash MX
текстовое поле является объектом с параметром
text. Чтобы текст
отображался в текстовом поле, нам нужно присвоить
фрагмент текста параметру text
текстового поля.
Имейте в
виду, что все еще можно добавить переменную текстовому
полю (Var). Мы не будем использовать этот метод, так как,
скорее всего, эта возможность была сохранена лишь для
обеспечения корректной работы с файлами, созданными во
Flash 5.
Создание эффекта
пишущей машинки
- Откройте новый
файл Flash и расположите текстовое поле на позиции
(217,113). Теперь перетащите кнопку текстового поля,
чтобы изменить размер поля примерно на 360 пикселей
в ширину и на 150 в высоту.
Всегда
лучше изменять размер динамических текстовых полей,
перетаскивая кнопку текстового поля. Если изменить
размер текстового поля, указав значения W и H в
Property inspector, текст будет искаженным.
- Выберите шрифт
Verdana, размер шрифта 9 и черный цвет. Установите
параметр текстового поля Dynamic Text, затем в
ниспадающем списке Line Type выберите Multiline.
Убедитесь в том, что опция Selectable не отмечена.
(Selectable является опцией, определяющей, может ли
пользователь делать изменения в тексте при просмотре
фильма.) Назовите инстанс текстового поля
tf_txt. Окно Property
inspector должно выглядеть примерно следующим
образом:
- Теперь создайте
новый слой scripts и
введите следующий ActionScript в кадре 1. Прежде
всего мы присвоим текстовому полю некоторый текст:
tf_txt.text = "When a
vibrating source of waves is
approaching an observer, the frequency observed is higher
than the frequency emitted by the source. When the source is
receding, the observed frequency is lower than that emitted.
This is known as the Doppler effect, or Doppler's principle.";
- Запустив фильм,
вы увидите, что Flash расположил текст внутри нашего
текстового поля. На данном этапе имеет смысл выбрать
команду меню Debug > List Variables и выяснить, в
каком состоянии находится текстовое поле. В окне
Output вы увидите примерно следующее:
Это
дает нам исчерпывающее представление о том, что
происходит с текстовым полем. Каждое динамическое
текстовое поле или текстовое поле ввода, размещенное
на рабочем месте, имеет параметры и свойства,
которые могут изменяться во время выполнения.
- До сих пор мы
выводили весь текст одновременно, а теперь нам нужно,
чтобы он отображался посимвольно с каждым кадром.
Чтобы добиться этого эффекта, возьмем наш фрагмент
текста и присвоим его переменной вместо параметра
текстового поля text.
Просто замените tf_txt.text
на text_str:
text_str="When a vibrating
source...
Теперь
мы создадим функцию
enterFrame для добавления символов в
текстовое поле один за другим с использованием
метода substr объекта
строки. Этот метод передает два аргумента - один из
них позволяет указывать стартовую позицию, а другой
указывает число символов. Затем метод получает
фрагмент строки. Итак, имея в виду текстовую строку,
рассмотренную выше, обратимся к следующему
ActionScript:
Text_str.substr (0, 6);
Это
выражение будет получать фрагмент "When a", т.е.
первые шесть символов строки. При реализации эффекта
пишущей машинки первый передаваемый аргумент будет
всегда равен нулю, так как текст должен отображаться
с начала строки, в то время как второй аргумент (длина
полученной строки) будет увеличиваться с каждым
разом, отображая все больший фрагмент строки.
- Введите следующий
ActionScript под имеющимся в слое
scripts кодом:
this.onEnterFrame =
function() {
// assign the portion of the string from 0 to
count to the
// textField.
tf_txt.text = text_str.substr(0, count);
count += 2;
};
- Сохраните ваш
фильм в файле
typeWriter001.fla и запустите его. Вы можете
ускорить появление текста, увеличив число, на
которое возрастает значение
count в каждом кадре. Одним из неприятных
побочных эффектов является некорректный перенос. Мы
можем обойти этот недостаток, вставив в текстовую
строку символы новой строки (\n):
text_str="When a vibrating
source of waves is approaching
an observer, the frequency observed is higher
than nthe frequency emitted by the source.
When the source is receding, the observed
frequency is lower than
that emitted. This is known as the Doppler
effect,
or Doppler's principle."
- Сохраните ваш
файл под именем
typeWriter001b.fla. Запустив его, вы увидите,
что текст появляется в новой строке, начиная с того
места, в которое вы добавили символ
\n.
Несмотря на
то, что этот эффект работает как надо, он далеко не
идеален, так как он никогда не перестает выполняться:
счетчик будет продолжать свое действие до бесконечности.
Кроме этого, мы настроили функцию
onEnterFrame в корневом уровне на управление
эффектом. Гораздо лучше доверить тексту самостоятельное
управление самим собой.
В идеале
нам нужно уже настроенное текстовое поле, тогда мы бы
просто указывали
myTextField.typeIn (некоторый текст для ввода) и
позволяли ему выполнять нужное действие. В предыдущих
версиях Flash это можно было сделать посредством
настройки функции onEnterFrame,
или используя внутренний управляющий фильм, который
выполнял бы нужные действия. У объекта
textField, к сожалению,
нет управляющего элемента
onEnterFrame, поэтому нам следует использовать
иной подход.
Мы будем
использовать метод setInterval.
Он позволяет повторять указанную функцию через каждое
определенное количество миллисекунд. setInterval
непосредственно связан с частотой кадров фильма. Давайте
рассмотрим несложный пример того, как работает данный
метод.
Повторение указанных
функций с помощью setInterval
Сейчас мы
будем анимировать два фильма. Один из них будет
использовать onEnterFrame,
а другой - метод setInterval.
- Откройте новый
файл Flash и установите частоту кадров на значение
20.
- Нарисуйте
изображение и преобразуйте его в фильм - в нашем
примере мы нарисовали небольшой шарик. Расположите
два инстанса объекта на рабочем месте и назовите
один из них obja_mc, а
другой obja2_mc.
- Теперь добавьте
слой scripts в главную
временную диаграмму и введите следующий код (мы
будем создавать одну функцию для работы с
onEnterFrame и другую
для запуска под управлением
setInterval).
_root.onEnterFrame =
function() {
obja_mc._x++;
trace("on enter frame");
};
function inter() {
obja2_mc._x++;
trace("interval function");
}
setInterval(inter, 50);
Здесь
мы использовали setInterval
с двумя аргументами: вызываемой функции и интервала
между вызовами. Функция inter
будет вызываться каждые 50 миллисекунд. Мы выбрали
значение 50 миллисекунд, так как оно будет
соответствовать частоте смены кадров - в секунде
1000 миллисекунд, а наш фильм обновляется 20 раз в
секунду, или один раз за 50 миллисекунд.
- Сохраните ваш
файл под именем
setInterval1.fla. Запустив его, вы заметите,
что шарики двигаются примерно с одинаковой скоростью,
однако расстояние между ними сильно увеличивается по
мере их движения на экране.
Два
объекта должны оставаться синхронизированными,
однако если обратить внимание на содержимое окна
Output, то станет видно, что on
enter frame и
interval function
изменяются, как положено, несмотря на то, что каждый
второй инстанс interval
function указывается дважды в строке.
Чтобы
увидеть, как изменяется инстанс, введите этот код в
одной из функций; это покажет расстояние между двумя
фильмами:
trace
(obja2_mc._x-obja_mc._x);
Расстояние между ними не остается постоянным. Однако
изменение интервала на 51 или 49 не имеет значения:
в одном случае obja_mc
движется быстрее, в то время как
obja2_mc движется
быстрее в другом. Функция
setInterval работает и весьма полезна, однако
если мы хотим, чтобы наши события были идеально
синхронизированы, то для управления движением лучше
использовать либо
onEnterFrame, либо
setInterval, но не использовать их вместе.
Если точная синхронизация не критична для
определенного приложения, тогда можно использовать
оба подхода.
- Чтобы наглядно
рассмотреть еще один момент, установите частоту
кадров на значение 1. Теперь функция интервалов
вызывается каждые 50 миллисекунд, однако рабочее
место обновляется лишь один раз в 1000 миллисекунд.
Запустив ваш фильм, вы обнаружите, что при
обновлении рабочего места
obja_mc каждую секунду перемещается на 1
пиксель, а obja2_mc
двигается на 10 или 11 пикселей, так как функция
setInterval вызывалась
10 или 11 раз между обновлениями рабочего места.
- Замените код в
слое scripts следующим
кодом и сохраните ваш файл под именем
setInterval2.fla. Мы
будем использовать его для принудительного
обновления рабочего места с использованием
updateAfterEvent().
_root.onEnterFrame =
function() {
trace("on enter frame");
obja_mc._x++;
trace(obja2_mc._x);
};
function inter() {
obja2_mc._x += 3;
trace("interval function called");
updateAfterEvent();
}
setInterval(inter, 30);
updateAfterEvent
является методом, вызываемым для обновления рабочего
места независимо от частоты кадров. Он будет
работать только как часть управляющего элемента
clipEvent или внутри
функции, присвоенной
setInterval. Этот метод чаще всего
используется для реализации более плавного
перетаскивания при работе с перетаскиваемыми
объектами. В нашем случае, мы используем его в
управляющем элементе
onMouseMove таким образом, что новое
расположение перемещаемого объекта отображается
немедленно, а не в начале следующего кадра.
Рекомендуется быть осторожным и не использовать этот
метод слишком много, так как вы можете видеть,
насколько движение прерывисто при использовании его
с setInterval. Для
сравнения верните частоту кадров обратно на значение
30, и вы увидите, в чем заключается разница. В
конечном счете, правильным решением будет не
пытаться и не принуждать
setInterval выполняться быстрее частоты смены
кадров (несмотря на то, что это возможно). Flash
позволяет использовать эту возможность, однако это
не повод пользоваться ею при всяком удобном случае.
Динамическое создание
текстового поля
Теперь мы
знакомы с работой setInterval
и можем применить этот подход для изменения нашего
эффекта пишущей машинки. На этот раз, вместо
расположения текстового поля на рабочем месте вручную,
мы будем создавать его динамически.
Для этого
мы используем метод createTextField.
this.createTextField
("tf_txt", 1, 50, 50, 360, 150);
Аргументы
в скобках указывают имя, глубину,
X, Y, ширину и
высоту нового текстового поля. Это создаст стандартное
текстовое поле со шрифтом, размером и т.д. по умолчанию.
Теперь нам нужно включить перенос слов и запретить
выделение текстового поля:
tf_txt.wordWrap = true;
tf_txt.selectable = false;
Затем мы
создаем наш собственный объект
textFormat для применения выбранных атрибутов
текстового поля. Сделать это можно двумя способами.
Одним из них является создание нового объекта
textFormat и затем
присвоение ему нужных параметров с помощью следующего
ActionScript.
myTform = new textFormat() ;
// set properties of textFormat object
myTform.font = "Verdana";
myTform.size = 9;
myTform.color = 0xff3300;
Второй
подход заключается в передаче параметров в виде
аргументов при создании объекта. Этот способ более
компактен, но гораздо более сложен, так как он требует
знания порядка, в котором аргументы будут передаваться.
Ниже приведен порядок передачи параметров.
new textFormat(font, size,
color, bold, italic, underline,
Кurl, target, align, leftMargin, rightMargin,
indent, leading) ;
Несмотря
на то, что все эти аргументы необязательны, для того,
чтобы установить какой-либо определенный параметр, нужно
включить все аргументы, которые ему предшествуют. Если
нам нужно опустить какие-либо из этих аргументов, то
необходимо передать методу значение
null. Например, если нам
нужно присвоить шрифту наклонное начертание, но не
жирное, то следует написать следующий код:
new textFormat ("Arial", 10,
0xff0000, null, true);
Таким
образом, для textFormat
имеем:
myTform = new textFormat
("Verdana", 9, 0xff3300);
Наконец,
применяем объект textFormat
к объекту текстового поля:
tf_txt.setNewTextFormat (myTform);
Обратите
внимание, что мы использовали
setNewTextFormat вместо
setTextFormat, так как последний влияет лишь на
символы, уже имеющиеся в текстовом поле, однако не на
вводимые в него символы. Для демонстрации результата
добавьте в конец вашего ActionScript следующий код:
tf_txt.text = "quick test";
Если вы
используете setNewTextFormat,
то текст будет отображаться красным цветом и шрифтом
Verdana; если был использован
setTextFormat, то символы будут черного цвета
шрифтом Times New Roman.
Итак,
приведем полный код для создания нашего текстового поля,
настроенный, как необходимо:
this.createTextField("tf_txt",
1, 50, 50, 360, 150);
tf_txt. wordWrap = true;
tf_txt.selectable = false;
myTform = new textFormat("Verdana", 9, Oxff3300);
// apply the textFormat to the textField
tf_txt.setNewTextFormat(myTform);
Довольно
сложно было добиться нужного результата, не правда ли? В
большинстве случаев намного проще всего лишь
перетаскивать текстовое поле на рабочее место и
настраивать параметры с помощью Property inspector.
Однако рекомендуется знать, как все это работает, так
как может возникнуть ситуация, в которой эти знания
очень вам пригодятся. Даже в этом случае мы можем
установить точный размер текста, несмотря на то, что мы
могли бы просто ввести следующий код:
tf_txt._width = 360;
tf_txt._height = 150;
Ввод текста
Мы
достигли нужного результата, и теперь будем использовать
его для создания следующего эффекта. Перед созданием
функции мы создадим ее вызов.
- Возьмите первые
пять строк кода из предыдущего упражнения и введите
под ними следующий код. Здесь сначала объявляется
переменная для записи нашей строки, а затем идет
вызов функции для ввода строки в текстовое поле:
text_str = "vWhen a
vibrating source of waves is approaching an
observer, the frequency observed is higher than the
frequency emitted by the source. When the source is
receding, the observed frequency is lower than that emitted.
This is known as the Doppler effect, or Doppler's principle." ;
this.tf_txt.typeIn(text_str);
- Здесь нам
понадобится функция typeIn
в качестве метода объекта
textField. Есть два способа определения
функции: посредством присвоения ее свойству объекта
tf_txt.typeIn =
function(texta) {
//etc. etc.
};
или внутри TextField.prototype:
TextField.prototype.typeln = function(texta) {
//etc. etc.
};
В
первом методе каждое текстовое поле, к которому мы
хотим применить функцию, должно иметь функцию,
определенную для нее индивидуально, тогда как во
втором подходе метод будет доступен для всех
инстансов объекта TextField,
что, возможно, предпочтительнее, так как позволяет
нам использовать его для любого текстового поля без
изменения кода.
- Теперь, когда мы
выяснили, где будет располагаться функция в корневой
временной диаграмме, нужно решить, какие именно
действия она будет выполнять. Вообще говоря, ее
функции будут такими же, как и ранее. Мы будем
использовать аргумент texta,
передаваемый функции, и записывать его в текстовое
поле. Затем мы будем постепенно прибавлять символы к
параметру текста нашего текстового поля до тех пор,
пока текст не будет таким же, как
texta. Итак, прежде
всего, запишем текст в поле
TextField. Для этого добавим следующий код
вверху имеющейся программы.
TextField.prototype.typeln
= function(texta) {
this.texta = texta;
};
- Затем нам нужно
создать функцию, которая будет выполняться через
определенные интервалы времени для увеличения
переменной-счетчика и соответствующего изменения
текстового параметра:
TextField.prototype.typeln
= function(texta) {
this.texta = texta;
this.controlType = function() {
this.count++;
this.text = this.texta.substr(0, this.count);
};
};
Это
аналогично тому, с чем мы имели дело ранее - здесь к
счетчику прибавляется единица и полученное значение
используется для извлечения текстового фрагмента из
this.texta с помощью
метода substr.
- Все, что сейчас
нам требуется добавить, это
setInterval для повторения этой командой
самой себя. Ранее, когда мы использовали
setInterval, мы просто
указывали имя функции для вызова. Теперь нам нужно
указать имя метода и ссылку на объект, для которого
нужно вызвать метод:
setInterval (this, "controlType",
30);
Ниже
приведен окончательный код программы:
TextField.prototype.typeln
= function(texta) {
this.texta = texta;
this.controlType = function() {
this.count++;
this.text = this.texta.substr(0, this.count);
};
// call the controlType function every 30 milliseconds
setInterval(this, "controlType", 30);
};
this.createTextField("tf_txt", 1, 50, 50, 300,
150);
tf_txt. wordWrap = true;
tf_txt .selectable = false;
myTform = new textFormat("Verdana" , 9,
0xff3300);
tf_txt.setNewTextFormat(myTform);
text_str = "When a vibrating source of waves is
approaching an
Кobserver, the frequency observed is higher
than the frequency emitted
Кby the source. When the source is receding,
the observed frequency is
Кlower than that emitted. This is known as the
Doppler effect,
or Doppler's principle.";
// initialize typeIn effect
this.tf_txt.typeIn(text_str);
- Сохраните ваш
файл под именем
typeWriter002.fla и запустите его. Вы будете
наблюдать тот же результат, что и в предыдущих
примерах, однако на этот раз текстовое поле будет
добавляться динамически.
Разделение метода на
инициализацию и управление
Сначала
отменим переопределение функции
controlType при каждом вызове метода
typeIn. Вместо этого можно
было бы разделить наш метод на два отдельных метода -
один для инициализации ввода, а другой для управления
им:
TextField.prototype.typeIn =
function(texta) {
this.count = 0;
this.texta = texta;
setInterval(this, "controlType", 30);
};
TextField.prototype.controlType = function() {
this.count++;
this.text = this.texta.substr(0, this.count);
};
Сохраните
этот файл под именем
typeWriter003.fla. Он не так компактен, как
предыдущий, так как содержит две функции вместо одной,
но зато в нем легче разобраться. Однако мы еще не
предпринимали никаких действий для остановки функции,
поэтому это будет нашим следующим шагом.
Завершение работы функции
Функция,
настроенная с помощью setInterval,
будет вызываться до тех пор, пока для нее не будет
вызыван clearInterval.
Когда setInterval
вызывается первый раз, он возвращает идентификационный
номер, который вы должны использовать следующий раз при
обнулении интервала. До сих пор мы не использовали эту
возможность, однако теперь настало время этим заняться.
В этом
упражнении у нас будет текстовое поле, добавленное
вручную.
- Чтобы установить
интервал, добавим следующий выделенный код:
TextField.prototype.typeIn
= function(texta) {
this.count = 0;
this.texta = texta;
this.myTypelD = setInterval(this, "controlType", 30);
};
- Для обнуления
интервала и прекращения вызова функции таймером
интервалов добавим следующее выражение:
clearInterval (this.myTypeID);
- Теперь добавим
другой метод - typeDone,
который будет обнулять вызов функции и затем удалять
все временные переменные, которые были использованы:
TextField. prototype.
typeDone = function() {
delete this.count;
delete this.texta;
// clear the interval that calls controlType
clearInterval(this.myTypeID);
delete this.myTypelD;
};
- Затем нам нужно
добавить вызов этой функции, который будет
действовать по достижении переменной
count длины
texta:
TextField. prototype.
controlType = function() {
this.count++;
this.text = this.texta.substr(0, this.count);
// if we reach the end of the string call typeDone
if (this.count>=this.texta.length) {
this.typeDone();
}
};
- Последним штрихом
для ActionScript в
этом примере будет текст, который должен
отображаться:
text_str = "When a
vibrating...
// rest of text goes here
... or Doppler's principle.";
this.tf_txt.typeln(text_str);
- Сохраните ваш
фильм в файле
typeWriter004.fla и запустите его. Если вы
выберете Debug > List
Variables по окончании ввода, то увидите, что
не осталось ни одной переменной или в объекте
текстового поля вообще ничего не содержится. Вы
могли бы добавить trace-выражение в функцию
controlType, чтобы
знать, когда действие завершается.
Дополнения к эффекту ввода
текста
Приведем
еще два дополнения для нашего набора функций.
- Прежде всего, мы
можем добавить дополнительные параметры для вызова
функции typeIn,
расположенной в последней строке нашего ActionScript.
Можно передавать ей количество символов,
появляющихся в каждом кадре, а также частоту
выполнения setInterval.
this.tf_txt.typeIn(text_str, 3, 30);
Итак,
в каждом кадре будут добавляться 3 символа, а
функция будет вызываться каждые 30 миллисекунд.
Теперь нам нужно добавить эти параметры в функцию
typeIn.
TextField.prototype.typeIn
=
function(texta, typeSpeed, interval) {
this.count = 0;
// store the typeSpeed inside the textField
this.typeSpeed = typeSpeed;
this.texta = texta;
this.myTypeID = setInterval(this, "controlType", interval);
};
- Теперь изменим
функцию typeControl,
чтобы применить переменную
typeSpeed:
TextField.prototype.controlType =
function() {
// increase the amount of text displayed by typeSpeed
this.count += this.typeSpeed;
this.text = this.texta.substr(0, this.count);
if (this.count>=this.texta.length) {
this.typeDone();
}
};
- Наконец, удалим
дополнительную переменную в функции
typeDone:
TextField.prototype.typeDone = function() {
delete this.count;
delete this.texta;
delete this.typeSpeed;
clearInterval(this.myTypeID);
delete this.myTypeID;
};
- Сохраните файл
под именем typeWriter005.fla.
Мы можем легко изменить работу функции
typeIn, просто передав
ей различные значения. Можете попробовать:
this.tf_txt.typeIn(tex,
30, 60);
или
this.tf_txt.typeIn(tex,
30, 30);
- По существу, нам
нужно контролировать действие эффекта ввода текста,
не внедряясь в функцию и не изменяя внутреннего кода.
Это сделает наш метод намного более гибким и мощным.
Добавление функции обратной
связи
Теперь
обеспечим возможность обратной связи с функцией при
завершении работы эффекта ввода текста. Для этого нужно
добавить еще два параметра в функцию, которые мы
расположим в конце, чтобы не применять обратную связь,
если нам это не будет требоваться.
- Добавим новые
параметры в функцию typeIn.
TextField.prototype.typeIn
=
function(texta, typeSpeed, interval, obja, func) {
this.obja = obja;
this.func = func;
this.count = 0;
this.typeSpeed = typeSpeed;
this.texta = texta;
this.myTypelD = setInterval(this, "controlType", interval);
};
- Итак, здесь мы
добавили две новые переменные -
obja и
func. Нам нужно
вызывать их по окончании ввода текста, поэтому мы
добавили их в функцию
typeDone.
TextField.prototype.typeDone = function() {
delete this.count;
delete this.texta;
delete this.typeSpeed;
clearInterval(this.myTypeID);
delete this.myTypeID;
// execute callback function
this.obja[this.func]();
delete this.obja;
delete this.func;
};
- Для проверки нам
понадобится создать функцию для получения обратного
вызова и затем изменить наш исходный вызов. Введите
этот код под имеющимися функциями.
function allDone() {
trace("type done");
}
- Наконец, нам
нужно передать некоторые дополнительные значения
функции typeIn.
Добавьте следующий выделенный код в последнюю строку
ActionScript:
this.tf_txt.typeIn (text_str,
1, 30, _root, "allDone");
- 5. Сохраните
фильм в файле
typeWriter006.fla. При выполнении фильма в
окне Output появятся слова
type done, так как по окончании ввода была
вызвана функция allDone.
О прототипах
При
добавлении функций или параметров в прототипы объектов,
необходимо быть осторожным. Если используется цикл
for:in для нумерации
параметров и методов объекта, на первый план выйдут
новые методы и параметры объекта. В качестве примера
рассмотрим следующий код:
_root.createEmptyMovieClip("blah",
1);
blah.myVariable = 20;
for (var i in blah) {
trace(i+" : "+blah[i]);
}
Протокол
выполнения этой процедуры в окне Output отобразит
"myVariable : 20". Теперь, если мы добавим функцию в
прототип Movieclip, которая так же будет выделена в
отдельном инстансе фильма:
MovieClip.prototype.yada =
function() {
};
_root.createEmptyMovieClip("blah", 1);
blah.myVariable = 20;
for (var i in blah) {
trace(i+" : "+blah[i]);
}
протокол
будет содержать следующее:
yada : [type Function]
myVariable : 20
Функция
yada, которую мы
определили для всех фильмов, выводится в инстансе
blah. Нет оснований
считать это проблемой, особенно когда мы ожидаем данное
действие. Однако в определенных ситуациях это может
стать проблемой, например, если вы используете еще
какой-либо код, повторяющий применение параметров и
методов MovieClip, и
ожидаете определенного результата.
Чтобы
предотвратить эти нежелательные последствия, можно
использовать метод AsSetPropFlags.
Он официально не поддерживается в ActionScript, поэтому
лучше на него все же не надеяться, однако он позволяет
"скрыть" любые дополнительные параметры или методы,
добавленные в цикле for:in.
Вызываем метод AsSetPropFlags,
передаем ему имя объекта, параметр которого необходимо
скрыть, имя параметра или метода и число 1:
AsSetPropFlags (MovieClip.prototype,
"yada", 1);
Итак, если
мы теперь поместим этот код в нашу предыдущую программу
и выполним ее, метод yada
больше не будет отображаться циклом:
MovieClip. prototype. yada =
function() {
};
ASSetPropFlags(MovieClip.prototype, "yada", 1);
_root.createEmptyMovieClip("blah", 1);
blah.myVariable = 20;
for (var i in blah) {
trace (i+" : "+blah[i]);
}
Это
лишь один из результатов, который может быть получен с
помощью AsSetPropFlags.
Также можно защитить параметры от перезаписи и
осуществлять многие подобные действия. За более
подробной информацией обратитесь к странице
http://chattyfig.figleaf.com/flashcoders-wiki/index.php?ASSetPropFlags.
Работа с объектом
textFormat
Теперь мы
собираемся задействовать объект
textFormat на базе полученных до сих пор знаний.
Мы упоминали ранее, что объект
textFormat можно использовать для изменения
форматирования определенных фрагментов текста, и теперь
мы сделаем так, чтобы это действие выполнялось
посимвольно, а не изменяло весь текст одновременно.
Затем мы, используя этот метод, сделаем шаг вперед и
создадим функцию, которая выбирает все вхождения
определенного слова и отображает их в другом формате,
большим размером и другим цветом.
Использование
setTextFormat
Начнем с
краткого изучения использования
setTextFormat как такового. Как уже было
упомянуто ранее, объект textFormat содержит все данные
форматирования для текстового поля. Даже если мы не
укажем объект textFormat
для текстового поля, у него есть такой объект по
умолчанию, и он может быть вызван с помощью выражения
TextField.getTextFormat ().
Когда мы прежде работали с
textFormat, мы использовали его для применения
форматирования ко всему объекту
textField. Теперь мы будем использовать его для
форматирования определенного фрагмента текстового поля.
- Откройте новый
фильм и создайте текстовое поле, как в предыдущих
примерах.
В
данном текстовом поле установите красный цвет текста
и дайте имя инстансу в Property inspector (tf_txt).
- Нам нужно
выделить определенный фрагмент текста, поэтому
сначала необходимо определить этот фрагмент и его
форматирование. Добавьте новый слой
scripts и в первом
кадре введите следующий код.
this.tf_txt.text = "The
eidophor system is
a projection television system,
i.e. it enables Кenlarged television pictures to
be projected
on to a screen.
An ordinary television picture Кderives its
brightness
from the fluorescence of
a screen bombarded by electrons;
with Кthe eidophor system, on the other hand,
a very powerful source of light is controlled by
Кthe television signal
picked up by the receiver." ;
// create textFormat object
myForm = new TextFormat() ;
myForm.color = 0x00000;
myForm.font = "Verdana";
myForm.size = 9;
- Итак, мы создали
объект textFormat с
именем myForm. Теперь применим его к текстовому полю.
Давайте остановимся на слове "eidophor", первый
символ которого стоит на 4 позиции, а последний - на
12-й. Мы передадим эти два значения в качестве
аргументов, а также объект
myForm, методу
setTextFormat. Добавьте следующую строку кода
под уже имеющимся кодом.
// apply textformat to
characters 4 to 12
this.tf_txt.setTextFormat(4, 12, myForm);
- Сохраните фильм в
файле setTextFormat.fla.
При его запуске вы увидите слово "eidophor",
выделенное черным цветом. Любые изменения в объекте
textFormat будут
отображены в тексте. Например, если вы добавите
следующее выражение над строкой
setTextFormat, наше
слово будет выделено черным жирным шрифтом:
myform.bold = true;
Полезно знать, что если объект
textFormat не имеет
определенного свойства при применении к объекту
textField, он будет
использовать уже присутствующее значение. Проверим
это.
- Замените весь код
textFormat на
следующее:
myForm = new TextFormat
();
myForm.color = 0x000000;
Здесь
нет никакой информации о шрифте или его размере,
однако при применении к текстовому полю используется
уже имеющееся форматирование (Verdana, 9 пикселей).
При запуске фильма, если вы выберете команду
Debug > List Variables,
то увидите, что объект myForm
содержит большое количество переменных со значением
null.
Когда
объект textFormat
применяется с использованием
textField.setTextFormat, все эти null-значения
просто отбрасываются и заменяются уже имеющимися
значениями.
- Добавьте
следующую строку кода. Мы будем использовать метод
getTextFormat, чтобы
передать textFormat
фрагмент текста.
// retrieve the textFormat
for characters 4 to 12 in the text field
post = this.tf_txt.getTextFormat(4, 12);
- Сохраните фильм в
файле setTextFormat(post).fla,
запустите его и выберите
Debug > List Variables, и вы увидите, что все
переменные присутствуют в post, даже те, которые мы
не устанавливали в myForm.
Теперь
у вас есть представление о том, как использовать
setTextFormat, и можно
приступить к созданию метода для постепенного
изменения textFormat.
Мы будем делать это во многом аналогично тому, как
поступали с функцией typeID.
Мы передадим функции число параметров, включая
объект textFormat,
точку начала, конечную точку, скорость и интервал.
Мы также настроим ее на работу с функцией обратной
связи, которую применим во второй части данного
примера.
- Вызов функции
будет выглядеть так. Добавьте эту строку внизу
ActionScript, под строками кода
myForm.
this.tf_txt.nooTextFormat
(myForm, 4, 11, 1, 30);
Теперь
ваш ActionScript будет выглядеть следующим образом.
this.tf_txt.text = "The
eidophor system...by the receiver.";
myForm = new TextFormat();
myForm.color = 0x000000;
this.tf_txt.nooTextFormat(myForm, 25, 43, 1,
30);
- Основное ядро
функции вам знакомо, так как вы уже встречались с
такой конструкцией. Добавьте следующий ActionScript
над имеющимся кодом (мы добавим оставшуюся часть
кода для nooTextFormatControl
и cleanNooTextFormat
одновременно).
TextField.prototype.nooTextFormat =
function(tForm, begin, end, speed, interval,
Кobja, func) {
// store parameters in text field
this.begin = this.current= begin;
this.end = end+1;
this.speed = speed;
this.end = end;
this.obja = obja;
this.func = func;
this.nooTform = tForm;
// set interval to call nooTextFormatControl
this.myNooText = setlnterval
(this, "nooTextFormatControl", interval) ;
};
TextField.prototype.nooTextFormatControl =
function() {
};
TextField.prototype.cleanNooTextFormat =
function() {
};
Мы
делаем то же самое, что и раньше - берем все копии
всех аргументов, передаваемых в аргумент, и помещаем
их в само текстовое поле. Мы приравниваем
this.end к end+1, так
как второй аргумент, передаваемый
setTextFormat,
ссылается на символ после последнего символа, к
которому применен другой формат, тогда как
передаваемое нами значение ссылается на последний
символ, формат которого мы хотим изменить.
В
функции управления
nooTextFormatControl мы будем пошагово
прибавлять значение переменной
this.current и
увеличивать строку текста, к которой применяется
textFormat. Мы
начинаем current со
значения begin и
продолжаем увеличивать его до тех пор, пока оно не
достигнет значения end.
- Добавьте
следующий выделенный код в nooTextFormatControl.
TextField.prototype.nooTextFormatControl =
function() {
this.current + = this.speed;
if (this.current>this.end) {
this.setTextFormat(this.begin, this.end, this.nooTform);
this. cleanNooTextFormat () ;
} else {
this.setTextFormat(this.begin, this.current, this.nooTform);
}
};
При
каждом вызове функции мы добавляем
speed к значению
переменной current.
Если это значение меньше, чем конец области, на
которую мы хотим оказать влияние, то мы меняем
значение textFormat с
begin на
current. Если оно
является конечной точкой или близко к ней по
значению (в случае, если мы с каждым кадром
прибавляем к current 3 или 4), то мы применяем
формат к тексту с использованием начального и
конечного значений, переданных в начале, и вызываем
функцию cleanUp.
- Последнее, что мы
сделаем, это добавим следующий выделенный код в
cleanNooTextFormat.
TextField.prototype.cleanNooTextFormat =
function() {
delete this.current;
delete this.nooTform;
delete this.begin;
delete this.end;
clearInterval(this.myNooText);
delete this.myNooText;
this.obja[this.func] ();
};
- Сохраните новый
файл под именем
switchTextFormat1.fla. Как и раньше, эта
функция удаляет все неиспользуемые переменные или
свойства.
Применение данного
подхода
Рассмотрим
применение только что изученного нами подхода на
практике. Мы напишем небольшое приложение, которое будет
находить все вхождения определенного фрагмента текста
внутри текста большего объема, и выделять их по очереди.
Здесь вы поймете значение функций обратной связи.
Для начала
нам понадобится функция для просмотра текста и
возвращения позиций указанной нами строки. Так как эта
функция будет работать со строками, нам нужно создать ее
в виде метода объекта строкового типа. Функция
findInstances выглядит так.
myString.findInstances (str);
Чтобы
найти вхождение строки внутри другой строки, можно
использовать indexOf. Сама
по себе indexOf выглядит
так:
var pos = myString.indexOf (str);
Функция
indexOf возвращает
номер-индекс первого вхождения
str. Теперь нам нужно найти каждое вхождение
str, и для этого можно
применить другой способ использования
indexOf, где указывается
номер-индекс, с которого следует начать просмотр:
var pos = myString.indexOf (str,
startIndex);
В этой
функции должен быть цикл. По нахождении первого
вхождения строки, она будет брать номер-индекс первого
найденного вхождения str и
использовать его в качестве точки начала следующей
операции indexOf. Цикл
будет повторяться до тех пор, пока не будут найдены все
вхождения str, после чего
indexOf возвратит значение
-1. Цикл закончит свою работу и возвратит массив
найденных значений.
String.prototype.findInstances
= function(str) {
var foundAt = [];
var nextFound = 0;
// while there are still instances of the string
while (nextFound != -1) {
nextFound = this.indexOf(smallStr, nextFound);
if (nextFound != -1) {
foundAt.push({begin:nextFound,
end:nextFound+str.length});
nextFound++;
}
}
// return the array of beginning and end values
return foundAt;
};
Разберем
каждую строку этого кода. Сначала мы устанавливаем
currIndex на ноль, т.е. на
ту позицию, с которой начинается поиск. Далее создаем
массив foundAt для
добавления в него всех значений, которые нужно
возвратить. Затем объявляется переменная
nextFound для записи
возвращаемого значения. При этом используется слово
var для указания того, что
переменная должна существовать только во время
выполнения функции.
Для
настройки цикла используется выражение
while(nextFound!=-1), так
как нам нужно, чтобы цикл завершал работу, когда больше
не может быть найдено ни одно вхождение строки. Первая
строка цикла дает нам номер-индекс следующего вхождения
строки поиска в более объемной строке, после точки,
указываемой currIndex.
nextFound = this.indexOf (str,
currIndex);
Если
значением nextFound не
является -1, это означает, что найдено вхождение строки,
и выражения, включенные в условие, будут выполнены.
Будет добавлено следующее вхождение строки и увеличено
значение nextFound, после
чего продолжится выполнение следующего кода:
if (nextFound != -1) {
foundAt.push({begin:nextFound, end:nextFound+smallStr.length});
nextFound++;
}
Мы
интерпретируем это как объект, содержащий начальное и
конечное значения, поэтому можно указать начальную и
конечную точки для фрагмента текста.
foundAt.push
({begin:nextFound, end:nextFound+str.length});
Если
больше не найдено вхождений строки поиска,
nextFound принимает
значение -1 и цикл while
прекращает свою работу. После этого возвращаются все
значения, которые были найдены, и выполнение функции
завершается.
return foundAt;
Чтобы
опробовать этот метод, создадим новый файл. Добавьте
определенный нами метод над и под следующим текстом.
text_str="The eidophor system
is a projection television system,
i.e. it enables enlarged Кtelevision pictures
to be projected on to a screen.
An ordinary television picture derives its
brightness from the fluorescence of
a screen bombarded by electrons;
with the eidophor system, on the other hand,
a very powerful source of light is controlled by
the television signal
picked up by the receiver."
vals=text_str.findlnstances("television")
Выполнив
код и просмотрев переменные, вы увидите, что
vals содержит массив с
четырьмя объектами - по одному для каждого вхождения
слова "television", указанного в строке выше. Однако
чтобы этот метод работал при любых обстоятельствах,
необходимо внести в него некоторые изменения.
Преобразование строк
- С нашими текущими
настройками, если регистр (верхний/нижний) строки
поиска не соответствует вхождению в тексте, оно не
будет интерпретироваться как найденная строка. Чтобы
избежать этого, преобразуем обе строки перед
использованием в нижний регистр. Ниже приведены
дополнения в коде.
String.prototype.findlnstances = function(str) {
var foundAt = [] ;
var nextFound = 0;
// change both strings to lower case
var largeStr = this.toLowerCase();
var smallStr = str.toLowerCase();
while (nextFound!=-1) {
nextFound = largeStr.indexOf(smallStr, nextFound);
if (nextFound != -1) {
foundAt.push({begin:nextFound,
end:nextFound+smallStr.length});
nextFound++;
}
}
return foundAt;
};
Теперь
код будет работать при поиске любой строки внутри
любой более объемной строки.
- Открываем
switchTextFormat1.fla
и добавляем на рабочее место текстовое поле и три
функции: nooTextFormat,
nooTextFormatControl и
cleanNooTextFormat.
После этого добавляем метод
findInstances. Теперь создаем функции для
поиска вхождений строки и выделяем их. Сначала нам
понадобится функция для инициализации, которая будет
вызывать findInstances
и записывать результат в массив. После этого она
будет вызывать функцию doNext.
function
nooFindAndReplace(textObj, str) {
this.indices = textObj.text.findlnstances(str);
this.doNext();
}
doNext
будет использовать метод
shift массива для извлечения первой пары
индексов из массива indices и затем передавать их в
nooTextFormat. Мы
передаем doNext в виде
функции с обратной связью таким образом, что когда
формат одного слова изменится,
doNext будет вызвана
снова, и мы перейдем к следующему слову.
function doNext() {
// if there is another string
if (indices.length>0) {
var nexta = this.indices.shift();
this.tf_txt.nooTextFormat
(myForm, nexta.begin, nexta.end, 1, 30, this, "doNext");
}
}
- Наконец, мы
определяем строку, в которой будет осуществляться
поиск, и затем вызываем функцию.
this.tf_txt.text = "The
eidophor system is
a projection television system,
i.e. it enables enlarged television pictures
to be projected on to a screen.
An ordinary television picture derives
its brightness from the fluorescence of
a screen bombarded by electrons;
with the eidophor system, on the other hand,
a very powerful source of light is controlled
by the television signal
picked up by the receiver. " ;
myForm = this.tf_txt.getTextFormat() ;
myForm.color = 0x000000;
myForm.size = 9;
myForm. bold = true;
// trigger find and replace
nooFindAndReplace(this.tf_txt, "television",
myForm);
В
окончательном виде весь код будет выглядеть так.
В окончательном
виде весь код будет выглядеть так.
TextField.prototype.nooTextFormat =
function(tForm, begin, end, speed, interval,
obja, Кfunc) {
this.begin = this.current=begin;
this.end = end+1;
this.speed = speed;
this.end = end;
this.obja = obja;
this.func = func;
this.nooTform = tForm;
this.myNooText = setlnterval(this, "nooTextFormatControl", interval);
};
TextField.prototype.nooTextFormatControl =
function() {
this.current += this.speed;
if (this.current>this.end) {
this.setTextFormat(this.begin, this.end, this.nooTform);
this.cleanNooTextFormat();
} else {
this.setTextFormat(this.begin, this.current, this.nooTform);
}
};
TextField.prototype.cleanNooTextFormat =
function() {
delete this.current;
delete this.nooTform;
delete this.begin;
delete this.end;
clearlnterval(this.myNooText);
delete this.myNooText;
this.obja[this.func]();
};
String.prototype.findlnstances = function(str) {
var foundAt = [] ;
var nextFound = 0;
var largeStr = this.toLowerCase();
var smallStr = str.toLowerCase();
while (nextFound!= -1) {
nextFound = largeStr.indexOf(smallStr, nextFound);
if (nextFound != -1) {
foundAt.push({begin:nextFound,
end:nextFound+smallStr.length});
nextFound++;
}
}
return foundAt;
};
function nooFindAndReplace(textObj, str) {
this.indices = textObj.text.findlnstances(str) ;
this.doNext();
}
function doNext() {
if (indices.length>0) {
var nexta = this.indices.shift();
this.tf_txt.nooTextFormat(myForm, nexta.begin, nexta.end, 1,
30, this, "doNext");
}
}
this.tf_txt.text = "The eidophor system is a
projection television system, i.e. it enables
enlarged television pictures to be projected on
to a screen. An ordinary television picture
derives its brightness from the fluorescence of
a screen bombarded by electrons,- with the
eidophor system, on the other hand, a very
powerful source of light is controlled by the
television signal picked up by the receiver.";
myForm = this.tf_txt.getTextFormat();
myForm.color = 0x000000;
myForm.size = 9;
myForm.bold = true;
nooFindAndReplace(this.tf_txt, "television",
myForm);
Пример
2.1.
- Сохраните файл
под именем
switchTextFormat2.fla и запустите его. Вы
увидите четыре вхождения слова "television",
выделенные красным цветом.
The
eidophor system is a projection television system, i.e.
it enables enlarged television pictures to be projected
on to a screen. An ordinary television picture derives
its brightness from the fluorescence of a screen
bombarded by electrons; with the eidophor system, on the
other hand, a very powerful source of light is
controlled by the television signal picked up by the
receiver.
Используя
этот метод, можно добиться большого количества
разнообразных эффектов. Например, можно просто изменить
некоторые значения в объекте
textFormat, изменить скорость и т.д.
Существует
несколько менее значимых, но полезных дополнений к этому
подходу. Например, функция doNext
намеренно написана для отдельного объекта текстового
поля и textFormat. В
идеале, мы имели бы дело с объектами текста и формата
текста, передаваемыми ей в виде аргументов. Это можно
реализовать, передавая в начале значения текстовому
полю, и затем, когда каждое слово обработано, передавать
эти аргументы в doNext для
использования при ее следующем вызове. Мы не будем
тратить время на то, чтобы разбираться в этом сейчас,
однако в файле
switchTextFormat3.fla есть комментарии, которые
помогут вам уяснить все должным образом. По большому
счету, это просто расширение нашей функции обратной
связи для передачи аргументов.
Дополнительные
текстовые эффекты
До
сих пор мы рассматривали текстовые эффекты внутри
текстового поля. Несмотря на то, что они могут быть
полезны, на них накладывается ряд ограничений Flash MX
позволяет создавать более содержательные текстовые
эффекты. При создании текстового эффекта мы, как
правило, будем располагать каждую букву в фильме и затем
динамически позиционировать (или перемещать) ее на
определенное местоположение. Во Flash 5 нельзя было
динамически получать ширину текста и, как следствие,
позиционировать отдельные символы. Для достижения таких
эффектов во Flash 5 приходилось использовать
дополнительное средство - строку с калькулятором из
www.swfx.org.
Flash MX
предоставляет два способа вычисления ширины строки так,
что мы можем выяснить, в каком месте должен
располагаться каждый символ. Сначала используется
textFormat.getTextExtent (str).
С помощью этого метода можно передавать ему строку, и он
будет возвращать объект, содержащий ширину и высоту
данного фрагмента текста, как если бы все они
располагались в одной строке. Это очень удобно, но
данный подход имеет несколько особенностей, которые мы
сейчас рассмотрим. Второй способ получения ширины строки
заключается в том, что строка помещается в текстовое
поле (с необходимым форматированием), и затем
используется параметр textWidth
текстового поля. Несмотря на то, что этот метод более
громоздкий (так как здесь приходится создавать текстовое
поле, чтобы задействовать его), он более точен по
сравнению с использованием
getTextExtent при работе со встроенными шрифтами.
Продемонстрируем теперь работу этого метода.
Вычисление ширины
строки
- Откройте новый
фильм Flash и разместите на рабочем месте поле
DynamicText, причем
сделайте так, чтобы его длина занимала большую часть
рабочего места. Мы будем использовать шрифт
Verdana.
- В Property
inspector дайте инстансу имя
tf_txt. Затем создайте слой scripts и введите
следующий код.
myTForm = new
TextFormat();
myTForm.size = 24;
myTForm.font = "Verdana";
str = "a piece of test text to check widths";
tf_txt.text = str;
tf_txt.setTextFormat(myTForm);
// retrieve width with getTextExtent
a = myTForm.getTextExtent(str).width;
// retrieve width with textWidth
b = tf_txt.textWidth;
trace(a+" : "+b);
- Запустите ваш
файл и посмотрите на результат в окне Output. Окно
будет отображать 407 : 416. 407 представляет собой
ширину getTextExtent, и 416 - это textWidth.
Мы
нарисовали две линии на рабочем месте, чтобы вы могли
сравнить их. Имя файла -
textWidthTest.fla.
Присутствующая здесь проблема типична для установки
интервалов между знаками: если мы располагаем текст с
помощью getTextExtent, символы отображаются один за
другим, и между ними нет никакого интервала. Другими
словами, textWidth - это наилучший способ аккуратного
размещения текста.
Определение местоположения
символов
Теперь мы
решили, что нам потребуется использовать
TextField.textWidth для
определения местоположения символа, и нам нужно написать
функцию для вычисления этого параметра для любого
данного нам объекта textFormat
(например, для определенного размера текста и шрифта).
Это намного проще сделать с использованием
textFormat.getTextExtent,
так как нам не нужно создавать текстовое поле для
вычисления ширины. Остановимся на этом подходе, как на
более аккуратном.
Определив
позиции символов, мы сможем использовать эти данные для
позиционирования фильмов для каждого символа, что даст
нам большую гибкость при изменении размеров, перемещении
и т.д.
Нам нужно
иметь возможность передавать функции объект
textFormat и строку, что
можно реализовать следующим образом.
function
charPositions(tFormat, str, depth) {
. . .
}
Мы также
включим параметр depth,
чтобы можно было указывать его извне, предотвращая
запись поверх любых других объектов.
Получение других
данных о символах
- Создайте
временное текстовое поле
Dynamic Text в месте, отличном от вашего
рабочего места. Установите для этого текстового поля
шрифт Arial.
- Добавьте новый
слой scripts и введите в нем следующий код.
function
charPositions(tFormat, str, depth) {
_root.createTextField("temp", depth, 0, -300, 100, 400);
temp.embedFonts = true;
temp.autoSize = true;
temp.setNewTextFormat(tFormat);
temp.text = str;
}
Мы
установили autoSize на
значение True, поэтому
поле будет изменять размер, чтобы вмещать любой
помещаемый в него текст. Мы также установили
параметр embedFonts на
значение True, и
textFormat на значение
tFormat. Кроме этого,
нам нужно присвоить переменную
str параметру
text текстового поля.
При
установке параметра
embedFonts текстового поля на значение
True помните, что
шрифт, используемый в фильме, необходимо
экспортировать. Для этого и понадобилось временное
поле Dynamic Text в
каком-либо другом месте. Также необходимо убедиться
в том, что отмечена опция
Embed Font Outlines For All Characters в
диалоговом окне Character Options:
- Чтобы открыть
диалоговое окно Character Options, просто нажмите
кнопку Character: при настройке атрибутов текста в
Property inspector. Для форматирования жирным или
наклонным шрифтом вам понадобится другое текстовое
поле, настроенное на жирный или наклонный шрифт. Вы
можете сделать то же самое с помощью символа шрифта.
- Далее мы создадим
временный массив для записи значений позиций, и
тогда все будет готово для работы цикла и
определения ширины строки.
function
charPositions(tFormat, str, depth) {
_root.createTextField("temp", depth, 0, -300, 100, 400);
temp.embedFonts = true;
temp.autoSize = true;
temp.setNewTextFormat(tFormat);
temp.text = str;
var arr = [] ;
}
- Для определения
позиции каждого символа надо сначала выяснять ширину
всей строки, а затем местоположение каждого символа,
которое будет вычисляться вычитанием ширины строки,
начинающейся с данной точки, из ширины всей строки.
Например, если нашей строкой является "In the
manufacture", то позиция символа "m" в слове
"manufacture" равна ширине "In the manufacture"
минус ширина "manufacture". Добавим в цикл следующий
код.
function
charPositions(tFormat, str, depth) {
_root.createTextField("temp", depth, 0, -300, 100, 400);
temp.embedFonts = true;
temp.autoSize = true;
temp. setNewTextFormat (tFormat);
temp, text = str;
var arr = [] ;
//the total width of the text
var totalWidth = temp.textWidth;
for (var i = 0; i<str.length; i++) {
temp.text = str.substr(i);
// calculate the difference between the width to this point
// and the total width
arr[i] = totalWidth-temp. textWidth;
}
}
В
каждой итерации цикла мы перемещаемся на один символ
вперед в строке и записываем строковое значение из
этого символа в наше временное текстовое поле
str.substr(i). Затем
мы вычисляем ширину, вычитаем ее из полной ширины и
записываем результат в наш массив.
- Далее нужно
удалить созданное текстовое поле и возвратить
массив:
function
charPositions(tFormat, str, depth) {
_root.createTextField("temp", depth, 0, -300, 100, 400);
temp.erabedFonts = true;
temp.autoSize = true;
temp.setNewTextFormat(tFormat);
temp.text = str;
var arr = [];
var totalWidth = temp.textWidth;
for (var i = 0; i<str.length; i++) {
temp.text = str.substr(i);
arr[i] = totalWidth-temp.textWidth;
}
temp.removeTextField();
return arr;
}
- Наконец, вызываем
функцию:
mt = new TextFormat();
mt.font = "Arial";
mt.size = 45;
str = "In the manufacture of safety matches,
softwood logs are peeled into
a thin continuous shaving,
or veneer, about one tenth of an inch thick.
The ribbon of wood is then cut up into splints
at
a rate of about two million per hour.
These splints are soaked in a bath of sodium
silicate,
ammonium phosphate
or sodium phosphate and then dried.
This impregnation prevents afterglow.";
posArray = charPositions(mt, str, 1);
Сохраните
фильм в файле obtainCharPos.fla
и запустите его. Если вы выберете команду меню Debug >
List Variables, то увидите, что массив
posArray содержит значение
для каждой буквы в нашей строке.
Теперь у
нас есть большой список позиций по
X. Далее нам нужно
каким-то образом использовать эту информацию.
Использование позиций символов
Сейчас мы
создадим простой текстовый эффект с использованием
полученных только что позиций. Самое сложное уже позади:
основной объем работы заключался в вычислении позиций,
на которых должны оказаться все символы. Теперь мы
просто выберем способ, с помощью которого можно
расположить символы на нужных местах.
Наш эффект
будет заключаться в плавном последовательном появлении
символов. Первая проблема - массив позиций содержит все
символы в одной строке, а их принято отображать в
нескольких строках . Этот вопрос можно решить, разделив
заранее текст на две строки. Мы можем разделить строки
либо вручную, либо с использованием
string.split() со
специальным разделителем или просто символом новой
строки в качестве места, в котором строки должны быть
разделены.
После
этого мы сможем по очереди получить позиции символов
каждой строки. Далее мы обеспечим автоматическое
разделение текста. Мы укажем ширину текстовой области и,
как только текст выйдет за рамки этой ширины, будем
возвращать его в начало следующей строки. Мы создадим
функцию setUpText, которая
будет получать позиции символов текста, обрабатывать
этот массив и делить его на отдельные строки, записывая
результаты и все отдельные символы в новый массив.
Прежде
всего, получим позиции символов. Далее определим высоту
каждой строки с помощью
getTextExtent (точность здесь не очень важна).
Затем мы создадим переменную
currentLine для записи того, в какой строке
находимся, и массив
finalPositions со всеми конечными координатами.
Использование данных о символах для плавного появления
текста
- Добавьте
следующий ActionScript под функцией
charPositions в файле
obtainCharPos.fla.
function setUpText(str, forma, lineLength) {
var positions = charPositions(forma, str, 1000);
var currentLine;
var lineHeight = forma.getTextExtent(str).height;
var finalPositions = [];
}
Далее
мы добавим цикл для обработки каждой записи в
массиве позиций. Этот цикл будет проверять, является
ли позиция X большей,
чем lineLength. Если
это так, она будет сбрасываться на ноль и к
переменной currentLine
будет прибавляться единица для обновления позиции
Y. Мы будем учитывать
расстояние, на которое необходимо возвращать
символы, так как все последующие символы также будут
перемещены назад на то же расстояние. Это значение
мы будем хранить в переменной с именем
substracta.
- Если у нас есть
символ на позиции 510, а значение
lineLength равно 500,
необходимо вернуть его и все последующие символы
назад на 510. Если позиция X
символа больше, чем 510 плюс длина строки, мы
сбрасываем ее на ноль и прибавляем число позиций,
которое было сброшено, в переменную
substractа, для учета
этого значения в сумме нарастающим итогом. Добавьте
следующий выделенный код в функцию
setUpText.
function setUpText(str,
forma, lineLength) {
var positions = charPositions(forma, str, 1000);
var currentLine;
var subtracta;
var lineHeight = forma.getTextExtent(str).height;
var finalPositions = [] ;
for (var i = 0; i<positions.length; i++) {
// if the current position is off the right edge
if (positions[i]>(lineLength+subtracta)) {
subtracta = positions[i];
currentLine++;
}
var x = positions[i]-subtracta;
var у = lineHeight*currentLine;
finalPositions[i] = {char:str.charAt(i), x:x, y:y};
}
return finalPositions;
}
Здесь
мы добавили две следующие функциональности. Первая
заключается в том, что мы вычисляем позицию
Y, умножая значение
currentLine на
lineHeight; мы
передвигаем вниз страницу на высоту текста для
каждой добавленной строки текста. Мы также записали
наши значения символов и позиции в массив в виде
объекта. Таким образом, при возвращении массива у
нас будет возможность использовать его без знания
строки; теперь это просто список символов.
- Далее мы создадим
небольшую функцию инициализации для вызова функции
setUpText.
function init(str, tForm,
lineLength) {
// retrieve character positions
charPos = setUpText(str, tForm, lineLength);
this.count = 0;
// set drawNext to be called every frame
this.onEnterFrame = drawNext;
}
Мы
будем передавать ей все соответствующие данные, и
функция будет получать позиции символов для строки.
По завершении ее работы мы настраиваем функцию
enterFrame для _root,
drawNext. Это нужно
для поочередного прорисовывания каждой буквы с
использованием переменной count для
протоколирования.
- После этого мы
добавляем функцию drawNext.
В каждом кадре при ее вызове она будет искать
следующий символ в массиве и получать его позицию.
Затем она будет создавать дубликат фильма на этой
позиции, а в нем текстовое поле с соответствующим
символом с корректным форматированием. Затем функция
устанавливает параметр интенсивности
alpha на значение 30 и
применяет к нему функцию
onEnterFrame для постепенного увеличения
интенсивности. Это все должно быть вам понятно, если
вы разбирали весь рассмотренный до данного момента
код. Добавьте в фильм следующий код.
function drawNext() {
var noo = this .createEmptyMovieClip ("lett"+count, count) ;
var nextObj = charPos[this.count];
// a reference to the object in the array
noo._x = nextObj.x;
noo._y = nextObj.y;
noo.createTextField("tex", 1, 0, 0, 100, 100);
noo.tex.text = nextObj.char;
noo.tex.embedFonts = true;
noo.tex.selectable = false;
noo.tex.setTextFormat(mt);
noo._alpha = 30;
noo.onEnterFrame = function() {
// increase alpha until 100 is reached
this._alpha += 5;
if (this._alpha>=100) {
delete this.onEnterFrame;
}
};
count++;
if (count>charPos.length) {
delete this.onEnterFrame;
}
}
- Настраиваем
текстовые форматы и добавляем вызов функции
init.
mt = new TextFormat();
mt.font = "Arial";
mt.size = 24 ;
str = "In the manufacture of safety matches,
softwood logs are peeled into
a thin continuous shaving,
or veneer, about one tenth of an inch thick.
The ribbon of wood is then cut up into splints
at
a rate of about two million per hour.
These splints are soaked in a bath of sodium
silicate,
ammonium phosphate or
sodium phosphate and then dried.
This impregnation prevents afterglow.";
init(str, mt, 530);
- Сохраните файл
под именем useCharPos.fla
и запустите его. Помните, для его правильной работы
необходимо иметь текстовое поле вне рабочего места,
настроенное на используемый вами шрифт, в данном
случае - Arial. Результатом вашей работы будет
постепенное появление букв и плавное усиление их
яркости.
Вы
могли обратить внимание на то, что метод, который мы
использовали для нахождения конца каждой строки и
перехода на следующую строку, может разделять слова
посередине. Мы не будем подробно рассматривать здесь
это явление, но можно изменить метод так, чтобы
слова не разделялись. Сначала идет проход по строке
и вычисление ширины каждого отдельного слова, а
затем эти значения складываются для определения
места, где они выходят за пределы правой границы.
После этого осуществляется переход к следующей
строке.
Прочие возможности
В данном
упражнении мы будем создавать другой файл, основанный на
предыдущем, чтобы показать вам, насколько просто
осуществлять управление, когда уже есть основные
необходимые значения, и, кроме того, мы расположим
символы в случайном порядке.
Реализация
случайного появления символов
- Единственным
изменением в данном файле будет функция
drawNext. Откройте
useCharPos.fla и
приготовьтесь вносить в него изменения.
Функция drawNext
необходима для случайного выбора символа из массива
и его прорисовки. Затем символ будет удаляться из
массива, после чего будут оставаться только те
символы, которые все еще должны быть прорисованы.
Код реализации этой функциональности довольно прост.
Сначала выбирается случайное число между 0 и числом
записей в массиве. Затем эта запись переносится из
массива во временную переменную. После этого элемент
удаляется из массива с помощью метода
splice.
var next =
Math.floor(Math.random()*charpos.length);
var nextObj = charPos[next] ;
charPos.splice(next, 1) ;
- Остальная часть
функции более или менее похожа на предыдущую.
Единственным отличием является способ выбора символа
для создания дубликата.
function drawNext() {
this.count++;
// pick a random character
var next = Math.floor(Math.random()*charpos.length);
var nextObj = charPos[next];
charPos.splice(next, 1);
var noo = this.createEmptyMovieClip
("lett"+this.count, this.count);
noo._x = nextObj.x;
noo._y = nextObj.y;
noo._alpha = 30;
noo.onEnterFrame = function() {
this._alpha += 5;
if (this._alpha>=100) {
delete this.onEnterFrame;
}
};
noo.createTextField("tex", 1, 0, 0, 100, 100);
noo.tex.text = nextObj.char;
noo.tex.embedFonts = true;
noo.tex.selectable = false;
noo.tex.setTextFormat(mt);
if (charPos.length == 0) {
delete this.onEnterFrame;
return;
}
}
- Можно ускорить
выполнение этой программы, заключив весь код в цикл,
вследствие чего с каждым кадром будет создаваться
больше дубликатов.
function drawNext() {
for (var i = 0; i<4; i++) {
this.count++;
var next = Math.floor(Math.random()*charpos.length);
var nextObj = charPos[next];
charPos.splice(next, 1);
var noo = this.createEmptyMovieClip
("lett"+this.count, this.count);
noo._x = nextObj.x;
noo._y = nextObj.y;
noo._alpha = 30;
noo.onEnterFrame = function() {
this._alpha += 5;
if (this._alpha>=100) {
delete this.onEnterFrame;
}
};
noo.createTextField("tex", 1, 0, 0, 100, 100);
noo.tex.text = nextObj.char;
noo.tex.embedFonts = true;
noo. tex. selectable = false;
noo.tex.setTextFormat(mt);
if (charPos.length == 0) {
delete this.onEnterFrame;
return;
}
}
}
Этот
код будет выполняться корректно, если вы заменили им
предыдущую функцию drawNext.
Сохраните ваш фильм в файле
useCharPosFurther и запустите его. Символы,
составляющие текстовую строку, появляются в
случайном порядке.
Создав
этот базис, очень легко продолжить работу и создать
довольно сложные текстовые эффекты. Можно применить
функцию slideTo, чтобы
буквы скользили или "прыгали" по очереди на свои
места.
Зная
конечную позицию каждой буквы, мы можем делать все,
что нам нужно, с каждой буквой фильма перед тем, как
она окажется на своем конечном месте. Три исходных
файла, прилагаемые к этой главе, демонстрируют
подобные эффекты, достигаемые изменением всего лишь
нескольких строк кода. Первый файл -
useCharPosSwingTo.fla
- располагает все буквы довольно далеко от их
позиций и использует колебательное движение,
рассмотренное в первой лекции, для перемещения
каждой буквы на свое место. Второй файл -
useCharPosScaleTo.fla
- представляет каждую букву в большем размере и на
большем расстоянии от ее места, постепенно уменьшая
и перемещая буквы на их места. Третий файл -
useCharPosScaleTo2.fla
- работает по такому же принципу, но обрабатывает
буквы по порядку, а не случайным образом.
Улучшение интерфейса
навигации для изображений
Теперь мы будем заново прорабатывать пример,
рассмотренный в лекции 1,
но используем другие фотографии. На этот раз мы сделаем
пример более динамичным. Нам не придется вручную
размещать все фотографии. Мы также добавим текстовый
эффект, который будет начинать действовать при
перемещении фотографии на свое место. Несмотря на то,
что это новый файл, мы будем использовать часть кода из
прежнего упражнения.
В
последней лекции этой части мы будем изучать
динамическую загрузку изображений, но сейчас не надо
импортировать их в файл Flash. Мы будем располагать
каждую картинку в своем собственном фильме и затем
динамически применять их.
Динамическое
позиционирование изображений и добавление текстовых
эффектов
- Импортируйте все
изображения (pic1.jpeg - pic8.jpeg с компакт-диска)
и разместите их в фильмах. Назовите их 'pic1' -
'pic8' и в диалоговом окне Linkage настройте экспорт
для ActionScript. Используя имена 'pic1' - 'pic8',
установите точку закрепления на левый верхний угол.
- Теперь на главном
рабочем месте мы установим несколько основных
переменных для фильма. Они будут представлять собой
информацию о размере фильма и размере изображений.
Мы будем использовать эти данные для центрирования
изображений на рабочем месте.
stageWidth=550;
stageHeight=400;
imageWidth=410;
imageHeight=308;
speed=3;
Запись
всех этих данных в переменные нужна для того, чтобы
без проблем использовать этот код еще раз с
картинками или страницей другого размера, если
понадобится. Мы также добавили переменную
speed для управления
скоростью скольжения.
- При помощи
переменных stageWidth
и stageHeight можно
выяснить, где должна располагаться картинка, чтобы
оказаться по центру рабочего места. Если фильмы
выровнены по центру, можно вычислить левую сторону
картинки, вычтя ширину картинки из ширины рабочего
места и затем разделив на два.
stageWidth минус
imageWidth даст нам
расстояние до другой стороны изображения. Разделив
этот результат на два, получим левую позицию.
topPos=
(stageHeight-imageHeight)/2;
leftPos= (stageWidth-imageWidth)/2;
- Мы собираемся
расположить изображение по центру рабочего места, а
также добавить строку текстовых кнопок под
картинкой. Нам нужны объекты
textFormat для кнопок и для текстового
эффекта, который будет располагаться вверху
картинки.
buttonTextFormat=new
TextFormat ("_sans", 9, 0x87A7E2, true);
captionTextFormat=newTextFormat ("Arial", 30,
0xffffff, true);
- Применим шрифт
Arial, но не sans. Для этого поместите текстовое
поле вне рабочего места, установите шрифт на Arial,
настройте его на динамический текст и добавьте все
символы, как мы это делали ранее. Убедитесь, что
отмечен параметр жирности шрифта, как указано в
объекте TextFormat. Вы
можете выбрать любой шрифт, я указал Arial просто
потому, что он имеется у всех пользователей.
- Далее мы
определим массив, содержащий идентификаторы ссылок
изображений, которые мы будем добавлять, и название,
которое будет присвоено каждому из них. Мы создадим
каждый элемент массива в виде объекта, имеющего два
параметра - ссылку и название.
images=[{link:"picl",title:"MAY 15 2002"},
{link:"pic2",title:"MARCH 12 2002"},
{link:"pic3",title:"JANUARY 23 2002"},
{link:"pic4",title:"APRIL 30 2001"},
{link:"pic5",title:"JUNE 07 2002"},
{link:"pic6",title:"JULY 12 2002"},
{link:"pic7",title:"AUGUST 25 2002"},
{link:"pic8",title:"DECEMBER 01 2002"}
]
Для расположения рисунков на рабочем месте нам нужно
создать функцию. Как и в примере
лекции 1,
мы поместим каждый рисунок внутрь фильма для
скольжения на нужные позиции. Прежде всего, в
функции необходимо создать пустой фильм "imageHolder",
координаты которого leftPos
и topPos вычислены
ранее. Теперь, чтобы добавить картинки, мы проходим
циклически через наш массив рисунков и используем
параметр ссылки для выбора нужных фильмов из
библиотеки. Мы поместим ссылку на только что
созданный фильм в нашем массиве рисунков в виде
дополнительного параметра "mov", чтобы иметь всю
необходимую информацию в центральном реестре. При
добавлении каждого фильма мы будем увеличивать
переменную currx на значение
imageWidth. Это значение будет использоваться
для установки позиции по оси
X для каждого фильма, чтобы они были
расположены впритык друг к другу.
function
populatelmages(imageArr,imageWid){
_root.createEmptyMovieClip("imageHolder",++this.depth)
imageHolder._x=leftpos;
imageHolder._y=topPos;
var currx=0;
for(var i=0,-i<imageArr.length;i++) {
imageHolder.depth++;
//attach image movieclip at currx
imageArr[i].mov=imageHolder.attachMovie(imageArr[i].link,
К"image"+i,imageHolder.depth,{_x:currx,_alpha:102});
//increase currx
currx+=imageWidth;
}
}
Мы
использовали возможность передавать значения с
attachMovie для
установки позиции фильма по оси
X и
alpha.
imageArr[i].mov=imageHolder.attachMovie(imageArr[i].link,
К"image"+i,imageHolder.depth,{_x:currx,_alpha:102})
Мы
установили alpha,
равное 102, во избежание дерганья изображения,
которое может возникать во Flash во время
перемещения картинок. Я не понимаю, как это
срабатывает, но, тем не менее, это так. Вы можете
попытаться исключить эти строки, когда мы закончим,
и понять разницу. Если вы запустите код сейчас, то
вы увидите по крайней мере два фильма, стоящие на
рабочем месте один за другим.
- Теперь создадим
кнопки.
function
createButtons(imageArr,tF){
_root.createEmptyMovieClip("buttonHolder",++this.depth)
buttonHolder._x=leftPos+10;
buttonHolder._y=topPos+imageHeight+5;
var currx;
for(var i=0;i<images.length;i++){
// attach empty movieclip for button to sit in
var nooButton=buttonHolder.createEmptyMovieClip
("button"+i,i) ;
// place button at currx
nooButton._x=currx;
nooButton.item=imageArr[i];
nooButton.createTextField("texta",1,0,0,1,1);
nooButton.texta.autoSize=true;
var caption = i>9 ? i+1 :"0"+(i+1);
nooButton.texta.text=caption;
nooButton.texta.setTextFormat(tF);
nooButton.onPress=function(){
_root.centerPic(this.item)
}
currx+=nooButton.texta.textWidth+5
}
}
Создадим другой пустой фильм "buttonHolder", который
будет содержать все кнопки. Расположим этот фильм
справа от левого края рисунков и значительно ниже
нижнего края изображений
(topPos+imageHeight).
_root.createEmptyMovieClip("buttonHolder",++this.depth);
buttonHolder._x=leftPos+10;
buttonHolder._y=topPos+imageHeight+5;
Далее
мы повторно проходим массив с помощью цикла,
добавляя кнопку для каждого его элемента, т.е. одну
кнопку для каждого изображения. Внутри каждой кнопки
создаем переменную "item", предназначенную для
записи ссылки на элемент в массиве рисунков, к
которому он относится. Это можно использовать для
получения доступа к другой информации о картинке,
например о фильме, который представляет данный
рисунок. Далее добавляем
textField в каждую переменную с помощью
объекта textFormat,
только что созданного нами. Мы используем значение
i для установки текста
в TextField. Если
значение i меньше, чем один символ, добавляем 0
впереди него. Хотя в данный момент это не относится
к делу (у нас только 8 картинок), в дальнейшем можно
применить это следующим образом.
var caption = i>9 ? i+1
:"0"+ (i+1);
nooButton.texta.text=caption;
Мы
настраиваем функцию onPress
для кнопки, чтобы вызывать функцию
centerPic, передавая
переменную "item", созданную нами ранее. Эта функция
и будет перемещать изображения.
nooButton.onPress=function(){
_root.centerPic(this.item)
}
Теперь
обеспечим правильное позиционирование, увеличивая
значение текущей позиции по оси
X на сумму ширины
TextField и небольшого
дополнительного места для уверенности.
- Теперь нам нужно
реализовать движение. Мы будем использовать для
этого созданную ранее функцию
slideTo.
MovieClip.prototype.slideTo=
function(x,y,speed,callbackObj, callbackFunc) {
if(this.slideControl){
var noo=this.slideControl
}else{
var noo=this.createEmptyMovieClip ("slideControl",++this.depth)
}
noo.tx=x;
noo.ty=y;
noo.speed=speed;
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;
this.callBackObj[this.callBackFunc](this._parent)
this.removeMovieClip ()
}
}
}
- Далее добавляем
функцию для инициализации процесса - centerPic.
function centerPic(item){
// if the picture is not already centered
if(item!=_root.currentPicture){
_root. currentPicture =item,-
var mov=item.mov;
var x=leftPos-mov._x;
var y=imageHolder._y;
imageHolder.slideTo(x,y,speed,this,"triggerText");
clearText();
}
}
В этой
функции нам необходимо проверять, выровнена ли
картинка по центру. Результат этой проверки
записывается в переменную _root.currentPicture.
Если это не так, берем значение
_root.currentPicture и
начинаем перемещать объект. Мы извлекаем фильм из
переданного элемента (это была запись в массиве
изображений, поэтому используем параметр mov). Затем
выясняем позицию, на которую должен переместиться
imageHolder, как мы
делали это ранее (leftPos
минус позиция фильма по оси X)
и вызываем функцию slideTo
для перемещения на эту позицию. При вызове функции
slideTo мы передаем ей
функцию "triggerText", которая инициализирует
текстовый эффект по достижении фильмом конечной
точки. Наконец, нам нужно удалить любой уже
присутствующий текст. Для этого в конце программы
вызываем функцию clearText.
- Запустив код, вы
увидите, что изображения позиционируются корректно.
Далее нам необходимо создать маску для сокрытия
рисунков, расположенных вокруг выбранной фотографии.
Это можно сделать посредством рисования api, но
сейчас мы будем использовать фильм из библиотеки.
Создайте новый фильм, установите параметр связывания
на значение "square" и внутри него нарисуйте квадрат
100x100 пикселей с точкой закрепления в левом
верхнем углу.
- Затем добавьте
следующий код.
function
createMask(targ,x,y,wid,high){
// create init object containing values for
scale and //position
var obj={_x:x,_y:y,_xscale:wid,_yscale:high};
_root. attachMovie ("square","maska",++depth,obj );
targ.setMask(maska);
}
При
написании этого кода я заметил кое-что интересное:
если попытаться установить
_width и _height
фильма при его применении с использованием initObj,
что мы и делаем, произойдет ошибка, и вы не увидите
фильм. Дело в том, что передаваемые переменные
настраиваются до того, как что-либо происходит в
фильме и, как следствие, программе неизвестно, для
чего внутри фильма можно настраивать ширину и высоту.
- Теперь рассмотрим
элемент текстового эффекта. Прежде всего, мы считаем
символы и позиции символов из каждой картинки. Далее
проходим циклом наш массив изображений и вызываем
функцию charPositions
для каждого элемента, сохраняя результаты в виде
characterArr внутри
каждого объекта изображения.
function
setCharPositions(imageArr,tF){
for(var i in imageArr){
imageArr[i].characterArr=
charPositions (tf,imageArr[i].title,10000)
}
}
- Функция
charPositions была
значительно изменена с тех пор, как мы имели с ней
дело ранее. Я выделил те ее части, которые были
изменены. В ней есть два основных отличия от прежней
версии. Во-первых, функция использует
textWidth и
textHeight объекта
TextField для
выяснения места расположения всего фрагмента текста.
Оно добавляется к координатам
X и Y в виде
смещения. Во-вторых, теперь возвращаемый функцией
массив содержит объекты, у каждого из которых есть
параметры для координат X
и Y, а также
релевантный символ.
function
charPositions(tFormat,str,depth){
_root.createTextField("temp",depth,0,-300,100,400);
temp.autoSize=true;
temp.embedFonts=true;
temp.setNewTextFormat(tFormat);
temp.text=str;
var arr= [];
var totalWidth= temp. textwidth;
var leftEdge=(stageWidth-totalWidth)/2;
var height=temp.textHeight;
var topEdge=(stageHeight-height)/2;
for(var i=0;i<str.length;i++){
temp.text=str.substr(i);
var xp=totalWidth-temp.textwidth;
arr[i]={x:xp+leftEdge,y:topEdge,char:str.charAt(i)};
}
return arr;
}
- Теперь у нас есть
дополнительная запись для каждого изображения в
нашем массиве изображений. Далее нам нужно создать
функцию triggerText
для позиционирования букв. Вам уже знакомо, как это
делается, из прошлого материала. Случайным образом
выбирается символ из заголовка и применяется плавное
увеличение интенсивности отображения. В коде ниже
выделены некоторые строки, на которые следует
обратить внимание.
function triggerText(){
depth++
latestText=_root.createEmptyMovieClip ("textHolder"+depth, depth) ;
latestText.characters=currentPicture.characterArr.slice();
latestText.movs=[];
latestText.onEnterFrame=function(){
this.count++;
var next=Math.floor(Math.random()* this.characters.length);
var nextObj=this.characters[next];
this.characters.splice(next,1);
var noo=this.createEmptyMovieClip
("lett"+this.count,this.count);
noo._x=nextObj.x;
noo._y=nextObj.y;
noo._alpha=30;
noo.onEnterFrame=function(){
this._alpha+=5;
if(this._alpha>=100){
delete this.onEnterFrame
}
}
noo.createTextField("tex",1,0,0,100,100);
noo.tex.text=nextObj.char;
noo.tex.embedFonts=true;
noo.tex.selectable=false;
noo.tex.setTextFormat(_root.captionTextFormat);
this.movs.push(noo);
if(this.characters.length==0){
delete this.onEnterFrame;
return;
}
}
latestText.remove=function(){
var
next=Math.floor(Math.random()*this.movs.length);
this.movs [next] .removeMovieClip();
this.movs.splice(next, 1);
if(this.movs.length==0){
this.removeMovieClip();
}
}
}
Пример
2.2.
Следует заметить, что мы создали отдельный фильм для
текстового эффекта. Он выступает как в роли главного
фильма, содержащего отдельные фильмы для букв внутри
себя, так и в роли управляющего фильма, т.к. буквы
сначала создаются, а затем опять удаляются при
переключении фотографий. Последний фильм
textHolder хранится в
переменной latestText.
При переключении фотографий текст в
latestText будет
удаляться. При создании основного фильма нужно
знать, какими являются все символы и в каком месте
они должны быть размещены. Для получения этой
информации мы используем массив символов текущей
картинки. Так как мы собираемся удалять элементы
этого массива, мы создаем копию массива с помощью
slice в фильме, не
трогая оригинал. Метод slice
используется, в основном, для возврата элементов из
массива между двумя точками, так, например,
arr.slice (2,5) возвратит копию элементов массива с
2 по 5. При вызове его без аргументов будет
возвращена копия всего массива.
latestText.characters=currentPicture.characterArr.slice
()
- Последняя часть
функции определяет функцию "remove" как
onEnterFrame для
удаления всех букв из фильма и затем самой себя по
окончании данной операции. Для этого мы добавляем
функцию clearText,
которая и будет обеспечивать эту возможность:
function clearText(){
_root.latestText.onEnterFrame=_root.latestText.remove
}
- Добавим строки
кода, вызывающие определенные нами функции, для
размещения изображений на рабочем месте, создания
кнопок, вычисления позиций символов, создания маски
и выравнивания по центру первого изображения.
populatelmages(images,imageWidth);
createButtons(images,buttonTextFormat);
setCharPositions(images,captionTextFormat);
createMask(imageHolder,leftPos,topPos,imageWidth,imageHeight);
centerPic(images[0]);
Мы
завершили создание расширенного интерфейса изображений.
Сохраните его и запустите - все должно работать
безупречно.
|