Одной из прекрасных возможностей Flash MX является широкий спектр средств управления параметрами текста. Если раньше для того, чтобы изменить шрифт в текстовом поле, нужно было присвоить тексту формат HTML, то теперь для этого есть объект textFormat. С помощью него можно избежать присутствия тегов среди переменных, если нужно отобразить их не как обычный текст.
Теперь мы можем указать определенную часть текста и установить формат независимо от самого текста. Также можно настраивать высоту и ширину определенных фрагментов текста, что позволяет лучше контролировать расположение и структуру текста. Теперь текстовое поле может интерпретироваться во многом аналогично фильму: отныне можно динамически создавать текстовые поля, устанавливать их позиции X и Y, а также присваивать им приемники, чтобы события происходили при изменении их содержимого.
В этой лекции мы будем работать с упражнениями, охватывающими большой спектр вопросов. В первую очередь мы обратим внимание на объекты textField и textFormat, познакомимся с их действием и с эффектами, которые можно достичь с их помощью. Некоторые результаты будут полезны в практическом применении. Другие упражнения помогут проиллюстрировать возможности этих объектов. Затем мы рассмотрим возможность определения ширины и высоты текстового содержимого для создания динамических текстовых эффектов с нужным позиционированием без применения дополнительных средств.
Первым эффектом, который мы рассмотрим, является стандартный эффект пишущей машинки, заключающийся в том, что текст в текстовом поле отображается так, будто он напечатан вручную. Мы рассмотрим два различных способа создания эффекта пишущей машинки. Прежде всего, мы изучим основные принципы работы данного эффекта.
Нам нужно, чтобы с каждым кадром в текстовом поле появлялась все большая часть строки текста. Этого можно добиться, введя переменную-счетчик и увеличивая ее значение с каждым кадром, и затем располагать текст в текстовом поле, используя этот счетчик для задания длины текста в каждом новом кадре. Во Flash 5 мы могли бы отображать текст в текстовом поле, присваивая ему переменную. Каждый раз при обновлении этой переменной текстовое поле также обновлялось бы соответствующим образом. Во Flash MX текстовое поле является объектом с параметром text. Чтобы текст отображался в текстовом поле, нам нужно присвоить фрагмент текста параметру text текстового поля.
Имейте в виду, что все еще можно добавить переменную текстовому полю (Var). Мы не будем использовать этот метод, так как, скорее всего, эта возможность была сохранена лишь для обеспечения корректной работы с файлами, созданными во Flash 5.

Всегда лучше изменять размер динамических текстовых полей, перетаскивая кнопку текстового поля. Если изменить размер текстового поля, указав значения W и H в 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.";

Это дает нам исчерпывающее представление о том, что происходит с текстовым полем. Каждое динамическое текстовое поле или текстовое поле ввода, размещенное на рабочем месте, имеет параметры и свойства, которые могут изменяться во время выполнения.
text. Просто замените tf_txt.text на text_str:text_str="When a vibrating source...
Теперь мы создадим функцию enterFrame для добавления символов в текстовое поле один за другим с использованием метода substr объекта строки. Этот метод передает два аргумента - один из них позволяет указывать стартовую позицию, а другой указывает число символов. Затем метод получает фрагмент строки. Итак, имея в виду текстовую строку, рассмотренную выше, обратимся к следующему ActionScript:
Text_str.substr (0, 6);
Это выражение будет получать фрагмент "When a", т.е. первые шесть символов строки. При реализации эффекта пишущей машинки первый передаваемый аргумент будет всегда равен нулю, так как текст должен отображаться с начала строки, в то время как второй аргумент (длина полученной строки) будет увеличиваться с каждым разом, отображая все больший фрагмент строки.
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 непосредственно связан с частотой кадров фильма. Давайте рассмотрим несложный пример того, как работает данный метод.
Сейчас мы будем анимировать два фильма. Один из них будет использовать onEnterFrame, а другой - метод setInterval.
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, но не использовать их вместе. Если точная синхронизация не критична для определенного приложения, тогда можно использовать оба подхода.
Запустив ваш фильм, вы обнаружите, что при обновлении рабочего места 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.myTypeID = 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.myTypeID;
};
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.myTypeID = 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");
При добавлении функций или параметров в прототипы объектов, необходимо быть осторожным. Если используется цикл 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 можно использовать для изменения форматирования определенных фрагментов текста, и теперь мы сделаем так, чтобы это действие выполнялось посимвольно, а не изменяло весь текст одновременно. Затем мы, используя этот метод, сделаем шаг вперед и создадим функцию, которая выбирает все вхождения определенного слова и отображает их в другом формате, большим размером и другим цветом.
Начнем с краткого изучения использования 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, и можно приступить к созданию метода для постепенного изменения textFormat. Мы будем делать это во многом аналогично тому, как поступали с функцией typeID. Мы передадим функции число параметров, включая объект textFormat, точку начала, конечную точку, скорость и интервал. Мы также настроим ее на работу с функцией обратной связи, которую применим во второй части данного примера.
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);
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 = setInterval
(this, "nooTextFormatControl", interval) ;
};
TextField.prototype.nooTextFormatControl = function() {
};
TextField.prototype.cleanNooTextFormat = function() {
};
Мы делаем то же самое, что и раньше - берем все копии всех аргументов, передаваемых в аргумент, и помещаем их в само текстовое поле. Мы приравниваем this.end к end+1, так как второй аргумент, передаваемый setTextFormat, ссылается на символ после последнего символа, к которому применен другой формат, тогда как передаваемое нами значение ссылается на последний символ, формат которого мы хотим изменить.
В функции управления nooTextFormatControl мы будем пошагово прибавлять значение переменной this.current и увеличивать строку текста, к которой применяется textFormat. Мы начинаем current со значения begin и продолжаем увеличивать его до тех пор, пока оно не достигнет значения end.
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), то мы применяем формат к тексту с использованием начального и конечного значений, переданных в начале, и вызываем функцию .
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.findInstances("television")
Выполнив код и просмотрев переменные, вы увидите, что vals содержит массив с четырьмя объектами - по одному для каждого вхождения слова "
String.prototype.findInstances = 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.findInstances(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 = setInterval(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.findInstances = 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.findInstances(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);
switchTextFormat2.fla и запустите его. Вы увидите четыре вхождения слова "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 при работе со встроенными шрифтами. Продемонстрируем теперь работу этого метода.
DynamicText, причем сделайте так, чтобы его длина занимала большую часть рабочего места. Мы будем использовать шрифт Verdana.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);
Мы нарисовали две линии на рабочем месте, чтобы вы могли сравнить их. Имя файла - textWidthTest.fla.

Присутствующая здесь проблема типична для установки интервалов между знаками: если мы располагаем текст с помощью getTextExtent, символы отображаются один за другим, и между ними нет никакого интервала. Другими словами, textWidth - это наилучший способ аккуратного размещения текста.
Теперь мы решили, что нам потребуется использовать TextField.textWidth для определения местоположения символа, и нам нужно написать функцию для вычисления этого параметра для любого данного нам объекта textFormat (например, для определенного размера текста и шрифта). Это намного проще сделать с использованием textFormat.getTextExtent, так как нам не нужно создавать текстовое поле для вычисления ширины. Остановимся на этом подходе, как на более аккуратном.
Определив позиции символов, мы сможем использовать эти данные для позиционирования фильмов для каждого символа, что даст нам большую гибкость при изменении размеров, перемещении и т.д.
Нам нужно иметь возможность передавать функции объект textFormat и строку, что можно реализовать следующим образом.
function charPositions(tFormat, str, depth) {
. . .
}
Мы также включим параметр depth, чтобы можно было указывать его извне, предотвращая запись поверх любых других объектов.
Dynamic Text в месте, отличном от вашего рабочего места. Установите для этого текстового поля шрифт Arial.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 в диалоговом окне Character Options:

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 = [] ;
}
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 со всеми конечными координатами.
Использование данных о символах для плавного появления текста
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.
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);
Вы могли обратить внимание на то, что метод, который мы использовали для нахождения конца каждой строки и перехода на следующую строку, может разделять слова посередине. Мы не будем подробно рассматривать здесь это явление, но можно изменить метод так, чтобы слова не разделялись. Сначала идет проход по строке и вычисление ширины каждого отдельного слова, а затем эти значения складываются для определения места, где они выходят за пределы правой границы. После этого осуществляется переход к следующей строке.
В данном упражнении мы будем создавать другой файл, основанный на предыдущем, чтобы показать вам, насколько просто осуществлять управление, когда уже есть основные необходимые значения, и, кроме того, мы расположим символы в случайном порядке.
Реализация случайного появления символов
drawNext. Откройте useCharPos.fla и приготовьтесь вносить в него изменения.Функция drawNext необходима для случайного выбора символа из массива и его прорисовки. Затем символ будет удаляться из массива, после чего будут оставаться только те символы, которые все еще должны быть прорисованы. Код реализации этой функциональности довольно прост. Сначала выбирается случайное число между 0 и числом записей в массиве. Затем эта запись переносится из массива во временную переменную. После этого элемент удаляется из массива с помощью метода .
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. Мы будем располагать каждую картинку в своем собственном фильме и затем динамически применять их.
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);
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 ()
}
}
}
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", которая инициализирует текстовый эффект по достижении фильмом конечной точки. Наконец, нам нужно удалить любой уже присутствующий текст. Для этого в конце программы вызываем функцию .
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();
}
}
}
Следует заметить, что мы создали отдельный фильм для текстового эффекта. Он выступает как в роли главного фильма, содержащего отдельные фильмы для букв внутри себя, так и в роли управляющего фильма, т.к. буквы сначала создаются, а затем опять удаляются при переключении фотографий. Последний фильм textHolder хранится в переменной latestText. При переключении фотографий текст в latestText будет удаляться. При создании основного фильма нужно знать, какими являются все символы и в каком месте они должны быть размещены. Для получения этой информации мы используем массив символов текущей картинки. Так как мы собираемся удалять элементы этого массива, мы создаем копию массива с помощью slice в фильме, не трогая оригинал. Метод slice используется, в основном, для возврата элементов из массива между двумя точками, так, например, arr.slice (2,5) возвратит копию элементов массива с 2 по 5. При вызове его без аргументов будет возвращена копия всего массива.
latestText.characters=currentPicture.characterArr.slice ()
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]);
Мы завершили создание расширенного интерфейса изображений. Сохраните его и запустите - все должно работать безупречно.
Одной из прекрасных возможностей Flash MX является широкий спектр средств управления параметрами текста. Если раньше для того, чтобы изменить шрифт в текстовом поле, нужно было присвоить тексту формат HTML, то теперь для этого есть объект textFormat. С помощью него можно избежать присутствия тегов среди переменных, если нужно отобразить их не как обычный текст.
Теперь мы можем указать определенную часть текста и установить формат независимо от самого текста. Также можно настраивать высоту и ширину определенных фрагментов текста, что позволяет лучше контролировать расположение и структуру текста. Теперь текстовое поле может интерпретироваться во многом аналогично фильму: отныне можно динамически создавать текстовые поля, устанавливать их позиции X и Y, а также присваивать им приемники, чтобы события происходили при изменении их содержимого.
В этой лекции мы будем работать с упражнениями, охватывающими большой спектр вопросов. В первую очередь мы обратим внимание на объекты textField и textFormat, познакомимся с их действием и с эффектами, которые можно достичь с их помощью. Некоторые результаты будут полезны в практическом применении. Другие упражнения помогут проиллюстрировать возможности этих объектов. Затем мы рассмотрим возможность определения ширины и высоты текстового содержимого для создания динамических текстовых эффектов с нужным позиционированием без применения дополнительных средств.
Первым эффектом, который мы рассмотрим, является стандартный эффект пишущей машинки, заключающийся в том, что текст в текстовом поле отображается так, будто он напечатан вручную. Мы рассмотрим два различных способа создания эффекта пишущей машинки. Прежде всего, мы изучим основные принципы работы данного эффекта.
Нам нужно, чтобы с каждым кадром в текстовом поле появлялась все большая часть строки текста. Этого можно добиться, введя переменную-счетчик и увеличивая ее значение с каждым кадром, и затем располагать текст в текстовом поле, используя этот счетчик для задания длины текста в каждом новом кадре. Во Flash 5 мы могли бы отображать текст в текстовом поле, присваивая ему переменную. Каждый раз при обновлении этой переменной текстовое поле также обновлялось бы соответствующим образом. Во Flash MX текстовое поле является объектом с параметром text. Чтобы текст отображался в текстовом поле, нам нужно присвоить фрагмент текста параметру text текстового поля.
Имейте в виду, что все еще можно добавить переменную текстовому полю (Var). Мы не будем использовать этот метод, так как, скорее всего, эта возможность была сохранена лишь для обеспечения корректной работы с файлами, созданными во Flash 5.

Всегда лучше изменять размер динамических текстовых полей, перетаскивая кнопку текстового поля. Если изменить размер текстового поля, указав значения W и H в 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.";

Это дает нам исчерпывающее представление о том, что происходит с текстовым полем. Каждое динамическое текстовое поле или текстовое поле ввода, размещенное на рабочем месте, имеет параметры и свойства, которые могут изменяться во время выполнения.
text. Просто замените tf_txt.text на text_str:text_str="When a vibrating source...
Теперь мы создадим функцию enterFrame для добавления символов в текстовое поле один за другим с использованием метода substr объекта строки. Этот метод передает два аргумента - один из них позволяет указывать стартовую позицию, а другой указывает число символов. Затем метод получает фрагмент строки. Итак, имея в виду текстовую строку, рассмотренную выше, обратимся к следующему ActionScript:
Text_str.substr (0, 6);
Это выражение будет получать фрагмент "When a", т.е. первые шесть символов строки. При реализации эффекта пишущей машинки первый передаваемый аргумент будет всегда равен нулю, так как текст должен отображаться с начала строки, в то время как второй аргумент (длина полученной строки) будет увеличиваться с каждым разом, отображая все больший фрагмент строки.
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 непосредственно связан с частотой кадров фильма. Давайте рассмотрим несложный пример того, как работает данный метод.
Сейчас мы будем анимировать два фильма. Один из них будет использовать onEnterFrame, а другой - метод setInterval.
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, но не использовать их вместе. Если точная синхронизация не критична для определенного приложения, тогда можно использовать оба подхода.
Запустив ваш фильм, вы обнаружите, что при обновлении рабочего места 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.myTypeID = 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.myTypeID;
};
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.myTypeID = 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");
При добавлении функций или параметров в прототипы объектов, необходимо быть осторожным. Если используется цикл 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 можно использовать для изменения форматирования определенных фрагментов текста, и теперь мы сделаем так, чтобы это действие выполнялось посимвольно, а не изменяло весь текст одновременно. Затем мы, используя этот метод, сделаем шаг вперед и создадим функцию, которая выбирает все вхождения определенного слова и отображает их в другом формате, большим размером и другим цветом.
Начнем с краткого изучения использования 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, и можно приступить к созданию метода для постепенного изменения textFormat. Мы будем делать это во многом аналогично тому, как поступали с функцией typeID. Мы передадим функции число параметров, включая объект textFormat, точку начала, конечную точку, скорость и интервал. Мы также настроим ее на работу с функцией обратной связи, которую применим во второй части данного примера.
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);
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 = setInterval
(this, "nooTextFormatControl", interval) ;
};
TextField.prototype.nooTextFormatControl = function() {
};
TextField.prototype.cleanNooTextFormat = function() {
};
Мы делаем то же самое, что и раньше - берем все копии всех аргументов, передаваемых в аргумент, и помещаем их в само текстовое поле. Мы приравниваем this.end к end+1, так как второй аргумент, передаваемый setTextFormat, ссылается на символ после последнего символа, к которому применен другой формат, тогда как передаваемое нами значение ссылается на последний символ, формат которого мы хотим изменить.
В функции управления nooTextFormatControl мы будем пошагово прибавлять значение переменной this.current и увеличивать строку текста, к которой применяется textFormat. Мы начинаем current со значения begin и продолжаем увеличивать его до тех пор, пока оно не достигнет значения end.
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), то мы применяем формат к тексту с использованием начального и конечного значений, переданных в начале, и вызываем функцию .
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.findInstances("television")
Выполнив код и просмотрев переменные, вы увидите, что vals содержит массив с четырьмя объектами - по одному для каждого вхождения слова "
String.prototype.findInstances = 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.findInstances(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 = setInterval(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.findInstances = 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.findInstances(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);
switchTextFormat2.fla и запустите его. Вы увидите четыре вхождения слова "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 при работе со встроенными шрифтами. Продемонстрируем теперь работу этого метода.
DynamicText, причем сделайте так, чтобы его длина занимала большую часть рабочего места. Мы будем использовать шрифт Verdana.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);
Мы нарисовали две линии на рабочем месте, чтобы вы могли сравнить их. Имя файла - textWidthTest.fla.

Присутствующая здесь проблема типична для установки интервалов между знаками: если мы располагаем текст с помощью getTextExtent, символы отображаются один за другим, и между ними нет никакого интервала. Другими словами, textWidth - это наилучший способ аккуратного размещения текста.
Теперь мы решили, что нам потребуется использовать TextField.textWidth для определения местоположения символа, и нам нужно написать функцию для вычисления этого параметра для любого данного нам объекта textFormat (например, для определенного размера текста и шрифта). Это намного проще сделать с использованием textFormat.getTextExtent, так как нам не нужно создавать текстовое поле для вычисления ширины. Остановимся на этом подходе, как на более аккуратном.
Определив позиции символов, мы сможем использовать эти данные для позиционирования фильмов для каждого символа, что даст нам большую гибкость при изменении размеров, перемещении и т.д.
Нам нужно иметь возможность передавать функции объект textFormat и строку, что можно реализовать следующим образом.
function charPositions(tFormat, str, depth) {
. . .
}
Мы также включим параметр depth, чтобы можно было указывать его извне, предотвращая запись поверх любых других объектов.
Dynamic Text в месте, отличном от вашего рабочего места. Установите для этого текстового поля шрифт Arial.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 в диалоговом окне Character Options:

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 = [] ;
}
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 со всеми конечными координатами.
Использование данных о символах для плавного появления текста
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.
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);
Вы могли обратить внимание на то, что метод, который мы использовали для нахождения конца каждой строки и перехода на следующую строку, может разделять слова посередине. Мы не будем подробно рассматривать здесь это явление, но можно изменить метод так, чтобы слова не разделялись. Сначала идет проход по строке и вычисление ширины каждого отдельного слова, а затем эти значения складываются для определения места, где они выходят за пределы правой границы. После этого осуществляется переход к следующей строке.
В данном упражнении мы будем создавать другой файл, основанный на предыдущем, чтобы показать вам, насколько просто осуществлять управление, когда уже есть основные необходимые значения, и, кроме того, мы расположим символы в случайном порядке.
Реализация случайного появления символов
drawNext. Откройте useCharPos.fla и приготовьтесь вносить в него изменения.Функция drawNext необходима для случайного выбора символа из массива и его прорисовки. Затем символ будет удаляться из массива, после чего будут оставаться только те символы, которые все еще должны быть прорисованы. Код реализации этой функциональности довольно прост. Сначала выбирается случайное число между 0 и числом записей в массиве. Затем эта запись переносится из массива во временную переменную. После этого элемент удаляется из массива с помощью метода .
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. Мы будем располагать каждую картинку в своем собственном фильме и затем динамически применять их.
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);
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 ()
}
}
}
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", которая инициализирует текстовый эффект по достижении фильмом конечной точки. Наконец, нам нужно удалить любой уже присутствующий текст. Для этого в конце программы вызываем функцию .
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();
}
}
}
Следует заметить, что мы создали отдельный фильм для текстового эффекта. Он выступает как в роли главного фильма, содержащего отдельные фильмы для букв внутри себя, так и в роли управляющего фильма, т.к. буквы сначала создаются, а затем опять удаляются при переключении фотографий. Последний фильм textHolder хранится в переменной latestText. При переключении фотографий текст в latestText будет удаляться. При создании основного фильма нужно знать, какими являются все символы и в каком месте они должны быть размещены. Для получения этой информации мы используем массив символов текущей картинки. Так как мы собираемся удалять элементы этого массива, мы создаем копию массива с помощью slice в фильме, не трогая оригинал. Метод slice используется, в основном, для возврата элементов из массива между двумя точками, так, например, arr.slice (2,5) возвратит копию элементов массива с 2 по 5. При вызове его без аргументов будет возвращена копия всего массива.
latestText.characters=currentPicture.characterArr.slice ()
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]);
Мы завершили создание расширенного интерфейса изображений. Сохраните его и запустите - все должно работать безупречно.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.