Изучаем программирование на html5 (head first o'reilly) 2013 part 002

Page 1

тестирование интервального таймера

Tecm-драйб таймера Э т о будет весело. Убедитесь, что вы набрали функцию h andleRef resh, а также внес­ ли изм енения в обработчик onload. С охраните все, а затем загрузите код в своем браузере. В результате вы долж ны увидеть ноток откры ваю щ ихся диалоговы х окон alert, остановить которы й сможете, лиш ь закрыв окно браузера!

------------------------------------------------------------------

1

h ttp ://lo c a lh o s t Cm alive

С

Л

Возьми в руку карандаш

4

Вот что мы получим!

Теперь, когда вы знаете, что такое setlnterval (не говоря уже о XMLHttpRequest и JSONP), задумайтесь над тем, для чего еще вы могли бы использовать их в других веб-приложениях. Напишите свои ответы здесь.

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

300

глава 6

OK

3


общение с веб-службами

Шаг 3: повторная реализация JS0NP Мы но-нрежнему х о т и м иснользовать JSO P для и звлечения данных, однако нам необходим снособ делать это нри каждом вызове обработчика h a n d le R e f re s h , а не только во врем я загрузки страницы. И менно здесь на сцену выходит объектная модель документа. Ее зам ечательная особенность заклю ча­ ется в том, что мы можем вставлять элементы в DOM в любой момент, даже элементы < s c r i p t >. Таким образом, мы долж ны иметь возмож ность вставлять новы й элемент < s c r ip t > всякий раз, когда захотим соверш ить JSO N P-вызов. Д авайте наниш ем соответствую щ ий код, воснользовавш ись всеми наш ими знаниям и о DOM и JSONP.

Сначала зададим URL-адрес JS0NP Это будет тот же самый URL-адрес, который мы использовали с нашим предыдущим эле­ ментом < s c r i p t > . Здесь мы присвоим его переменной для последующего использования. Удалите a l e r t из своего обработчика и добавьте вот этот код: Снова возвращаемся к нашей функции handleRefresh.. ^

Задаем UIZL-adpec JSONP и п р и сваиваем его переменной urli

function handleRefresh () { var url = "http://gumball.wickedly smart.com? callback=updateS ales " ;

}

Далее создадим новый элемент < script> На этот раз вместо имеющегося элемента < s c r i p t > в составе нашей HTML-разметки, мы будем создавать такой элемент с использованием JavaScript. Нам потребуется создать элемент < s c r i p t > , а затем задать соответствующие значения для его атрибутов s c r и id : function handleRefresh () { var url = "http://gumball.wickedly smart.com? callback=updateS ales " ;

var newScriptElement = document.createElenient (" script") newScriptElement.setAttribute (" src" , url) ; newScriptElement.setAt tribute ("id" , "jsonp") ;

r Метод setA ttrib u te может показаться вам ч е м -т о новым (мы лишь мимоходом упоминали его ранее), однако несложно понять, что он делает . Данный м ет од позволяет задавать значения для ат рибут ов HTML-элем ент ов (например, для scr и id), а также для множества других, включая class, href и m. д.

Сначала мы создаем но ­ вый элем ент <scnpt>... ...а за т е м присваиваем его а т р иб ут у scr значение виде URL-адреса JSONP. Мы также присвоим данному элем ент у <script> иден т и ф и ка т ор , чтобы его можно было без труда найти позже, что, как вы увидите, нам и п о т р е б у ­ ется сделать.

дальше ►

301


вставка jsonp в dom

Как мы будем Вставлять элемент < script> 6 DOM?? Мы ночти д о с т и г л и цели, осталось только н роизвести вставку нашего нового элем ента <script>. Как только мы сделаем это, браузер увидит его и нреднрим ет соответствующ ие действия, что нриведет к соверш ению JSO N P-вызова. Вставка элем ента <script> требует небольш ого планирования и предусмотрительности; давайте но смотрим, как все это работает: Начнем с объектной модели докумен­ та где отсутствует элемент <script> с id в виде "j sonp" (на данный мо-

X

©

В коде нам потребуется извле­ кать ссылку на элемент <head>.

©

<script> в элемент <head>.

Затем мы вставим новый элемент

П осле того как мы вставим <script>, браузер увидит этот новы й элемент в объектной модели до­ кумента (DOM) и отнравится извлекать то, что раснолож ено но URL-адресу, которы й задан в каче­ стве зн ачен ия атрибута scr. Однако у нас также имеется второй вариант иснользования. Взглянем на него. /Cpv Теперь, за исключением времени, когда происходит первый вызов handleRefresh, у нас уже будет иметься элемент <script> с id в виде "jsonp" в DОМ.

title

meta

данном случае мы снова будем из­ влекать ссылку на элемент <head>.

script

link

script id--"jsonp" src^'httpV/gumbollwi;

г

302

глава 6

На этот раз мы заменим существующий элемент нашим новым элементом вместо того, чтобы добавлять новый <script> в объектную /модель документа. Да, можно было бы добавить новый <script>, то есть браузер инициировал бы JSONP-вызов, однако со временем у нас бы накопилась огромная коллекция элемен­ тов <script> в DOM, а это уже может сказаться на производитель­ ности. Поэтому замена элемента будет оптимальным выбором.


общение с веб-службами

Теперь напишем код для вставки < script> в DOM Теперь, когда вы знаете необходимые шаги, давайте взглянем на код. Здесь мы тоже выполним два шага: сначала покажем вам код для добавления нового <script>, а затем продемонстрируем код для замены <script>: function handleRefresh() { var url = "http://gumball.wickedlysmart.com?callback=updateSales" ;

var newScriptElement = document.createElement (" script") ; newScriptElement.setAttribute("src", url); newScriptElement.setAttribute("id", "j sonp");

var oldScriptElement = document.getElementByld("jsonp") var head = document.getElementsByTagName("head")[0]; if (oldScriptElement == null)

{

head.appendChild(newScriptElement);

} Теперь, когда у нас есть ссылка на элем ент <head>, мы п р о ­ веряем, имеется ли т а м уже элем ент <script>, и если он о т ­ с у т с т в у е т (о чем будет свидетельст вовать возврат зн а ­ чения null при попытке извлечь на него ссылку), мы добавим новый элем ент <script> в <head>.

Сначала мы будем извлекать ссылку на элем ент <script>. 8 случае его о т ­ сут ст вия будет возвращено null. О брат ит е внимание, что мы рассчитываем на то, что он будет и м е т ь id со значением «jsonp». Д алее будем извлекать ссылку на элем ент <head>, используя новый м ет од объекта document. О т о м , как он работ ает , мы п о ­ говорим позже, а пока просто знайт е, что он извлекает ссылку на э л е ­ м е н т <head>.

Итак, взглянем на код для замены элемента <script> в случае, если вы­ ясняется, что таковой уже существует. Мы рассмотрим только условный оператор if, в котором сосредоточен весь новый код: Наил условный оператор, который, как вы пом нит е, п р о веряет, сущ ест вует ли уже элем ент <script> в РОМ. if (oldScriptElement == null)

{

head.appendChiId(newS criptElement); } else { head.replaceChild(newScriptElement, oldScriptElement);

} \

Если в <head> уже имеет ся элем ент <scnpt>, мы просто заменяем его. Мы используем м ет од replaceChild в отношении <head> и передаем ему new ScriptE lem ent и oldScriptElement для выполнения данной процедуры. Через несколько мгновений мы подробнее поговорим об эт ом методе.

дальше ►

303


подробнее о дополнительных методах для работы с dom

g e t^e in e n b ^y X a g ^a K ie п о д у в е л и ч и те л ь н ы м с т е к л ° м ________________ Это было ваше нервое знакомство с методом g e tE le m e n tsB yT a g N a m e , ноэтому быстро ис­ следуем его нодробнее. О н нодобен методу g e tD o c u m e n tB y ld за исклю чением того, что возвращ ает массив элементов, соответствующ их определенному имени тега. getElem entsByTagNam e возвращает все элем е н т ы , с о о т е т ст вую щ и е данному т е г у , которые им ею т ся в DOM

\ var arrayOfHeadElements = document.getElementsByTagName ("head" ) ;

3 данном случае он возвращает массив элементов <head>. Получив массив, можно извлечь н ервы й его элемент, иснользуя индекс 0: £

Л

var head = arrayOfHeadElements [0] ;

Возвращает первый элем ент <kead> в Массиве (и т а м ОН должен быть единственным, не т ак ли?).

А сейчас давайте объединим обе эти строки следующим образом: var head = document.getElementsByTagName ("head") [0];

Извлекаем массив, а за т е м используем индекс в нем для и звле­ чения первого элем ент а, причем делаем все это за один подход. В нриведенном н рим ере кода мы ностоянно иснользуем н ервы й элемент <head>, однако вы мож ете нрим енять метод ge tE le m e n tsB yT a g N a m e в случае с любыми тегами: <р>, < d iv > и т. д. П ри этом вы обычно будете нолучать обратно более одного из соответствующ их элементов, которы е имею тся в массиве.

Гер1асе(Ти1с1 по д у в е л и ч и те л ь н ы м с т е к л ° м

____________________________

Взглянем также на метод r e p la c e C h i I d , носко льку вы не встречали его раньш е. Д анны й ме­ тод следует вызы вать но отнош ению к элементу, в котором вы хотите зам енить дочерни й элемент, нередав ему ссылки на н овы й и стары й дочерние элементы. М етод r e p la c e C h ild нросто зам еняет стары й д очерни й элем ент новым. Метод replaceChild дает ук а за ние э лем ент у <head> зам енит ь один из его дочерних элементов с именем oldScn'ptElement новым элем ент ом с именем new S cnp tE lem en t. ^

Наш новый элем ент <scnpt>.

Элемент <script>, который уже и м е ется на странице.

head.replaceChild(newScriptElement, oldScriptElement) ;

304

глава 6


общение с веб-службами Часш°

Задаваем ы е В сЩ роСъх 1 3 : п о „ , „ е н

„ ь , ________ „

Как можно узнать параметры веб-службы? И то, поддер­

вместо того, чтобы заменять элемент <script> целиком?

живает ли она JSON и JSONP?

0 : Если вы лишь замените значение атрибута s c r элемента < s c r ip t > новым URL-адресом, браузер не будет рассматривать его как новый элемент < s c r i p t > и, следовательно, не станет

0 : В случае большинства веб-служб публикуется общий APIинтерфейс, который включает способы доступа к конкретной службе, а также описание всего того, что можно сделать с ее помощью. Если вы используете коммерческий API-интерфейс, то вам может потребоваться получить соответствующую документацию напрямую от поставщика. Информацию относительно большей части общих API-интерфейсов вам, скорее всего, удастся найти в Интернете, используя поисковик либо зайдя в раздел для разработчиков на сайте соответствующей организации. Вы также можете посетить, например, сайт programtheweb.com, где документируются APIинтерфейсы, список которых постоянно увеличивается.

совершать запрос для извлечения JSONP. Чтобы заставить бра­ узер выполнить запрос, необходимо создать абсолютно новый элемент < s c r ip t > . Данная методика называется скриптовой

инъекцией. ^ 3 * Что происходит со старым дочерним элементом, когда я заменяю его новым?

Q j Он удаляется из объектной модели документа (DOM). А что произойдет дальше, будет уже зависеть от вас: если у вас попрежнему имеется ссылка на него, сохраненная в находящейся где-то переменной, то вы сможете продолжить использовать его (любым путем, который будет иметь смысл). Если же у вас ее нет, то среда выполнения JavaScript в конце концов регенерирует (освобо­ дит) память, которую занимает данный элемент в вашем браузере.

Очевидно, что XMLHttpRequest старше HTML5, а как насчет JSON и JSONP? Являются ли они частью HTML5? Нужен ли мне HTML5, чтобы использовать их?

getElementsByTag?

0 : Мы бы назвали JSON и JSONP современниками HTML5. Ни один из них пока не определен спецификацией HTML5, од­ нако они активно используются HTML5-пpилoжeниями и играют важнейшую роль в процессе создания веб-приложений. Таким образом, несмотря на то что мы говорим HTML = Язык разметки + API-интерфейсы JavaScript + CSS, JSON и JSONP также являются весомой частью данной картины (равно как и запросы с использо­ ванием HTTP И X M LH ttpR e q u e s t).

0 : По определению HTML-файл включает только один элемент

^

<head>. Следует отметить, что, конечно же, кто-то может включить

время везде уже господствует JSON?

А что, если в HTML-файле будет более одного элемента <head>? В случае с вашим кодом, по-видимому, предполага­ ется, что там будет только один элемент <head>, поскольку вы используете индекс 0 в массиве, возвращаемом методом

и два таких элемента в HTML-файл. В этом случае получаемые ре­ зультаты могут варьироваться (так и будет, если вы не произведете валидацию своего HTML!), но браузер, как обычно, постарается приложить максимум усилий, чтобы сделать все правильно (а что именно считается правильным, зависит от браузера). Можно ли остановить интервальный таймер после его запуска?

0 : Конечно, можно. Метод s e t l n t e r v a l возвращает значение id , которое идентифицирует таймер. Сохранив данное значение i d в переменной, вы сможете в любой момент передать его методу c l e a r i n t e r v a l для остановки таймера. Закрытие браузера

J Продолжают ли люди использовать XML? Или в настоящее

0 : В компьютерной индустрии существует одна прописная истина, согласно которой ничто никогда не умирает. При этом также следует отметить, что JSON в настоящее время набирает обороты, в силу чего создание многих новых веб-служб осуществлялся именно с его помощью. Вы часто будете сталкиваться с тем, что многие веб-службы поддерживают разнообразные форматы, включая XML, JSON и массу других (например, RSS). Преимуществом JSON является то, что он основан непосредственно на JavaScript, a JSONP позволяет избежать междоменных проблем.

также останавливает таймер.

дальше ►

305


разбираемся с кэшем браузера

Чуть не забыли сказать: берегитесь опасного кэша браузера Мы н о ч т и г о т о в ы нерей ти к тестированию , однако сначала нужно нозаботиться об одной небольш ой детали, которая относится к нроблемам тина «если вы никогда не делали этого нрежде, то как вы вообщ е узнаете, что вам необходимо с этим снравиться». У больш инства браузеров имеется лю боны тная особенность: если вы извлекаете данны е, м ногократно иснользуя один и тот же URL-адрес (как наш JSO N P-занрос), то браузер в конце концов нроизведет их кэш ирование в целях новы ш ения нроизводительности, и вы будете снова и снова нолучать обратно один и тот же кэш ированны й файл (или данны е). А это не то, что нам нужно. К счастью, существует нростое и старое, как И нтернет, «лекарство» от этого. Все, что нам нотребуется сделать, —это обеснечить добавление случайного числа в конец URL-адреса. Благодаря этой хитрости мы заставим браузер думать, что неред ним новы й URL, которы й он никогда не видел нрежде. О ткор­ ректируем наш код, изменив приводившуюся ранее строку с URL-адресом: Аанный код вы найдете в верхней часты своей функции handleRefresh.

И зм енит е приводившееся раньше объявление url, чтобы оно стало выглядеть так.

var url = "http://gumball.wickedlysmart.com/?callback=updateSales" + "&random=" + (new Date()).getTime();

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

Создаем новый объект Date и используем мет од getT im e объекта Date для извлечения значения времени в миллисекундах, после чего добавляем это значение в конец URL-адреса,

Благодаря этому новому коду сгенерированны й URL-адрес будет выглядеть нрим ерно так: Эта часть уже должна быть вам знакома...

д gom п а р ам е т р random.

http://gumball.wickedlysmart.com?callback=updateSales&random=1309217501707

У * Эта часть будет каждый раз изменяться для предотвращения кэширования. Зам ените объявление н ерем ен ной url в своей функции handleRefresh нредставленны м здесь кодом, но еле чего вы будете готовы к нроведению тест-драйва!

306

глава 6


общение с веб-службами

Еще раз проводим тест-драйв Итак, на этот раз мы, несом ненно, все предусмотрели. Все должно быть нолностью готово. Убедитесь, что вы добавили весь код, приводивш ийся с момента носледнего тест-драйва, и перезагрузите страницу. П рекрасно, тен ерь мы видим, как данны е н епреры вно обновляются!

Гу5АМ Mighty Gumball

M ig h ty G um ball Постойте-ка... вы видите то же, что и мы? Что это еще за дубликаты? Это нехорошо. Хм. Может быть, извлечение происходит слишком быстро и мы получаем отчеты , к о ­ торые уже извлекались ранее?

Дубликат ы!

LOS GATOS sold

2 gumbalfs

[ COURTLAftio sofd

3 gumbaJ|s

C O U R T U N D sold

3 gumballs

FRESNO sold

5 gumballs

COURTLANd sold FRESNO sold

3 gumballs

5 gumbalfs

FRESNO sold 5 gumballs

Как избавиться о т дубликатов отчетов об уровне прода>к Е с л и в ы снова взглянете на специф икации сервера Mighty Gum ball, приводивш иеся на с. 262, то увидите, что в URL-адресе занроса мы можем указать парам етр lastreporttime, как показано далее:

Просто у к а Вы также можете добавить п а р а м е т р lastreporttim e в к о время н е ц U R L -адреса, чтобы извлечь только от чет ы , которые в миллисекундах, по ст упили начиная с указанного времени. Например: oQnj f QQ h t t p : / / gUnba 1 1 . Wic3cedly sma r t .conl/ ?1a s t r e p o J:t t i Iae=1302212903099

Это, конечно, здорово, но как узнать врем я ностунления носледнего отчета, которы й мы извлекали? Д авайте еще раз взглянем на ф орм ат вывода отчетов об уровне нродаж: [{"name":"LOS ANGELES","time":1309208126092,"sales":2}, {"name":"PASADENA","time":1309208128219,"sales":8}, {"name":"DAVIS CREEK","time":1309214414505,"sales":8} . .

.]

У каждого от чет а об уровне продаж имеет ся время его поступления.

дальше ►

307


использование параметра веб-службы

q

V

/

Я понял, к чему вы клоните; то есть мы можем отслеживать время поступления последнего отчета, а затем использовать его, когда будем совершать следующий запрос, чтобы сервер не возвращал нам отчеты, которые мы уже получали?

Вы все правильно поняли. Чтобы отслеживать время поступления последнего отчета, нам нотребует­ ся внести ряд дополнений в функцию updateSales, в которой нроисходит вся обработка данных об уровне продаж. Однако сначала нам нужно будет объявить переменную, в которой будет размещ аться значение времени по­ ступления самого последнего отчета: Поместит е данЗначение времени ный код в g не м о ж е т быть м е т ^ v a r la s tR e p o r tT im e = 0 ; нуЛЯ, поэтому I ЭлЯ J a v a S ^ a° начала просто зада^ дим здесь значение О. ф ункции Тенерь извлечем значение врем ени ностунления самого ноеледнего отчета об уровне нродаж в u pdateSales : function updateSales(sales)

{

var salesDiv = document.getElementByld(Msales"); for (var i = 0; i < sales.length; i++)

{

var sale = sales[i]; var div = document.createElement("div"); d i v . s e t A t t r i b u t e ( Mc l a s s " , Ms a le lt e m " ) ;

div.innerHTML = sale.name + M sold M + sale.sales + M gumballs"; salesDiv.appendChi 1d (div) ;

} if

( s a l e s . le n g t h > 0)

{

la s tR e p o r tT im e = s a l e s [ s a l e s . l e n g t h - 1 ] . t i m e ;

} Если вы взглянете на массив sales, то у в и ­ дите, что самый свежий о т ч ет о прода­ жах является последним в эт о м массиве. Поэтому здесь мы присваиваем его нашей переменной lastReportTime.

308

глава 6

Нам необходимо убедиться в Н АЛ И Ч И И массива; в случае о т с ут ст ви я новых отчетов о продажах будет возвращен пустой массив и наш код сгене р и р у е т исключение.


общение с веб-службами

Обновление URL-agpeca JSON с целью включения lastreporttime Тенерь, когда мы отслеж иваем врем я ностунления носледнего отчета об уровне нродаж, нам необходимо удостовериться в том, что мы отнравляем его на сервер Mighty G um ball как часть JSO N -занроса. Д ля этого отредактируем функцию hand l e R e f r e s h и добавим нарам етр занроса last report time: Разбиваем URL-адрес на не­ function handleRefresh () { сколько ст рок, которые конvar url = "http://gumball.wickedlysmart.com" + S ' к ат енируем друг с другом... "?callback=updateSales" + "&lastreporttime=" + lastReportTime + "&random=" + (new Date()).getTime();

...а вот п а рам е т р lastreporttime со своим новым значением.

var newScriptElement = document.createElement("script"); newScriptElement.setAttribute("src", url); newScriptElement.setAttribute("id", "j sonp"); var oldScriptElement = document.getElementByld("jsonp"); var head = document.getElementsByTagName("head")[0]; if (oldScriptElement == null)

{

head.appendChiId(newS criptElement);

} else { head. replaceChild (newScriptElement, oldScriptElement)

}

Тест-драйв lastReportTime П роведем тестирование нарам етра занроса last reporttime и посмо трим, реш ает ли он нашу нроблему с дубликатами отчетов об уровне про даж. Убедитесь, что вы набрали весь нриведенны й чуть выше новы й код перезагрузите страницу и щ елкните на кнонке Refresh (О бновить). А О О

_

ИЦМуСииМ»__________ |

у

ГлИЗС+З Mighty Gumball Sales LOS ANGELES sold 3 gumballs LOS ANGELES sold

9 gumballs

ATWATER sold 8 gumballs FARMINGTON sold 1 gumboils F A R M IN G T O N sold 1 gumballs

GARDEN GROVE sold 3 gumballs

Отлично! Теперь мы будем получат ь т о л ь ­ ко новые отчеты о продажах, то есть все дубликаты исчезнут!

дальше ►

309


Вы превзошли самих себя! Приложение работает замечательно — теперь я могу быть в курсе уровня продаж как сидя за своим рабочим столом, так и находясь в пути. Я начинаю думать, что в подобных веб-приложениях действительно что-то есть. Только представьте, сколько всего мы сможем сделать, используя автоматы для продажи жевательной резинки в сочетании с J S O N и всеми этими A P I-интерсрейсами HTML5!!


общение с веб-службами

КЛЮЧЕВЫЕ "МОМЕНТЫ ■ XMLHttpRequest

не позволяет запрашивать

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

параметра URL запроса в JSONP-запросе. ■

библиотеками с помощью элемента

к вашим веб-страницам и файлам cookie пользо­

со сторонними JavaScript-библиотеками.

Альтернативой

XMLHttpRequest для доступа

к данным, имеющимся у веб-служб, является JSONP.

Используйте

XMLHttpRequest,

<script> для

совершения

ственно в свой HTML либо посредством добавления

<script> в объектную модель докумен­

элемента

компьютере, что и ваши данные.

та (DOM) с использованием JavaScript.

Используйте JSONP, если вам требуется доступ

Добавляйте случайное число в конец своего URL-

к данным, имеющимся у веб-службы на удаленном

адреса JSONP-запроса, если многократно исполь­

сервере (при этом предполагается, что эта веб­

зуете этот URL для совершения запросов, чтобы

служба будет поддерживать JSON Р). Веб-служба —

браузер не кэшировал ответ. ■

Метод

replaceChild заменяет

один элемент

другим в DOM.

JSONP представляет собой способ извлечения данных с использованием элемента

Указывайте элемент

JSO NP-запроса путем внедрения его непосред­

если ваши

вляется по протоколу HTTP.

HTML- и JavaScript-файлы размещаются на том же

это веб-интерфейс API, доступ к которому осущест­

<script>.

Всегда проявляйте осторожность при связывании

вателей.

JSO NP не является более (или менее) безо­ пасным подходом, чем связывание с JavaScript-

предотвращать доступ вредоносного JavaScript-KOfla

Указывайте функцию обратного вызова в качестве

<script>.

■ set Interval — это таймер,

который вызывает

функции через заданный интервал времени. Вы мо­

setlnterval для

JSONP — это JSON-данные, обернутые в JavaScript;

жете использовать

обычно JSON-данные обертываются в вызов функ­

повторяющихся JSONP-запросов на сервер с целью

отправки

ции.

извлечения новых данных.

Функция, в вызов которой обернуты JSON-данные, в случае с JSONP называется

функцией обрат­

ного вызова.

дальше ►

311


U I M L 5 - K f ° CCBopA Здорово, в этой главе вы научили свое веб-нриложение общ аться с веб-службами! П ора заставить ноработать левое нолуш арие мозга для закрепления материала.

По горизонтали

По вертикали

4. Шаблон использования XMLHttpRequest для извлечения данных 1. В середине данной главы нас подстерегал один из них. ссерверов иногда называют . 2. JSONP означает JSON with__________ . 7. Гуру учила Кузнечика тому, что аргументы функций также являются 3. JSONP использует__________ . 5.Формат, который, как мы все полагали, «спасет» мир. 8.__________ представляет собой новейшую модель автомата 6.__________ ,работающий контролером качества, был расстроен, для продажи жевательной резинки Mighty Gumball с поддержкой под­ когда запрос, отправленный на производственный сервер Mighty ключения кИнтернету. Gumball, потерпел неудачу. 10. Одно из прозвищ XMLHttpRequest в Microsoft. 8. Локальный сервер легко установить в операционной системе 13. Мы допустили_________ ,сначала углубившись на 25 страниц в главу и только затем рассказав вам о браузерной политике безо­ 9. У _________ имеется веб-служба JSONP. пасности. 11. Используемые JSONP типы объектов. 12. Компания Mighty Gumball проводит тестирование модели торгового 15. XMLHttpRequest высмеял слово_______ в названии JSONP. автомата MG2200 в__________ . 14. напомнила Фрэнку,Джиму иДжо о междоменных проблемах, возникающих В случае С XMLHttpRequest.

312

глава 6


общение с веб-службами

Специальное сообщение из главы 7 ...

Пока в вашей памяти еще свежи знания о JSONP, мы хотели бы; чтобы вы помогли нам кое с чем в главе, посвященной элементу v

.

canvas.

Мы работаем с АР1-интерсреисом JSONP T w itte r и создаем службу, ко­ торая дает пользователям возможность размещать на футболках любые твиты.

Мы любим говорить: «Если вы — поклонник T w itte r, то закажите футболку с от­ печатанным на ней твитом».

Оснобятел&ница Tw/eetS^i rt.com

дальш е ►

313


решение кроссворда

314

глава 6


7 р аскр ы в аем б се^е х у д о ж н и к а %

т

Элемент canvas * Да, разметка — это, конечно, здорово, но ничто не сравнится с тем, когда собственными руками раскрашиваешь что-либо свежими, аккуратными пикселами.

HTML больше не является просто языком «разметки».

Благодаря

новому НТМ1_5-элементу canvas у вас появилась возможность собственноруч­ но создавать пикселы , манипулировать ими и уничтожать их. В этой главе мы й-

воспользуемся элементом canvas, чтобы раскрыть таящегося в вас художни-

Ладно, ^

ка — больше никаких разговоров о HTML, когда речь идет чисто о семантике « уИичтои отсутствуют представления; используя canvas, мы начнем раскрашивать и жать» рисовать красками. Теперь все будет опираться на представления. Вы узнаете, Mblj в03~

МОЖНОJ немного ские изображения (естественно, используя JavaScript) и даже как быть в случае перебор ,

как вставлять элемент canvas в свои страницы, как рисовать текст и графиче-

с браузерами, не поддерживающими данный элемент.

^

Как стало известно, на самом деле элементы <canvas> и <video> дела­ ю т нечто большее, чем просто делят друг с другом одни и те же веб­ страницы... Об этих любопытных подробностях мы поговорим позже.

щили.


новый стартап tweetshirt

Наш новый cmapman: TweetShirt Наш девиз звучит так: «Если вы поклоппик Твиттера, по сите фут­ болки TweetShirt». В копце копцов, чтобы пазы ваться журпалистом, нужпо стре­ миться к тому, чтобы паписаппое вами ону бликовали, а лучшее место для печати п а футболке — область груди! По крайпей мере, в этом заклю чается суть коммерческого п ризы ва пашего стартапа, которого мы будем придерж иваться. Ч тобы успешпо полож ить пачало даппому стартану, пам потребуется веб-приложепие, позволяю щ ее клиептам соз­ давать пользовательский дизайп футболок, отраж аю щ ий одип из их педавпих твитов.

t Вероятно, вы подумали: « А зна е т е, это неплохая идея». Что ж , в т аком случае мы с вами успешно положим начало данному с т а р т а п у , создав к концу главы полност ью готовое к работе веб-приложение. А если вы р еш ит е использовать его для зараба­ тывания денег, мы не ст анем заявлять права на и нт е л ле к т уа л ь н ую собственность, но хот я бы вышлите нам бесплатную футболку! Мы любим говорить: «Если вы поклонник Твит­ тера, закажите футболку с отпечатанным твитом».

Нам требуется соответствующее веб-приложение, которое даст пользо­ вателям возможность создавать классные представления их любимых твитов.

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

Основательница Т\л/ е et S Кir t ’-со w

316

глава 7


раскрываем в себе художника

Взгляд на «оригинал-макет» П роведя исчерпывающ ую итеративную разработку и обш ирпое тестирование с участием фокус-группы, мы создали оригипал-макет (процесс его создапия по-другому пазы вается пачальпы м визуальпым проектированием ), па которы й сейчас и взгляпем. Это наш ст арт ап. Сначала мы все нарисовали на са лф ет ке, сидя болки в Starbuzz Coffee. Д изайн

Наше веб-приложение должно по возмож­ ности выглядеть, как данная с т р а н и ­ ца! Д р у ги м и словами, мы х о т и м показывать дизайн ф утболки и предоставлять п о л ь ­ зоват елю возмож­ ность интерактивно изменят ь его с п о ­ мощ ью элемент ов управления.

А вот как v должен вы гля\ деть интерфейс \ пользователя. S elect background c o lo r

Пользователь сможет выбирать цвет фона (Select background color), круги или квадраты для отображения на фоновой по верх­ ности (Circles or Squares?), цвет т екст а (Select t e x t color) и т в и т (Peek a tweet).

JVK/teJ* ]

Circles o r Squares?

jarcies | ; j

Select text color.

fdlackJ^J

Peek a tweet: |p V g w e w j

дальше ►

317


обзор требований

9

М

*

Г

9

*

9

Й

_____________________________________________________________________________________________________________________________________________________________________________________

Ш ТУРМ Взгляните еще раз на требования, приведенные на предыдущей странице. Как вы считаете, можно ли их выполнить, используя HTML5? А помните, что одно из требований заключает­ ся в обеспечении работоспособности вашего сайта на как можно на большем количестве устройств различного формата и размера? Ознакомьтесь с приведенными ниже возможностями (а затем выберите наилучший ответ). □

Можно просто использовать технологию Flash, поскольку она работает в боль­ шинстве браузеров.

Можно обратить свой взор на HTML5 и посмотреть, есть ли какие-нибудь но­ вые технологии, которые могут помочь (подсказка: есть одна такая технология под названием canvas).

j

|

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

Часш°

ЧаДаВаеМые В опросы

А серьезно, почему бы в данной ситуации не использо­

Мне нравится идея генерирования изображений на сторо­

вать Flash или не прибегнуть к написанию пользовательского

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

приложения?

который вместе с генерируемыми изображениями сможет

0 : Flash является замечательной технологией и вы, несомненно, можете использовать именно ее. Однако в настоящее время инду­ стрия движется по направлению к HTML5, и на момент написания данной книги у вас могли бы возникнуть проблемы с выполнением Flash-приложений на всех устройствах, включая очень популярные.

эта задача должна быть мне по плечу.

работать на всех устройствах. Я немного знаю РНР, так что

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

318

глава 7

0 : Это еще один путь, по которому вы можете пойти, однако его недостаток заключается в том, что если у вас будет огромное множество пользователей, вам придется беспокоиться о масштаби­ ровании используемых для генерирования изображений серверов, чтобы они смогли удовлетворить предъявляемые требования (в противопоставлении с тем, когда клиент каждого из пользовате­ лей сам будет генерировать предварительный просмотр футболки). Вы также сможете обеспечить более интерактивное и цельное взаимодействие, если предпочтете написать соответствующий код для браузера. Как? Что ж, мы рады, что вы об этом спросили...


раскрываем в себе художника

LiuV

Заглянем к ребятам из команды TweetShirt... Вы уже ознакомились с требованиями, а также с базовым проектировани­ ем взаимодействия пользователя с приложением. Пришло время перейти к сложной части — реализации всего этого на практике. Давайте прислуша­ емся к разговору и узнаем, как обстоят дела...

Джо: Я думал, что все будет просто, пока пе увидел эти ф оповы е круги. Фрэнк: Ч то ты хочеш ь этим сказать? Ведь это всего лиш ь изображ епие... Джудн: Нет, пет, осповательпица TweetShirt хочет, чтобы разм ещ епие кругов происходило случайпым образом, благодаря чему располож ение кругов, к примеру, па м оей футболке будут отличаться от располож ения кругов па твоей. То же самое и с квадратами.

Я ^ фрэнк> Л w А* 0

Фрэнк: Все пормальпо, поскольку рапы не мы делали это, геперируя изобра­ ж епие п а сторопе сервера.

Джо: Да, я зпаю, по такой подход был пе очепь разумпым; помпите, как пам приходилось платить ком папии Am azon за пользовапие серверами?

Фрэнк: Да. Но это пе беда. Джо: В лю бом случае, пам пеобходимо, чтобы все работало очепь быстро, то есть пе было пикаких долгих «рейсов» обратпо па сервер. Поэтому давай­ те будем делать все па сторопе клиепта, если это возможпо.

Джудн: Ребята, я думаю, что это возможпо, я тут смотрю па canvas в HTML5. Фрэнк: Я всего лиш ь дизайпер, поэтому разъяспи мпе, что это такое. Джудн: Ф рэпк, ты, должпо быть, уже слышал о canvas —это повы й элемепт в HTM L5, которы й п озволяет создавать поддерживающую рисовапие об­ ласть для 2 Б-фигур, текста и растровы х изображ епий.

Фрэнк: Все это похож е па тег <img>. Мы просто помещ аем его в страпицу с указапием ш ирипы и высоты, а браузер делает все остальпое.

Джудн: Н еплохое сравпепие, мы действительно определяем ш ирину и вы­ соту для canvas, одпако в даппом случае все рисуемое в canvas будет зави­ сеть от JavaScript-кода. Джо: А где здесь в дело вступает разметка? М ожпо ли сказать canvas па JavaScript: «Даппый элемепт <hl> пеобходимо разм естить вот здесь».

Джудн: Нет, после того как ты помещ аеш ь canvas в страпицу, ты оставляеш ь мир разм етки позади; па JavaScript мы размещ аем точки, липии, коптуры, и зображ епия и текст. Это пизкоуровпевы й API-иптерфейс.

Джо: Ч то ж, если оп сможет справиться со всеми этим и размещ аемы ми слу­ чайпы м образом кругами, то оп мепя устраивает. Ладпо, хватит разговоров, давайте взгляпем па пего! дальше ►

319


добавление canvas к странице

Как добавить canvas в свою веб-страницу Ф рэпк был прав в том, что canvas песколько схож с элемептом осущ ествляется следующим образом:

Элемент canvas п ред­

I

Д обавлепие

canvas

Аналогичным образом height определяет верт икальную об­ л аст ь веб-страницы, кот орую будет за ним ат ь элем ент canvas (в данном случае — 2-00 пикселов)-

А т р и б у т w idth опреде­ ляет количество пикселов по горизонтали, которое canvas будет заним ат ь на веб-странице.

ст а вл яе м собой обычный HTML-э лем ент , в нача­ ле которого располага­ ется открывающий тег <canvas>.

<img>.

К

Ccanvas id=MlookwhatIdrewM width="600

v.

height=lf200"></canvas>

I

Мь/ добавили id для иден­ тификации canvasj а как его использовать, вы увидите чут ь позже...

Здесь для w idth мы задали значе­ ние (оОО пикселов.

Браузер выделит пространство па веб-страпице для и height.

canvas

I Закрывающий тег

согласпо указаппым зпачепиям

width

В данном случае значением w idth является (оОО> а зн а " чением height — 2-00.

Аевая верхняя позиция canvas. Ъудем использо­ ват ь э т у точку, чтобы о т м е р ят ь все остальное в canvas (в чем вы вскоре убедитесь)

L&ok

ID'rw

Высота canvas (в н а ­ шем случае она равна 2.00 пикселам). Вокруг canvas имеется неболь­ шое п р о с т р а н ­ ство, п р ед с т а в­ ляющее собой поле по умолчанию элемент а <body>.

/

I Ширина canvas (<ЬОО пикселов) Ваш повседневный

I—Может об т е­ к а т ь canvas. Элемент canvas является т аким

же, как и любой другой элем ент (например, im age и т. п..).

320

глава 7


раскрываем в себе художника

Tecm-драйв вашего нового canvas П риш ло врем я задействовать даппы й элемепт па ваш ей веб-страпице. Н аберите приведеппы й пиж е код и сохрапите его в повом файле, а затем загрузите в своем браузере. < ! d o c ty p e h tm l> < h tm l la n g = " e n " > <head> < t i t l e > L o o k W hat I D r e w < / t i t l e >

Напечатайте данный код и п р о т е с т и р у й т е его.

< m eta c h a r s e t = " u t f - 8 "> < /h e a d > <body>

< ca n va s id = " lo o k w h a t I d r e w " w id t h = " 6 0 0 " h e i g h t = " 2 0 0 " > < /c a n v a s >

< /b o d y > < / h tm l>

В чем дело? Моя страница пуста!

Вот что видит она...

...вероятно, то же са ­ мое увидите и вы! Мы нарисовали эти линии, чтобы объяс­ нить, как именно canvas вставляется в с т р а н и ­ цу, и сделали это лишь в целях иллюстрирования. На самом деле их т а м не будет (если только вы их сами не нарисуете).

\л Переверните страницу, чтобы узн ат ь больше... дальше ►

321


добавление css для canvas

Как увидеть свой canvas П ока вы пе парпсуете что-пибудь в элемепте c a n v a s , вы его пе увидите. О п просто является простран ­ ством в окпе браузера, в котором вы мож ете рисовать. Рисовапием в c a n v a s мы займемся очепь скоро, а па даппы й момепт пам требуются доказательства того, что c a n v a s действительно присутствует в па­ ш ей страпице. Существует другой способ увидеть ca n v a s ... Если мы прим епим CSS для стилизации элем епта < c a n v a s> , чтобы стала видимой его рамка, то сможем увидеть его па страпице. Задействуем простой стиль, кото­ ры й добавляет черную рамку ш и ри пой 1 пиксел для ca n v a s . < ! d o c ty p e h tm l> < h tm l la n g = " e n " > <head> < t i t l e > L o o k W hat I D r e w < / t i t l e > <m eta c h a r s e t = " u t f - 8 "> < s t y le > ca n va s

{

b o rd e r:

lp x

s o lid

b la c k ;

Mы добавили ст иль для canvas, который просто р и су ет черную границу толщиной пиксел, к о т о ­ р у ю можно видеть на странице.

< /s ty le > < /h e a d > <body> < ca n va s id = " lo o k w h a t I d r e w " w id t h = " 6 0 0 " h e i g h t = " 2 0 0 "> < /c a n v a s > < /b o d y > < / h tm l>

Так намного лучше! Теперь мы видим canvas. Д а льш е сде­ лаем с ним кое-чт о интересное...

322

глава 7

ooo

Look What I Drew


раскрываем в себе художника Часш°

^адаВ аеМ ы е В опросы

На каждую страницу может приходиться только один canvas?

Можно ли использовать CSS для задания ширины и высо­ ты canvas вместо атрибутов width и height в случае с данным элементом?

0 : Нет, вы можете вставлять в страницу столько элементов

canvas, сколько вам потребуется (либо то количество, с которым сможет справиться браузер или ваши пользователи). Просто при­ свойте всем им уникальные id , и вы сможете рисовать в каждом из них как в отдельном canvas. Вскоре вы увидите, как использовать i d элемента canvas.

В

Является ли canvas прозрачным?

0 : По умолчанию c a n v a s является прозрачным. Вы можете рисовать в элементе ca n va s, заполняя его цветными пикселами. Как именно это делается, вы узнаете позже в данной главе. Если canvas прозрачен, то это означает, что я могу раз­ местить его поверх другого элемента, чтобы, например, на­ рисовать что-нибудь на изображении или еще на чем-либо, имеющемся на странице, ведь так?

0 : Все верно! Это одна из замечательных особенностей canvas. Он позволяет добавлять графику в любую часть веб-страницы.

0 : Да, можно, однако здесь все будет работать немного подругому, чем вы могли бы ожидать. По умолчанию элемент canvas имеет ширину 300 пикселов и высоту 150 пикселов. Если вы не за­ дадите атрибуты w id t h и h e ig h t в теге < c a n v a s >, то элемент получит размеры по умолчанию. Если вы затем зададите размеры, используя CSS, допустим, 600 х 200 пикселов, то c a n v a s раз­ мером 300 х 150 пикселов подвергнется масштабированию в соответствии с этими новыми параметрами, равно как и все, что будет в нем нарисовано. Это сродни масштабированию изобра­ жения путем задания для него новых ширины и высоты, которые больше или меньше, чем реальные ширина и высота этого изо­ бражения. А при увеличении на изображении будет наблюдаться пикселизация, не так ли? Тоже самое происходит и в случае с c a n va s. Элемент ca n va s шириной 300 пикселов, масштабируемый до ширины 600 пикселов, будет включать прежнее количество пикселов, но растянутых вдвое, из-за чего все станет выглядеть несколько неуклюже. Однако если вы задействуете атрибуты w id t h и h e i g h t в < c a n v a s >, то сможете задать для ca n v a s размеры, которые будут больше (или меньше), чем 300 х 150 пикселов, и все создаваемое в этом c a n v a s будет отрисовываться нормально. Таким образом, мы рекомендуем задавать атрибуты тега w i d t h и h e i g h t и не прибегать к CSS для настройки данных свойств, если только вы действительно не хотите масштабировать ca n va s.

Ш ТУРМ Возможно, вы обратили внимание на то, что наш элемент canvas не включал никакого содержимого. Если поместить текст между тега­ ми, то что, по вашему мнению, будет делать браузер, когда страница загрузится?

° #)

< / canvas>

I

дальше ►

323


рисование в canvas

Рисование в элементе canvas Н а даппы й момепт у пас имеется нустой элемепт canvas. Н е будем медлить, постараемся обрести вдохповепие как JavaScript-писатели и поместим в паш canvas прямоугольпик с черп ой заливкой. П ред­ варительно пам потребуется реш ить, где имеппо оп будет распола­ гаться и пасколько большим мы его сделаем. Как пасчет того, чтобы его м естополож епие было х = 1 0 и у = 1 0 пикселов, а вы сота и ш ирипа равпялась 1 0 0 пикселам? Так и поступим. А теперь взгляпем па код, которы й пам будет для этого пеобходим: — < ! d o c ty p e h tm l>

Сначала идет с т а н дартный HTMLS.

< h tm l la n g = " e n " > <head>

Наша C SS -рам ка остается на месте.

< t i t l e > L o o k W hat I D r e w < / t i t l e > <m eta c h a r s e t = " u t f - 8 " />

г

< s t y le >

0т наш обработчик onload; рисовать мы начнем п о е м полной загрузки страницы

13

c a n va s

{ b o rd e r:

lp x

s o lid

b la c k ;

}

< /s ty le > < s c r ip t > w in d o w .o n lo a d = f u n c t i o n () v a r canvas

{

d o c u m e n t. g e tE le m e n tB y ld ( - t s h ir t C a n v a s »> ;

Д л я рисования в canvas нам п о ­ т ребует ся ссылка на него. Воспользуемся g etE lem en tB yld , чтобы извлечь ее из РОМ.

это инт ересно, нам я н° рисовать...

v a r c o n te x t = canvas . g e tC o n te x t ("2 d ") ;

c o n t e x t . f i l l R e c t (1 0 , 1 0 , 1 0 0 , 1 0 0 ) ; ^ “ "

А ' }; < /s c r ip t> < /h e a d > <body>

Эти числа являются позицией х, у

Т

И спользуем конт екст 2 d для рисования прямоугольника с заливкой в canvas.

Здесь у нас также им ею т ся ширина и высота (в пикселах),

Любопытно то, что м ет од fillRect не п рини м ает цвет заливки... Подробнее об э т о м мы поговорим чут ь позже.

< ca n va s w id t h = " 6 0 0 " h e ig h t = " 2 0 0 "

id = " t s h ir t C a n v a s " > < / c a n v a s >

< /b o d y > < / h tm l>

И не будем забывать о нашем элем ент е canvas. Здесь мы определяем canvas шириной (ЬОО и вы­ сотой ZOO пикселов, с id в виде "tshirtCanvas".

324

глава 7


раскрываем в себе художника

Небольшой mecm-драйВ canvas... Н аберите приведеппы й чуть выше код (либо мож ете взять его с h ttp :/ / w ickedlysm art.com /hfhtm l5) и загрузите его в своем браузере. Если вы используете соврем еппы й браузер, то долж пы увидеть п рим ерпо то же, что и мы:

Вот наш прямоугольник с размерами гоо селов, имею щий позицию Ю , 1 0 в canvas.

*

гОО пик

А

А вот наш canvas шириной 6 о о и высотой ZOO пикселов с черной рамкой толщиной 1 пиксел.

Более пристальный Взгляд на код Э то

был

отличпый

пеболы ной тестовы й прогоп, одпако давайте пы рпем пемпого глубже.

В паш ей разм етке мы определили canvas и присвоили ему идентиф икатор, используя тег <canvas>. П ервое, что пам пеобходимо сделать, чтобы пачать рисовать в даппом canvas, —это извлечь ссылку п а объект canvas в объектпой модели докумепта (DOM). Как обычпо, мы делаем это с помощью метода getElementByld:

var canvas = document.getElementByld("tshirtCanvas");

дальше ►

325


обзор работы кода canvas

Мы располагаем ссылкой па элемепт canvas, присвоепп ой п ерем еп пой canvas. Далее пам нужпо разобраться с частью «протокола», которому пеобходимо следовать, прежде чем мы сможем п ерей ти к рисовапию в canvas. Н ам нужпо сказать canvas, чтобы оп предоставил пам коптекст для рисовапия. А в даппом случае пам требуется имеппо коптекст 2 d. Коптекст, возвращ аемы й canvas, п рисваивается п ерем еп пой c o n te x t:

var context = canvas .getContext( ff2 d ff) ; Это часть « прот окола», которому ~ нам необходимо следовать, прежде чем мы сможем п р и с т у п и т ь к ри со ­ ванию в canvas. Теперь, имея в руках объект context, мы можем использовать его для рисовапия в canvas, для чего вы зы ваем метод f i l l R e c t . Д аппы й метод создает прямоугольпик, беря за пачало позицию х, у со зпачепиям и соответствеппо 1 0 , 1 0 , при этом оп будет иметь ширину и высоту 1 0 0 пикселов. О б ра т ит е внимание, что мы вызываем м е ­ тод fillRect в отношении c o n tex t, а не canvas.

j context.fillRect(10, 10, 100, 100);

ч

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

Ш ТУРМ Можете ли вы придумать способ использовать элемент canvas, если ваш браузер поддерживает его, а при отсутствии поддерж­ ки просто выводить сообщение, например: Hey, you, yes

you, upgrade your browser! ! (Эй, вы, да, вы, обно­ вите свой браузер! !)?

326

глава 7


раскрываем в себе художника

4acm<

^аД аВ аеМ ы е BoTLj=>otbl

Ж Л

I ) ; Откуда c a n va s знает, что к прямоугольнику следует применять именно черную заливку? ! В случае c a n v a s черный является цветом по умолчанию. Конечно же, можно изменить это, воспользовавшись свойством f i l l s t y l e , в чем

Т1ля- любознательных ---------------

О

вы вскоре убедитесь. А если мне потребуется нарисовать контур прямоугольника, а не фигуру с заливкой? 0 : Чтобы нарисовать только контур прямоуголь­ ника, вместо f i l l R e c t следует воспользоваться функцией s tr o k e R e c t . Подробнее об обводке мы поговорим позже в этой главе. Что такое контекст 2d и почему нельзя рисо­ вать сразу в canvas?

I canvas представляет собой графическую об­ ласть, отображаемую на веб-странице, c o n te x t — это объект, ассоциированный с c a n va s, который определяет набор свойств и методов, используемых для рисования в can va s. Вы можете даже сохра­ нять состояние c o n te x t, а затем восстанавливать его позже, что иногда бывает кстати. В оставшейся части этой главы вы познакомитесь с множеством свойств и методов объекта c o n te x t.

Интересно, а как предусмотреть в коде проверку на предмет того, поддерживает браузер canvas или нет? Это, конечно же, можно сделать, однако отметим, что все это время предполагалось, что наш браузер поддерживает canvas. Но в любом производственном коде вам будет необ­ ходимо позаботиться о проведении проверки, чтобы убедиться в наличии такой поддержки. Все, что вам потребуется сделать, — это проверить, при­ су тс тв у е т ли метод getContext в с о о тв е т с тв у ю ­ щем объекте canvas getElementByld):

Сначала мы извлекаем ссылку на элем ент canvas в ст ранице.

0

Элемент canvas создавался с расчетом на поддерж­ ку более одного интерфейса — 2d, 3d и пр., о ко­ торых мы даже еще не задумывались. Используя c o n te x t , можно работать с разными интерфей­ сами в пределах одного элемента canvas. Нельзя рисовать сразу в can va s, поскольку необходимо будет указать, какой интерфейс вы используете, выбрав c o n t e x t . Означает ли это, что существует также кон­ текст 3d? Q : Пока еще нет. Существует ряд конкурирую­ щих перспективных стандартов, но не похоже, что какому-либо из них уже удалось стать лидером. Не упускайте из виду данный момент; между тем взгляните на библиотеку WebGL, а также на библи­ отеки, которые ее используют, например SpiderGL, SceneJS и three.js.

(который возвращается методом

v a r canvas =

^

d o c u m e n t .g e t E l e m e n t B y l d ("tshirtCanvas") ; if (canvas.getContext) { // под д е р ж к а canvas имеется } else { // и з в и н и т е , A P I -интерфейс canvas не поддер ж и в а е т с я

} З а т е м проверяем п р и сут ст вие метода getContext. О б р ат и т е внимание: мы не вызываем егоj а просто см о т р и м , есть ли у него значение.

Если вы захотите проводить проверку на предмет поддержки

canvas

без необходимости заранее иметь canvas в своей разметке, то можете создавать элемент c a n v a s «на лету», используя все методики, которые вам уже известны. Например: var

canvas

=

d o c u m e n t .c r e a t e E l e m e n t ("canvas") ;

He забудьте заглянуть в приложение (в конце книги), где име­ ется информация о библиотеке с открытым исходным кодом, которую вы сможете использовать для проведения последова­ тельного тестирования на предмет поддержки всевозможной функциональности в HTML5.

дальше ►

327


canvas и internet explorer

Когда я провожу тест в In te rn e t Explorer, то ничего не вижу там, где должен быть canvas. В чем тут дело?

Internet Explorer поддерживает canvas только с версии 9 и выше, поэтому вы должны преду­ смотреть в коде своей страницы вывод соот­ ветствующего сообщения для пользователей. Дело обстоит следующим образом: если вам дей­ ствительно требуется обеспечить поддержку фупкциональности canvas в браузере In tern et Explorer (версии ниж е 9), то вы мож ете прибегнуть к про­ екту ExplorerCanvas или иному похожему инстру­ менту и использовать его как плагип, обеспечива­ ющий данную функциональность. Теперь предположим, что вы реш или уведомлять своих пользователей о том, что опи упускают заме­ чательное содерж имое вашего canvas. П осмотрим, как это сделать... И, возможноj вы также посо­ ве т уе т е им обновить браузер Internet Explorer до версии <?/

328

глава

7


раскрываем в себе художника

Выходим достойно из проблемной ситуации И так, возможпо возппкповеппе ситуации, когда пользователь реш ит зайти па ваш сайт, по его браузер пе будет поддерж ивать элемепт canvas. Н е хотели бы вы в этом случае вы­ вести для пего сообщ епие о том, что ему следует обповить браузер? Вот код, которы й для этого потребуется: Мы используем типичны й, заурядный элем ент canvas.

/

< can v as id = " a w e so m e c o n te n t" > Hey you, y es YOU, u p g ra d e y o u r b ro w s e r! < /c a n v a s >

\

Сообщение, которое будет выводиться для пользователей, чьи браузеры не подд е р х и в а ю т canvas.

Как это работает? Всякий раз, когда браузер видит пезпаком ы й элемепт, оп по умолчапию вы водит лю бой содерж ащ ийся в пем текст. Таким образом, когда браузеры, пе под­ держиваю щ ие элемепт <canvas>, столкнутся с пим, опи выведут п а э к р а п сообщ епие Неу, you,

yes YOU,

upgrade your b r o w s e r ! ! (эй,

вы,

да,

ВЫ,

обновите

свой браузер!!).

А поддерж иваю щ ие даппы й элемепт браузеры будут просто и гнори ровать лю бой текст между тегами <can v a s > и пе стапут выводить его па экрап.

Г Hey y o u , ye s YOU, upgrade y o u r b r o w s e r !!

За то, что все это делается т ак легко, мы должны побла­ годарить парней (и девушек), за н и м а ­ ющихся разработкой ст андартов HTMLS!

Как вы уже зпаете, другой способ выхода из ситуации, когда браузеры пе поддерж ива­ ю т canvas, заклю чается в использовапии JavaScript с целью вы яспепия того, зпаком ли браузеру даппы й элемепт. Такой подход обеспечивает пемпого большую гибкость в обе­ спечении для пользователей ипого взаимодействия в случае, если их браузеры пе будут поддерж ивать canvas; паприм ер, вы сможете перенаправить их па другую страпицу или взамеп вы вести па экрап какое-то изображ епие.

дальше ►

329


обзор плана реализации

Теперь, когда мы знаем, как создавать прямоугольники, можно использовать аналогичный подход для создания квадратов в canvas, не так ли? Нам необходимо понять, как размещать их на футболке случайным об­ разом, с заливкой цветом, выбранным поль­ зователем.

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

Джудн: Ты прав, Фрэнк. Д вигаться дальше без интерф ей са пе им еет смысла.

Джо: О н, вероятно, будет представлять собой простой HTML?

Фрэнк: Да, похоже. Однако если исходить из того, что мы пы таемся все сделать на стороне клиента, то как оно будет работать? Н априм ер, куда будет отправляться форма? Я не увереп, что понимаю, как все это станет слаж енно функци­ онировать.

Джо: Ф рэнк, мы можем просто вы зы вать JavaScript-функцию, когда пользователь паж мет кпопку Preview (П редва­ ри тельны й просм отр), а затем отображ ать дизайп футбол­ ки в элемепте canvas.

Фрэнк: Звучит разумпо, по как мы получим доступ к зпачепиям ф ормы , если все опи будут располагаться па сторопе клиепта?

Джудн: Тем же путем, каким мы всегда получаем доступ к объектпой модели докумепта (DOM); мы можем восполь­ зоваться docum ent. getE lem entB yld для и звлечепия зпачеп ий формы . Вам уже доводилось делать это рапее.

Фрэнк: Ч то ж, ребята, отступать пам пекуда. Джо: Ладпо, давайте вместе пош агово во всем разберемся. Н ачпем с рассм отрения общ ей картипы .

330

глава 7


раскрываем в себе художника

TweetShirt: общая картина П реж де чем мы приступим к серьезпой работе по реализации задумаппого, давайте взгляпем па общую картипу. Мы собираемся создать веб-приложепие, используя элемент c a n v a s п а р а д у с элемептам и ф ормы , которы е будут играть роль и п тер ф ей са пользователя, а всю работу за кадром будут вы полпять JavaScript и API-интерфейс Canvas. Вот как все будет выглядеть: JavaScript будем о т вечат ь за извлечение введенных п о л ь ­ зоват елем данных из формы и рисование посредством A P I-интерф ейса Canvas. 1

I

а

пхп HTML- будет о\мве

canvas и простои фор

*1 *л ог

с>

Ж

и ш

JS

Это canvas чдля дизайна фмтболки.

^

S elect background color:

L Circles o r Squares? ic'trcles 1*1

, S elect

te x t color:

Z Z T

M(?i будем и с п о л ь з овать JavaScript ъАЯ рисования e canvas графики ^

^

т §олки.

Peek, a tw e e t:

Щелчок на кнопке Preview (Предварительный п р о ­ см от р) будет вызывать JavaScript для выполне­ ния со от вет ст вую щ их действий и генерирования предварительного п р о ­ см от ра футболки.

интерф ейс п о л ь -^ зователя, который n 0 cyvnu явл яется э л е м е н т о м form.

В определенный м о м е н т нам пот ребует ся под­ держка со стороны сервера для торговли ф у т б о л ­ ками через И н т ер не т , но мы реш или ост авит ь э т у часть работы вам (ее придется выполнить, когда вы будете организовывать собственный ст артап). Не забудьте присла т ь нам бесплатную футболку. А если вы, как основатели ст а р т а п а , возьмете нас в долю, то это будет еще лучиле! дальше ►

331


СТАНЬ браузером

КЛ1°Чаетгк:*г Б Л1°М, Чцю&ы сыГ^агщ» |^оЛь браузера

^деЛаБ зщо, сравните БаШ интерфейс с лри— БеДенныМ на 1^едыдущей ог^аниДе, Чцюёы узнать, Бее Ли Бы г^аБиЛьНо сделали. < f огш> <р> < l a b e l f o r = " b a c k g r o u n d C o lo r " > S e le c t b a c k g ro u n d c o l o r : < / la b e l > < s e le c t id = " b a c k g r o u n d C o lo r " > < o p t io n v a lu e = " w h it e " s e le c t e d = " s e le c t e d " > W h it e < / o p t io n > < o p t io n v a lu e = " b la c k " > B la c k < / o p t io n > < / s e le c t > < /p > <p> < l a b e l f o r = " s h a p e " > C ir c le s < s e le c t id = " s h a p e " >

o r s q u a r e s ? < /la b e l>

< o p t io n v a lu e = " n o n e " s e l e c t e d = " s e le c t e d " > N e it h e r < / o p t io n > < o p t io n v a l u e = " c i r c l e s " > C i r c l e s < / o p t i o n > < o p t io n v a lu e = " s q u a r e s " > S q u a r e s < /o p tio n > < / s e le c t > < /p > < l a b e l f o r = " f o r e g r o u n d C o lo r " > S e le c t t e x t c o l o r : < / la b e l > < s e le c t i d = " f o r e g r o u n d C o lo r "> < o p t io n v a lu e = " b la c k " s e le c t e d = " s e le c t e d " > B la c k < / o p t io n > < o p t io n v a lu e = " w h it e " > W h it e < / o p t io n > < / s e le c t > < /p > <p> < l a b e l f o r = " t w e e t s " > P ic k < s e le c t id = " t w e e t s " > < / s e le c t >

a t w e e t : < / la b e l >

< /p > <p> < in p u t t y p e = " b u t t o n " < /p > < /fo r m >

332

глава 7

id = " p r e v ie w B u t t o n " v a lu e = " P r e v ie w " >


раскрываем в себе художника

Результ ат рендеринга вашего интерфейса изобразите здесь. Нарисуйте, как будет вы глядеть веб-страница с элем е н ­ т а м и формы слева.

—\ ▼

Представьте, что вы ис­ пользует е э т о т и н т е р ­ фейс для выбора вариантов для своей футболки.

СТАНЬ 6рду>ером еще pa) Теперь, к°гда у Бас есть ингоер^ейс, вЬх— полните при«еденные здесь Ja V a ^ tи н ап иШ и те Значение ДЛЯ к а ж д о го э л е м е н т а и н т е р ф е й с а .

(V u оШБешы Бы см°же:те г^оВ е^ш рь в реш ении к д а н н о ^ у п р а ж н е н и е В Конце ГЛаБы.

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " b a c k g r o u n d C o lo r " ) ; v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r b g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " s h a p e " ) ; v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r shape = s e l e c t O b j [ i n d e x ] . v a l u e ;

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r " ) ; v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

дальше ►

333


написание html

Сначала напишем необходимый HTML Х ватит разговоров! Д авайте займемся создапием пашего прилож епия. П реж де чем мы сможем сделать что-то еще, пам потребуется п ростая HTM L-страпица. О бповите свой файл index.html, чтобы его со­ держ имое выглядело следующим образом: £ < !doctype html>

Д д, это славный H TM LSсовместимый файл!

<html lang="en"> <head> <title>TweetS h i r t < / t i t l e >

О б ра т ит е внимание, что мы изменили з а ­ головок на T weetshirt.

<meta c h a r s e t = " u t f - 8 " /> <style> canvas

{border:

lpx solid black;}

</style> <script s r c = " t w e e t s h i r t .js"></script>

Поместим весь Ja va Script-код в о т д е л ь ­ ный файл, чтобы им было немного легче управлять.

</head> <body>

Д вот наш canvas1 .

< h l > TweetShirt</hl> <canvas width="600" height="200"

i d = " t s h i r t C a n v a s ">

<p>Please upgrade your browser to use T w e e t s h i r t !</p> </canvas> <form>

Это fo rm , в кот ором будут содержаться все элементы управления для приложения T w eetshirt. Об э т ом мы пого­ ворим на следующей странице...

</f orm> </body>

\

Мы также предусмот рели небольшое сообщение для п о л ь ­ зоват елейj к о т о ­ рые п р им еняю т устаревшие версии браузеров.

</html>

WTVPM Что еще вам необходимо знать для того, чтобы заменить CSS-рамку в сво­ ем canvas рамкой, нарисованной в canvas с помощью JavaScript? Какую методику вы предпочли бы (CSS или JavaScript) и почему?

334

глава 7


раскрываем в себе художника

Теперь добаВим < fo r m > Итак, добавим и и тер ф ей с пользователя, чтобы мы могли приступить к паписапию кода для создапия дизайпа футболок. Вы уже сталкивались с этим кодом рапыне, одпако па этот раз мы добавили ряд аппотаций, чтобы все было попятпо (пабирая код, обязательпо обратите па пих впимапие): ^ <form >

£

Весь э т о т код будет разм ещ ат ься между тегами Указа* ™ м и на предыдущей странице.

<Р >

< la b e l fo r = " b a c k g r o u n d C o lo r " > S e le c t b a c k g ro u n d c o l o r : < / la b e l > < s e le c t id = " b a c k g r o u n d C o lo r " > < o p t io n v a lu e = " w h it e "

s e le c t e d = " s e le c t e d " > W h it e < / o p t io n >

< o p t io n v a lu e = " b la c k " > B la c k < / o p t io n > < / s e le c t >

^

Здесь пользователь будет выбирать ц cm --------------- фона для дизайна футболки. На выбор < / Р> <Р> дается черный (Ыаск\ либо бельш (white) цвет. Вы можете добавить сюда другие < la b e l f o r = " s h a p e " > C ir c le s o r s q u a r e s ? < /la b e l> цвета по своему усмотрению . < s e le c t id = " s h a p e " > < o p t io n v a lu e = " n o n e " s e l e c t e d = " s e le c t e d " > N e it h e r < / o p t io n >

Здесь мы задействуем еще один ^ э л е м е н т управления, позволяю выбирать круги (circles) или квадраты (squares) для конф игу</&> рирования дизайна. Пользователь <Р> также сможет выбрать в а р и < la b e l f o r = " f o r e g r o u n d C o lo r " > S e le c t t e x t c o l o r : < / la b e l > ант none (нет) — фон не будет < s e le c t id = " f o r e g r o u n d C o lo r "> содержать никаких фигур. < o p t io n v a l u e = " c i r c l e s " > c i r c l e s < / o p t i o n >

^

C o p tio n v a lu e = " s q u a re s " > S q u a re s < /o p tio n > < / s e le c t >

< o p t io n v a lu e = " b la c k " s e le c t e d = " s e le c t e d " > B la c k < / o p t io n > < o p t io n v a lu e = " w h it e " > W h it e < / o p t io n > Еще один элемент управления

< /s e le c t>

select, на э т о т раз - для выбора цвета текста. О пя т ь ^ т а к и , на выбор дается черный ( b l a c k ) л и б о белый (white

< /Р> <р > < l a b e l f o r = " tw e e t s " > P ic k a t w e e t : < / l a b e l > < s e le c t i d - tw e e ts " > < / s e le c t >

</ р > <р> < in p u t t y p e = " b u t t o n " < /fo r m >

) ^ ^ B o m где будут размещ ат ься все твиты. А почему здесь пусто? А х да, мы же будем заполнят ь данный элем ент позже (подсказка: нам необходимо, чтобы т вит ы извлекались непосредственно из Т ви т т ер а , ведь это же веб-приложение, не т ак ли?!). id = " p r e v ie w B u t t o n " v a lu e = " P r e v ie w " >

&CAU @ам доводилось ст алкиват ься с элем ент ам и fo r m , то вы, вероятно, обратили внимание, что здесь form не им еет ат ри б ут а action (а это означ ает , что при щелчке на кнопке Preview (Предвари­ тельный просм от р) ничего не произойдет). Со всем э т и м мы разберемся через несколько мгновений...

g конце добавляем кнопку дАЯ предварительного п р о см от ра футболки,

дальше ►

335


добавление javascript

Пришло время добавить JavaScript для вычислений Разметка — это, копечпо, хорош о, одпако имеппо JavaScript будет объедипять все веб-приложепие TweetShirt. Мы разм естим необходимы й код в файле tweet s h i r t .j s. Н ачать мы собираем ся с размещ е­ н ия произвольны х квадратов п а футболке, по прежде пе обходимо активировать кпопку Preview (П ред­ варительны й просм отр), чтобы п ри ее паж атии происходил вызов JavaScript-фупкции. Создайте файл tweetskirt.js и добавьте в него данный код.

2 window, onload = function ()

Сначала будет и з ­ влекаться элемент previewButton.

^

{

var but t o n = d o c u m e n t .g e t E l e m e n t B y l d ("p r e v i e w B u t t o n " ); b utton. o n c l i c k = p r e v i e w H a n d l e r ;

Добавьте обработчик событий click для данной кнопхи,

t

но

«ри на ней (и д » к ■ сенсор ном экране м об и м н о го у е ш p c u c m U ) п р т с х

дил вызов функции previewHandler. Таким образом, когда кпопка Preview (П редварительны й просм отр) будет пажата, п роизой дет вызов фупкции previewHandler. И здесь самое врем я обповить canvas с целью представить футболку, пад дизайпом которой трудится пользователь. Приступим к паписапию p r e v i e w H a n d l e r : Сначала извлекаем элем ент function prev i e w H a n d l e r ()

^

{

и запрашиваем его к онт екст рисования /-&•

c a n v a s

var canvas = d o c u m e n t .g e t E l e m e n t B y l d (" t s h i r t C a n v a s "); var context = canvas .getContext ("2d") ;

var selectObj

= d o c u m e n t .g e t ElementByld

var index

= s e l e c t O b j .s e l e c t e d l n d e x ;

var shape

= selectObj [index]

j

.value; Г ^

_J If

(shape for

==

squares

)

~rpneVb наМ необходимо узнать^ка / '''к ч Л ^ р в « интерфейсе й ель Первым делом извле (" s h a p e " ) ; г^ОЛЬЗО am a.^n "ска&е". каем элем ент с id б Сиге ьп у

{

(var squares = 0; squares < 20;

З ат ем 8b^C^eMj какой элемент был выоран (квадраты или круги), для чего извле индекс выбранного элем ент а и при — сваиваем его значение переменной Фаре. squares++)

draw Square (can v as, c o n te x t) ;

4

{

X

,^д,лл

И если значением shape будет

«squares», ся на К/\.\s\щ J нам пот ребует I рисовать некоторое количество квадратов. Ка к насчет 2-0 шт ук? Что касается рисования каждого квадрата , мы будем полагаться Обо а

Т ЩиЮ dmw54uare>в т о р у ю нам предст оит написать

J ак L и7 context. c Z ^ 7 Hm‘позже 7 т Чуть

336

глава 7

п7 е3мм уви ди т е , как мы их используем.

'


раскрываем в себе художника Часш°

^адаВ аеМ ы е В о Ц р о С ьх • Как именно работает selected Index?

0 : Свойство selectedlndex элемента управления формы select возвращает номер параметра, выбранного пользовате­ лем в раскрывающемся списке. Каждый список параметров преоб­ разуется в массив, при этом все объекты в массиве располагаются по порядку. Допустим, у вас имеется список выбора, включающий следующие варианты: "pizza", "doughnut" и "granola bar". Если вы выберете «doughnut», то selectedlndex вернет 1 (не забывайте, что нумерация в JavaScript-MaccnBe

начинается с 0). Вероятно, вам потребуется не только индекс, но и значение параметра с этим индексом (в нашем случае — "doughnut"). Чтобы извлечь данное значение, сначала нужно воспользоваться индексом для извлечения элемента массива; в результате обратно вы получите объект параметра. Чтобы из­ влечь значение этого объекта, необходимо прибегнуть к свойству value, которое возвращает строку в атрибуте value параметра.

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

Одну из табличек мы уже р а з ­ м е ст и ли в нужном месте.

function drawSquare (

c o n te x t ) {

Расположите здесь таблички с псевдоко­ дом в нужной после­ довательности!

н а рисовать квадрат, и м е ю щ и й позицию

в ы ч ислить п р о и з в о л ь н у ю п о з и ц и ю У для к в а д р а т а в н у т р и canvas

х, у

и ширину

w

]

"lightblue" являемся ц ве­ т о м квадратов в нашем дизайнерском оригиналмакете.

задать для fillstyle значение

" l i g h t b lU

ie j

в ы ч ислить п р о и з в о л ь н у ю по з и ц и ю X для к в а д р а т а в н у т р и c a n v a s

дальше ►

337


реализация квадратов

Написание функции drawSquare Теперь, когда вы разобрались в приведеппом выше псевдокоде, давайте восполь­ зуемся тем, что вы уже зпаете, для паписапия d ra w S q u a re : Мы используем M ath.randomQ с целью генерирования случайных чисел для ш и ­ Наша функция, у которой имею т ся рины и позиции х, у квадрата. Волге два па рам ет ра — canvas и context. подробно об э т о м мы поговорим через несколько мгновений... f u n c t i o n d ra w S q u a re (c a n v a s , c o n t e x t S — Мы выбрали 4 0 как наибольшее зн а ­ чение размеров квадратов, поэт ом у Здесь нам v a r w = M a th , f l o o r (M a th , ra n d o m () они не будут слишком большими. требуется ( п р о и з­ Координаты х и у У var x M a th , f l o o r (M a th , ra n d o m () * c a n v a s . w i d t h ) ; вольная базируются на ш и ширина рине и высоте canvas. c a n v a s .h e ig h t) ; и позиция \ v a r у = M a th , f l o o r (M a th , ra n d o m () Мы выбираем с л у ­ чайное число между о X, у для и значением ширины квадрата. c o n te x t. f i l l S t y l e = " lig h t b lu e ” Применим к квадра­ и высоты с о о т в е т ­ т а м красивую с в е т ­ ственно. c o n t e x t . f i l l R e c t ( x , У, w, w) ; л о -си н ю ю заливку в книге «И зучаем с помощ ью метода HTML, XHTML и CSS» fillStyle, на который имеется полезная c n n T H£Lij P, UCyeM Сам квадрат п °мощ ью fillRect. более прист ально глава, посвященная взглянем чут ь позже.. работе с цветами (если вам пот ргбу е т с я освежить знания Как мы реш или, какие числа будем умпожать па зпачепия, геперируем ые м данному вопросу)M a th , random , чтобы получить зп ачеп ия ш ирипы и позиции х, у пашего ква­ драта? В случае с ш и ри пой прямоугольпика мы вы бирали зпачепие 4 0 , так как опо обеспечивает пеболы ной разм ер отпосительпо разм еров ca n v a s . П о­ В своем коде вы скольку это квадрат, мы вы брали апалогичпое зпачепие для высоты. Мы так­ можете свободно же вы брали ш ирипу и высоту ca n va s в качестве осповы для зп ачеп ий пози ­ указат ь значение, ции х, у, чтобы паш квадрат пе выходил за грапицы c a n v a s . отличное от 4 0! Ширина canvas

Координаты X и у предназначены для левого верхнего угла квадрата.

Ширина и высота квадрата (не забы­ вайте, что в с л у ­ чае с квадратом эти значения будут одинаковыми).

л В ы со ка canvas

J 338

глава 7


раскрываем в себе художника

Время для mecm-драйВа! В П

О

Twccdh rt

И так, затратив столько сил п а создапие кода, давайте, пакопец, протестируем его. О ткрой ­ те свой TweetShirt-файл in d e x .h tm l в браузере. Щ елкпите па кпопке Preview (П редварительны й просм отр), после чего вы долж пы увидеть п рои з­ вольны е сипие квадраты. Вот что мы видим:

^

^

Sskct background coloc: ( \'Aiw ; ’

Circlcs or jqiiWCi"* I 5сцаге»МН

Отлично, все выглядит так, как нам нужно!

Salad Ия! а й н л ' is nr*

.Pick a tweet: I

Постойте-ка, ведь если продолжать нажимать кнопку Preview (Предварительный про­ смотр), квадратов будет становиться все БОЛЬШЕ. А это не то, что нам нужно!

Qiwctcliwt С

#

I

* V-

S>lo cs.lho s«/~ B *th,H e ad.Fir*t.W T V L...

jJ ☆

| B j

И

-$г

Л

Г^ Он прав, у нас воз­ никла небольшая проблема. Щ елкнит е на кнопке Preview (Предварительный просм от р) несколько раз подряд — и вы увидите нечто п о ­ добное.

Scloct background co lo r f w »№н»| Circles or squares? j

i: j

Sclotl LCXt colon ' BLfclc Fick a tweet; [ Щ

дальше ►

339


корректировка кода для квадратов

Почему мы видим старые и новые квадраты, когда нанимаем кнопку Preview? Вообще-то получается класспый эффект... по это пе то, что пам пужпо. Нам пеобходимо, чтобы повы е квадраты заменяли стары е каждый раз, когда мы щ елкаем па кпопке Preview (П редварительны й просм отр) (точпо так же пам потребуется, чтобы п овы й твит замепял стары й). О сповпой м омепт здесь заклю чается в том, что пужпо помпить, что мы папосим пикселы в элемепте canvas. Когда вы паж имаете кпопку Preview (П редварительны й про­ смотр), вы берете canvas и рисуете в пем квадраты. П ри этом поверх всего, что уже им еется в canvas, просто будут папоситься повы е пикселы! Вы уже зпаете все пеобходимое для того, чтобы исправить ситуацию прямо сейчас. Вот что мы сделаем:

ф

Будем извлекать выбранный цвет фона из объекта "backgroundcoior".

©

Будем осуществлять заливку фона canvas соответствующим цветом, используя filistyle и filiRect каждый раз перед тем, как начать рисование квадратов.

Возьми в руку карандаш Чтобы при каж д ом нажатии кн о п ки Preview (П редварительны й просм отр) мы наблюдали в ca n v a s тол ько новые квадраты, потребуется залить фон c a n va s цветом, вы бранны м пользователем в меню " b a c k g ro u n d c o io r " . Сначала реа­ лизуем ф ункцию для заливки ca n va s вы бранны м цветом. Ниже приведен код, в котор ом вам необходим о устранить пробелы. Сверьте свои ответы с реш е­ нием д ан н ого упр аж н е н ия в конце главы, прежде чем двинетесь дальше.

fu n c t io n

f illB a c k g r o u n d C o lo r ( c a n v a s , c o n t e x t )

{

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " ____ v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r b g C o lo r = s e l e c t O b j . o p t i o n s [ i n d e x ] . v a l u e ; c o n te x t. f i l l S t y l e

= _________________ ;

c o n t e x t . f i l i R e c t (0 ,

0 , _______________ , ________

Подсказка: т о, ч т о вы no черпнете из выбранного параметра, будет строкой со значением цвета, кот орую вы сможете использовать т о чно т а к же, как "И д Ш и е для заливки квадратов. , Подсказка: мы х о т и м за ли т ь ВЕСЬ canvas соо т вет ст в ую щ и м ц в е т о м .1

340

глава 7


раскрываем в себе художника

Добавление вызова fillBackgroundColor У вас имеется фупкция f i l lB a c k g r o u n d C o lo r , готовая к работе; теперь пам просто пужпо убедиться, что ее вызов будет осущ ествляться из p r e v ie w H a n d le r . Ее вызов будет происходить в самом пачале, благо­ даря чему мы получим аккуратпы й чисты й ф оп, прежде чем пачпем добавлять что-либо в c a n v a s . f u n c t i o n p r e v ie w H a n d le r ()

{

v a r c a n va s = d o c u m e n t. g e tE le m e n tB y ld ( " t s h i r t C a n v a s ' v a r c o n te x t = c a n v a s . g e tC o n te x t( " 2 d " ) ;

fillBackgroundColor(canvas, context); v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " s h a p e " ) ; v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r shape = s e l e c t O b j [ i n d e x ] . v a l u e ; if

(shape == " s q u a r e s " ) fo r

Добавляем вызов fillBackgroundColor до создания квадратов, поэт ом у то, что было нарисовано ранее, окажется скры ты м под слоем з а ­ ливки, и мы получим чистый фон для рисования новых квадратов.

{

( v a r s q u a re s = 0 ; d ra w S q u a re (c a n v a s ,

s q u a re s < 2 0 ;

s q u a re s + + )

c o n te x t);

}

Быстрый тест-драйв: убедимся, что наше новея функция fillBackgroundColor работает... Добавьте п овы й код в файл t w e e t s h i r t .j s, перезагру­ зите страпицу в браузере, вы берите цвет фопа, а также Squares (Квадраты) в мепю Circles or squares? (Круги или квадраты?), после чего пажмите кпопку Preview (П редварительны й просм отр). Затем щ елкпите па пей спова. И при каждом следующем щ елчке па кпопке вы долж пы будете видеть только повы е квадраты.

Ш ТУРМ

Теперь при каждом нажа­ тии кнопки Preview (Предварительный п р о см о т р ) мы будем видеть только новые квадраты.

Подсчитайте количество квадратов при нескольких нажатиях кнопки Preview (Предварительный просмотр). Наблюдалось ли хоть раз менее 20 квадратов? Такое вполне может быть. Почему так происходит? Что можно сделать для устранения этой проблемы? (Вы же не хотите обманывать своих клиентов, не давая им их честные 20 квадратов, не так ли?)

дальше ►

341


обзор свойства fill style

л

J a V a ^c iij4 —с в о й с т в о

у в е л и ч и те л ь н ы м о п е к л °м

>

Б олее приетальпо взгляпем па свойство fillStyle, поскольку вы впервы е с пим столкпулись. О по является свойством context, которое содерж ит определеппое зпачепие цвета для того, что вы рисуете в canvas. л £ 3йЭйем мы значение цвета. ы сможете использовать т е же ф о р ­ Но в отличие от filiRect, fillStyle м а т ы цвет ов, что и в CS5. У вас будет К ак и fi'HRect^ является свойством, а не м е ­ с б о й с т б о л л f illS ty le иТ ЛЬ30вать ™ ена, тодом. Поэтому мы задаем для как hghtblue, либо значения вроде #ccccff мы управляем п о него значение , а не вызываем его. или п •gb(o 173, 231). Попробуйте! средством c o n t e xt . J.

^ c o n te x t.f illS t y le

= " lig h tb lu e " ;

t

Часш°

О б ра т ит е внимание, ч т о , в о т ­ личие о т CSS >значение необходи­ мо заклю чат ь в кавычки , если вы не используете переменную.

^адаВ аеМ ы е В сЩ роСъх Я ожидал, что мы будем задавать цвет фона квадратов и canvas путем

f t

Почему значение цвета следует за­

ключать в кавычки, в то время как в CSS

передачи значения цвета методу filiRect. со значениями свойств так поступать не нужно?

Я не могу понять, как работает свойство

fillStyle. Как оно влияет на то, что делает filiRect? 0 :

Отличный вопрос. В данном случае

О

Ладно, я сдаюсь. Почему мы иногда наблюдаем менее 20 квадратов?

0:

\J * Позиция х, у и ширина квадратов являются произвольными. Одни квадраты ! Что ж, CSS является языком, отличным

могут перекрыв

от JavaScript, и не ожидает, что вы будете

использовать кавычки. Если вы не заключите со значениями соответственно 599, 199,

все немного по-другому, чем вы привыкли значение цвета в кавычки, то JavaScript ре- из-за чего вы сможете увидеть только один думать. Как вы помните, c o n t e x t пред­ шит, что имя этого цвета является перемен- его пиксел (поскольку остальная часть этого ставляет собой объект, управляющий до­ ной, а не строкой, и попытается использовать квадрата будет лежать вне canvas). Одни ступом к canvas. Используя fillStyle

значение переменной вместо имени цвета,

квадраты могут иметь ширину 1 пиксел,

и filiRect, вы сначала задаете свойство, Допустим, у вас имеется переменная а другие - даже 0 пикселов, так как метод которое говорит элементу canvas следую­ fgColor = " b l a c k ”. Вы могли бы напи- M ath, r a n d o m может возвращать значещее: «Все, что будет нарисовано в сать context.fillStyle = fgColor, ние 0. Либо вы можете сгенерировать два

тебе далее, должно иметь данный и это сработало бы, поскольку значением квадрата с абсолютно одинаковыми разцвет». Таким образом, все, к чему вы ста­ f gcolor является “b l a c k ”. меРами и местоположением. нете применять заливку цветом (например,

Однако в случае с нашим приложением все Однако c o n t e x t .fillStyle = black ” это является произвольным, поэтому мы и не сработает, так как black не является пества fillStyle, будет иметь данный цвет, считаем, что все в порядке. А в ином случае ременной (если только вы не определите его пока вы снова не измените цвет, присвоив нам, возможно, пришлось бы позаботиться как переменную, что может внести неболь­ fillStyle другое значение цвета. о том, чтобы такого не случалось. шую путаницу). Вы узнаете, что допустили с помощью filiRect) после задания свой­

эту ошибку, поскольку будет сгенерирована JavaScript-ошибка и выведено сообщение вроде Can't find variable: black

(He могу найти переменную: black) (но не стоит беспокоиться, так как все мы хотя бы раз допускали эту ошибку).

342

глава 7

Квадрат так


раскрываем в себе художника

Тем временем, возвращаясь к TweetSbirt.com... Неплохо, а знаешь, все это уже начинает выглядеть так, как того и хотел наш босс.

Д ж им : Я впечатлен тем, как мало кода потребо­ валось. Только представь, если мы бы делали все это по-старому, на сторопе сервера, то до сих пор возились бы с нашим сервером.

Фрэнк: Похоже, нам также представилась хоро­ шая возмож ность заняться создапием кругов в процессе дизайна; в копце копцов, ведь их ри ­ сование будет осущ ествляться точпо так ж е, как и квадратов. Д ж им : Согласен, а где Джуди? Опа, вероятпо, уже знает API-интерф ейс для рисовапия кругов. Х отя с другой стороны , для этого пам, возможпо, потребуется лиш ь вызы вать метод f i l l C i r c l e .

г Джим

Фрэнк: М пе кажется, так и есть! Кому пужпа эта Джуди, если у пас есть метод f i l l C i r c l e !

дальше ►

343


знакомство с контурами и дугами

бы я пи делал, п ри вы зове fillCircle в canvas пичего пе появляется. Д жудн: Ч то ж , дай-ка я взгляпу па твой метод f i l l C i r c l e . Ф рэн к : Ч то ты имееш ь в виду под «моим методом»? Н ет у мепя пикакого своего метода, я использую метод пепосредствеппо из APIи п терф ей са Canvas. Д жудн: В API-иптерф ейсе Canvas пет метода f i l l C i r c l e . Ф рэн к : А я предполагал, что есть, ведь существует же метод f i l l R e c t . . . Д жудн: Теперь ты зпаеш ь, к чему могут привести предполож ения. Запусти-ка браузер и введи следующий адрес, по которому всегда можпо пайти ипф орм ацию отпосительпо соответствующ его APIи птерф ейса: h t t p : / /d e v .w 3 .o r g /h tm l5 /2 d c o n te x t/. ...Так или ипаче, рисовапие круга —пемпого более слож пы й процесс, чем вызов лиш ь одпого метода. Тебе спачала пужпо изучить, что пред­ ставляю т собой коптуры и дуги. Д ж н м (входя в кабинет): Джуди, а Ф рэпк рассказал тебе о паш ей п ро­ блеме с рисовапием кругов? Ф рэн к: Да, Джим, enoughway ithway ethay irclecay* ^

Чтобы понять смысл этой фразы, рекомендуем вам вос­ пользоваться услугам и сайта

piglatin.bavetta.com. * Enough with the circle! — «Хватит ходить по кругу!». —Примеч. перев.

344

глава

7


раскрываем в себе художника

Черчение контуров П реж де чем п ерей ти к кругам, пеобходимо п оговорить о коптурах и дугах. Д авайте пачпем с коптуров и парисуем пе­ сколысо треугольпиков. Если вам потребуется парисовать треугольпик в c a n v a s , то зпайте, что метода f i l l T r i a n g l e пе существует. Одпако треугольпик все же можпо парисовать, спачала пачертив его контур, которы й затем нужпо будет обве­ сти, чтобы парисовать треугольпик в c a n v a s . Ч то все это озпачает? Донустим, вы хотите очепь аккуратпо парисовать что-то па холсте, для чего мож ете взять карапдаш и пабросать едва зам етпы е очертап и я нужпой вам фигуры (будем пазы вать их коптуром). Вы п ачертите их так легопько, что едва сможете разглядеть эти липии. Затем, когда коптур вас устроит, вы возьмете ручку (с толщ ипой стерж пя и цветом ч ерп ил по своему выбору) и обведете коптур, чтобы все смог­ ли увидеть ваш треугольпик (или любую другую фигуру, кото­ рую вы пачерти ли карапдаш ом). И меппо так осущ ествляется рисовапие произвольны х фигур с помощью л ип и й в элемепте c a n v a s . Д авайте н а р и с у е м тр е \Сарандаш, с угольпик и посмотрим, как это работает. Используем метод begmPatW, чтобы сказать canvas о т о м , что £ начинаем чертить новый контур.

которого Mbi ЬудеМ ч е р т м то к о н т у р -

c o n t e x t . b e g in P a t h ( ) ; c o n te x t.m o v e T o (1 0 0 ,

150

Здесь мы о п у ­ скаем кончик карандаша в Используем метод moveTo для перемещения «карандаша т о ч к у с к оордив определенную точку в canvas. на1ЛЛами X = Ю О М о ж е т е счит ат ь, что мы и у = 150. Это как бы опускаем кончик каран- 5 у Э е т первая даила в данную точку. точка контура

/

Метод ИпеТо черт ит конт ур начиная с текущего местоположения ко н ч и ка к а ­ рандаша и двигаясь к новой точке в canvas.

4c o n t e x t . l i n e T o (2 5 0 ,

7 5 );

J

карандаша находился в точке с ко ^ ординатами х = Ю О и у = IS O , от которой мы чертим конт ур , двигая инст румент к т о ч к е с координатами х = 2-50, у - 7 5. Кончик

Начертите линию от начальной точки до этой новой т оч­ ки с координатами X = 2SO, у = 15.

дальше ►

345


как рисовать с помощью контуров

У нас имеется одна сторона треугольника, нужно начерт ит ь еще две. Д а ва йт е снова воспользуемся мет одом hneTo и нарисуем вт орую сторону: . Начертите вт орую л и н и ю j двигая к а ­ рандаш от преды­ дущей точки к н о ­ вой с координатами К = 125, у = за

У c o n t e x t . l in e T o (1 2 5 ,

30)

Ч ерт им линию от т екущ ей позиции кончика карандаша ( z s o , 7 s), двигая его к новой точке с координатами х = i Z s У ~ 30. 8 р е зу л ь т а т е у нас получит ся вторая сторона треугольника. Мы почти достигли цели! Нам осталось лишь начерт ит ь еще одну л и н и ю , чтобы заверш ит ь треугольник. Д л я этого просто замкнем конт у р , воспользовавшись м ет одом closePath.

А вот и наш т р е ­ угольник! Но не забы­ ва й т е, что это пока лишь к о н т у р , п о ­ эт о м у он будет все еще не виден пользо­ вателям.

c o n t e x t . c lo s e P a t h ( ) ;

Метод closePath соединяет начальную точку контура (Ю О , IS O ) с конечной (1 Z S , 30).

Urnak, у нас е с ть контур! U что теперь?

пражненне

Теперь вы будете использовать этот контур для рисования линий и заливки своей фигуры цветом, конечно же! Создайте простую НТМ1_5-страницу с элементом canvas и наберите весь приводившийся чуть ранее код. Затем проведите тестирование.

c o n te x t.b e g in P a th ( ) ; c o n te x t.m o v e T o (1 0 0 ,

1 5 0 );

c o n t e x t . l i n e T o (2 5 0 ,

7 5 );

Вот код, приводившийся ранее.

c o n t e x t . l i n e T o (125 , 3 0 ) ; c o n t e x t . c lo s e P a t h ( ) ; c o n t e x t . l in e W id t h = 5 ; c o n t e x t . s t r o k e () ; c o n te x t. f i l l S t y l e

= "re d ";

c o n t e x t . f i l l () ;

А здесь приведен новый код. О п и ш и т е , что делает каждая из этик ст р ок . Загрузит е страницу. Ваши ответы оказались правильными? Решение упражнения - в конце главы.

346

глава 7


раскрываем в себе художника

Просто, чтобы быть в курсе: я ду­ мала, мы будем пытаться нарисовать круги. Какое отношение все эти конту­ ры имеют к созданию кругов?

Чтобы нарисовать круг, сначала нужно начертить его контур. Сейчас мы собираемся показать вам, как п ачерти ть коптур круга. Научивш ись делать это, вы сможете создавать любые круги, какие только захотите. Н емпого дополпительпой ипф орм ац ии для вас. Вы уже зпаете, как пачать черти ть коптур, пе так ли? Это, как вы видели рапее, делается с помощью следующего кода: c o n te x t.b e g in P a th (); Н о мы пока пе говорили вам о том, что в объекте c o n te x t имеется еще одип метод — arc: c o n t e x t . a r c (1 5 0 ,

1 50,

50,

0,

2 * M a th . P I ,

tru e );

^

И что же on делает? Н а следующей страпице мы разъяспим вам детали. Н о, как вы сами могли догадаться, даппы й метод п озволяет черти ть коптур вдоль окружпости.

\ I J

Из уроков геометрии

вы наверняка пом нит е, ч т о длина окружности равна ZnR? Просто ненадолго отложите в подсознание данный ню анс-

дальше ►

347


взгляд на метод arc

Подробное исследование метода arc Взгляпем па метод a rc и изучим его парам етры . context.arc(х, у , radius, startAngle, endAngle, direction)

Суть метода a rc заклю чается в том, что оп позволяет определять, как будет ч ерти ться требуемый коптур вдоль окружпости. П осмотрим , как имеппо каж­ ды й из его парам етров содействует этому. Х ,у

П арам етры х и у определяю т, где будет паходиться цептр круга в вашем canvas.

Это позиция X, у центра вашего круга. Canvas

c o n te x t. a r c (х ,

у ,

r a d iu s ,

radius Д аппы й парам етр используется для определепия

348

глава 7

1 / 2

ш ирипы круга.


раскрываем в себе художника

d ire c tio n

П озволяет определять, как будет черти ться дуга: в паправлепии против часовой стрелки или же по часовой стрелке. Если зпачепием direction является true, то рисовапие будет происходить против часовой стрелки; если же false —по ча­ совой стрелке.

tru e

Если значением direction является true, дуга будет черт ит ься прот и час вой ст релки, а если false Iпо часовой стрелке.

false

s ta r tA n g le ,

e n d A n g le ,

d ir e c tio n )

Ниже приведен важный момент! Если зпачепием d irection является true, дуга будет черти ться п ротив часовой стрелки, ас* если j_* false — Конечная точка по часовой стрелке нашей дуги —

startAngle, endAngle

Д у га , к о т о р у ю мы х о т и м на чер т и т ь Конечный угол это угол между осью X и конечной точкой дуги.

Н е п р о п у скай те это. Углы могут изм еряться в отрицательпы х величипах (в паправлепии против часовой стрелки от оси X) либо в полож ительпы х величипах (по часовой стрелке от оси X). Это пе то же самое, что парам етр direction в случае с дугой! (Вы убедитесь в этом па следую­ щ ей страпице.) Угол, от меряем ый в направлении Ось X прот ив часовой ст релки от оси X, это Начальный угол будет и м ет ь о т рицат ельную между осью Х и н а величину (н а при м ер, -35°). угол чальнои мочкой дуги

Начальная точка нашей дуги

Угол; от меряем ый в направле­ нии по часовой ст релке от оси X, будет и м ет ь положительную величину (например, 45°). дальше ►

349


практикуемся в использовании метода arc

Небольшой пример использования метода arc т о пам сейчас нужпо, так это хорош ий прим ер. Донустим, вы хотите п ачерти ть дугу па круге, цеп тр которого им еет позицию х = 1 0 0 , у = 1 0 0 . П ри этом вам нужпо, чтобы ш ирипа круга была 150 пикселов (то есть оп имел радиус 75 пикселов). А дуга, которую вы хотите пачертить, будет составлять лиш ь 1 / 4 круга. Ч ерт им дугу в направлении прот ив часовой с т р ел к и .

Ч

’Это наила дуга. Центр: х = Ю О , у = гоо

Н я м -н я м j яблочный пирог!

Г К

Начальный угол равен <9 °, а конечный составляет 270°.

радиус равен 7 5 пикселам.

V— Следует о т м е т и т ь , что мы от м ер яем конеч­ ный угол в направлении по часовой стрелке от оси ™ э^ о м у величина конечного угла будет п о ложительной.

Н апиш ем вызов метода arc, которы й будет рисовать пашу дугу: Н ачпем с позиции х, у, которую им еет цеп тр круга: 100, 100. context.arc (100 , 100, __, __ , ______________________ ,

);

Далее пам потребуется радиус круга, равп ы й 75 пикселам. context.arc (100 , 100, 75, __, ______________________ ,

);

А что с паш ими пачальпы м и копечпы м углами? Н ачальпы й угол будет равеп 0° отпосительпо оси X. К опечпы й угол —это угол между осью X и копечпой точкой паш ей дуги. Поскольку паша дуга является 90-градуспой, копечпы й К э т о й функции угол будет равеп 270° (90° + 270° = 360°) (если бы мы изм еряли его в отрица- мы вернемся тельпы х величипах, то есть в паправлепии против часовой стрелки, то ко- через несколько п ечпы й угол был бы в итоге равеп -90°). ----------------------- мгновений. Она просто преобcontext, arc (100, 100, 75, 0, degree sToRadians (270) , ____ ) ; р азует градусы тт ^ » (которые нам Н акопец, поскольку дуга будет черти ться в паправлепии против часовой л ^ ^ стрелки, указываем зпачепие true. пРи Ра дианы (которые предпочит ает

О

context.arc (100 , 100, 75, 0, degr ее sToRadians (270) , true);

350

глава 7

context).


раскрываем в себе художника

Я говорю «градус», вы говорите «радиан» Все мы каждый депь говорим об углах, связаппы х с кругами: «Класспый разворот па 360 градусов», или «Я паправился по этому нути и развернулся па целых 180 градусов», или... ну, в общем, вы попяли. Одпако проблем а заклю чается в том, что мы думаем в граду­ сах, a c o n t e x t в случае с c a n va s —в радиапах. у __ Сейчас мы могли бы сказать вам, что: 360 г р а д у с о в = 2 P i р а д и а н и после этого вы были бы готовы посчитать в уме градусы в радиапах в случае необходимости. Если по какой-то причи пе вы пе захотели бы делать это в уме, то зпайте, что существует удобпая фупкция, которая вы полпит дапную работу за вас: f u n c t i o n d e g re e s T o R a d ia n s (d e g re e s ) re tu rn

^

{

(d e g re e s * M a th . P I ) / 1 8 0;

1

Как пом н ит е, с этой ф у н к цией м ы м и м о л е т о м с т а л кивались в гла ве, посвящ енной A P I - и н т е р ф е й с у G eolocation.

t

Чтобы перевести г р а д у сы в р а д и а н ы , нуж но у м н о ж и т ь их на п и р а з д е л и т ь на 1 2 0 .

(ТА Н Ь браум ром

Классный разворот на 360 градусов! То есть я хотел сказать, классный разворот на 2п радиан!

Радиан еще одна единица и з м е ­ рения углов. Один радиан равен 120/Ъ,14-15Ч2<Ь5... ( то есть числу IS O , р а з ­ деленному на п). И с п о л ь з у й ^ э т у функцию когда захот ит е дум ат ь в градусах, но будете о п е ­ рировать радианами при рисовании дуги.

На с. 3 4 7 вы видели, как мы и сп о л ь ­ зовали 2 * Matk.PI для определения конечного угла дуги на круге. Бы могли бы п о с т у п и т ь т ак же... либо прост о использовать degreesToRadians(3(,0).

---------------

I I н т е ] ^ р е т и р у й т е п о в е д е н н ы й н и ж е в ы зо в м е т о д а аГс и н а п и ш и т е все

со ощ В ещ ещ ^^Щ и е значения, к о т о р ы е б у д у т х а р а т с т е ^ ^ о В а т ь круг, а т а к ж е и з о б р а з и т е ДУ^)» со зд а в а ем у ю в р е з у л ь т а т а э т ° Г о ВыЗоВа.

context.arc(100, 100, 75, degreesToRadians(270), 0, true);

Напишите все параметры данного круга и нарисуйте дугу, которая будет создана в резуль т а т е вызова метода arc.

Подсказка: что останется от п и ­ рога, если съесть э т о т кусок?

дальше ►

351


/ еэеи г

ZSZ

Ответ: Рисование угла осуществляется с использованием начального угла 0° и конечного угла 360°. Неважно, какое направление вы выберете, поскольку будете рисовать полный круг.

^эинэьене 010 ии 1Э81/\1И бэмиэс^ю иоаоэеь ои иии ишэс1±о иоаоэеь aniodu ^ le d e g is a н а 0HH0uaedueH эоме>]

ojOHLfou bHHeaoond but/ я±еаоея1_гоиэи eietfAg н а н ш Л шяньэном и шяняиеьен иоме>]

W d M fD ‘S ? J V Y ) b S M V J l'p

H6&6J16VN

Y)dY\V)

-у н б ф v gvbfivv д owie Y)VVV9Q OHhOWI

сэ ж

>iVW I

9jV JJ2M V jy?

YlYlh>iH(ncf? 1 X 9 1 V I 0 V s v a v iv v

Y)

W d v g z d d jj

{ .' (q.xsq.uoo ;spaupo) эхоттэм^тр

-m ) (oHPVnowovI

(+ + sax o iio .'OS > s s p i i o

CHfidov*

онжВн д а в и

nrihylHFi(r

0

=

.'0

2 0

x 0 1 1 0 лгл)

joj

} („ se p iT O y == scteqs) j t ss x s {

go?fid>t Ot w ?

{

\evndvH k»w ' ( i w v d e m 0

.' (q.xsq.uoo ;spaupo) si^nbsM^ip

sw nbs ™ v 4 " * ^

(++saienbs

.'os > saienbs

vvdpwg « v w » 9° w ° ' A"У* ■<:,cwvdevg* v)VY) Yi?fidyI)

ssijvnbs ло s« jw p

.'0

= saienbs л г л )

joj

} („ sei^ n b su == scteqs) j t

9

/s n j B A * [хэрит] Cqo^-osx^s =

.L o w v o v . nv L to H * _ He e «

'огош fie** наииш »M HH»V

;п?л

.'x s p u ip s q -o s x ^ s * C qo^-osx^s = х э р и т ;п?л .' ( 41sd ^ 4s 41) p iA g q .u s u is x a is 6 *^иэш поор = C q o io s x s s ;п?л

i

(q.x©q.uoo ' s b a u b o ) л охо эр и п о х б эр -ея х Т Т З 1

• ( iiP 2 ii) ^-Xsq.u°oq.s5 * s p a o t o = q.xsq.uoo

jctsa

.' ( 11s b a u ? o ^ i t 4 s ^ 11) p iA g q .u s u is x a is 6 *^иэш поор = s ? a u ? o }

() згэ-[рит?да-этлэz

d

a

jcts

uopounj

:tfoH Ш Ч Я О Ы э ж и ц и1чииэ^эаис1и эдегадоН и s С •q.;rT4sq.3aM.q. ш г е ф ОШ ЙЯыАф Я tfOH ИИ^ПСЯАЯХЭХЭЯХООЭ

wn&zyotf

И1ГИ H jA d ^ j) £ S 9 J ^ n b s

j o s a p j i ^ ошэш я (H jA d ^ j) s a p j i ^ w d y v in ч 1гэх^яоеч 1гоы о хь ‘q x m ra lta d iio к э х э ^ ^ х о п ш геь ш ю ‘q j^ a o D H d - г а х и r i g o ! ^ *(шмш,ш1Ь^яя э э^ьХ 1гэ я и эгея) HOjAdn xiq n q iro aeH o d n о& qj/etfeo3 imhxox iqp^ *эхо;гтзмл?;гр — ошйяыАф сяАяоы q in r a g o tf и :ц щ £ р э м х я KDqxXHdaa ^ d o n ‘ш М я q j^ ao D H d явя ‘эхэш ге и а в й ю я ‘q d a n a x

gozAd>| впнедоэй kv6 е б о ^ л ц ^ э э м ^ ошнеэпиен >j imfdetoedQsog эогЛсй/ эпнэиэедод


раскрываем в себе художника

Пишем функцию drawCircle... Подобно т о м у как мы п о с т у Теперь паппш ем фупкцию d ra w C ircle. Н е забы вайте, что здесь пам лали в случае с квадратами, мы потребуется парисовать лиш ь одип произвольны й круг. О стальпой указываем 4(9 в качестве м а к ­ симальной величины радиуса, код обеспечит вызов даппой фупкции 2 0 раз. чтобы наши круги не получились слишком большими. f u n c t i o n d r a w C ir c le ( c a n v a s , c o n t e x t ) { v a r r a d iu s

= M a th . f l o o r ( M a t h . ra n d o m ()

* 4 0 );

v a r x = M a t h . f lo o r ( M a t h . r a n d o m ()

* c a n v a s .w id th )

v a r у = M a t h . f lo o r ( M a t h . r a n d o m ()

* c a n v a s . h e ig h t)

О п я т ь -т а к и , координаты х и у центра круга базиру­ ю тся на ширине и высоте canvas. Мы выбираем п р о ­ извольные числа между О и шириной и высотой с о о т ­ ветственно.

'J

c o n t e x t . b e g in P a t h ( ) ; c o n te x t. a rc (x ,

y,

c o n te x t. f i l l S t y l e

r a d iu s ,

0,

d e g re e s T o R a d ia n s (360)

= " lig h tb lu e " ;

c o n te x t. f i l l () ;

Снова используем "UgWtblue" в качестве значения для fillStyle и заливаем контур с помощ ью context. fill().

tru e )

Используем конечный угол 3 6 <9 ° для создания полного круга. Рисуем в направлении прот ив часовой с т р е л к и , однако в случае с кругом неважно, какое н а пра в­ ление мы выбрали.

... и проводим тест-д р ай в ! Н аберите приведеппы й рапее код (и пе забудьте добавить фупкцию d e g re e s T o R a d ia n s ), сохрапите его, а затем загрузите в своем браузере. Вот что мы видим (поскольку это произвольны е круги, ваши будут выглядеть пемпого по-другому):

дальше ►

353


b iB П

е г

е г

ЦебоЛьШой ле^е^ыБ на леченье J f \ ^щраниДьх, п° Кощо^ыМ Мы с ВаМи

т°ЛьК« Чзцо проделали путь, быЛи ДоВоДь— Но

увлекательными. ]Je знаем, как Вы , а Мы

хоцшм печенья. ](ак насчет небольшого пере­ рыва?

Д о

не думайте» чт ° Мы не поручим Вам

нечщ о и н тересн ое, п о к а Вы б у д е т е ег° е с т ь

(на следующей странице справа Вас ждет Задание). |а к Чщо отки ньтесь на спинку стула, сде­ лайте небольшой перерыв, и «вгрызитесь» В Задание пока ВаШ М°ЗГ и Желуд°К будут

ненадолго заняты к<>е-чем другим, ^атем Возвращайтесь, и Мы ЗаК°нЧиМ ^weet^iiTt—К°д!

354

глава 7


раскрываем в себе художника

Справа изображено улыбающееся лицо (или печенье с кусочками шоко­ лада в форме улыбающегося лица, если вам так больше нравится). При­ веденный внизу код для рисования улыбающегося лица почти завершен; нам нужна ваша помощь, чтобы устранить имеющиеся в нем пробелы. После работы, проделанной в этой главе, у вас есть все необходимое для того, чтобы справиться с данной задачей. Закончив, вы сможете сверить свои ответы с решением этого упражнения в конце главы.

= гоо> Я.so *> У = 4 0 0 , 2SO радиус - 2-5

длийа носа = SO] угол)- 2.0°

у = з о о , 3SO радиус = 7 5 f u n c t i o n d ra w S m ile y F a c e ()

{

v a r ca n va s = d o c u m e n t. g e tE le m e n tB y ld ( " s m i l e y " ) v a r c o n te x t = c a n v a s . g e tC o n te x t( " 2 d " ) ;

Bom что нам требуемся. По ходу дела у вас может возникнуть желание испечь настоящее печенье с кусочками ш окола­ да в ф орме улыбающейся рожицы...

c o n t e x t . b e g i n P a t h () ; c o n t e x t . a r c (3 0 0 , c o n te x t. f i l l S t y l e

300,

200,

0,

d e g re e s T o R a d ia n s (3 6 0 ) ,

= " # ffffc c ";

c o n t e x t . f ill(); c o n t e x t . s t r o k e () ;

c o n t e x t . b e g i n P a t h () ; c o n t e x t . a r c (_____,

25,

tr u e )

tru e

К руг лица. Здесь мы уже уст ранили за вас один из пробелов. О б рат ит е enuManuej что мы применили к кругу заливку жел­ т ы м цветом. Левый глаз

c o n t e x t . s t r o k e () ;

c o n t e x t . b e g i n P a t h () ;

Правый глаз

c o n t e x t . a r c ( 4 0 0 , _____, c o n te x t. s tr o k e () ;

c o n t e x t . b e g i n P a t h () ; c o n t e x t . _________(____ ,

Нос

c o n t e x t . _________(____ , c o n t e x t . __________ () ;

Рот. Самый мудреный аспект! c o n t e x t . b e g i n P a t h () ; c o n te x t.

(3 0 0 ,

350,

_, d e g re e s T o R a d ia n s (_

)

, d e g re e s T o R a d ia n s (_

c o n t e x t . s t r o k e () ;

дальше ►

355


добавление jsonp для твиттера

Добро побаловать обратно... Итак, вы вернулись отдохнувшими. Мы с вами находим­ ся на заключительном этапе. Нам осталось лишь обеспе­ чить отображение твитов и прочего текста при предвари­ тельном просмотре футболки в c a n v a s . Теперь, чтобы добавить в c a n v a s твит, нам сначала нуж­ но извлечь последние твиты пользователя, из которых можно будет выбрать желаемый, для чего воспользуем­ ся JSONP. Из главы 6 вам уже известно, как это делается (если требуется освежить свои знания, вернитесь к гла­ ве 6). Вот что нам нужно будет сделать:

Говоря о вкусностях, помните JSONP-код, который мы готови­ ли в главе 6? Пора достать его из «духовки».

flo6aBHTb<script>BHH)KHK)K)4acTb4>aimatweetshirt. html для вызова API-интерфейса JSONP Twitter. Мы бу­ дем запрашивать самые последние статусные обновле­ ния определенного пользователя. Реализовать функцию обратного вызова для извлечения твитов, которые Твиттер будет присылать в ответ. Имя этой функции обратного вызова мы используем в URLадресе для <script> во время шага 1. Наш HTML-ф айл для T w e e ts h ir t Представьте, что здесь находится ваш элем ент <head>> а здесь — ваш элем ент <form> (мы просто решили сэкономить место).

£

<body> < fo rm >

< /fo r m >

J S O N P -вызов; он работ ает п у т е м извлечения J S O N -данных, получаемых посредством обращения к URL-адресу Т в и т т е р а , с последующей передачей этих J S O N -данных функции обратного вызова (кот орую мы определим через несколько мгновений). Вызов A P I-инт ерф ейса Twitter. Можете зам енит ь это Мы запрашиваем временную шкалу своим именем пользовапользоват еля>что даст нам п о т еля или другим , если следние статусы. ^ | пожелаете.

< s c r i p t s r c = " h t t p : / / t w i t t e r . c o m / s t a t u s e s / u s e r _ t im e lin e / w ic k e d s m a r t ly . j s o n ? c a llb a c k = u p d a te T w e e ts "> < /s c r ip t> < /b o d y > < / h tm l>

Функция обратного вызова, которой будут передаваться JSON -данные.

Здесь много чего происходит. Если вы не все поним ает е, снова взглянит е, как работ ает JSONP, обратившись к главе 6 .

356

глава 7

Наберите все это в одной строке в своем т екст овом файле ( у м е ­ с т и т ь все в одну строку в книге не получилось).


раскрываем в себе художника

извлечение твитов Мы уже п о к о п ч и л и со слож пой работой, заключавш ейся в извлече­ нии твитов из Твиттера. Теперь пеобходимо добавить их в элем епт <select>, используемый для вы бора твитов, в элемепте <f orm> па­ ш ей страпицы. Еще раз повторим: когда происходит вызов фупк­ ции обратпого вы зова (в паш ем случае — update Tweets), Твиттер передает ей ответ, содерж ащ ий твиты в ф орм ате JSON.

Ответ Твиттера пред­ ставляет содой массив твитов. Каждый твит включает в себя массу данных; мы будем использо­ вать текст т вит а.

О тредактируйте файл tweetshirt.j s и добавьте фупкцию update Tweets в его пижпюю часть: функция обратного вызова

Данной функции передается от вет , содержащий твиты с временной шкалы пользова­ теля в виде массива твитов.

Извлекаем ссылку на tweetsSelection из <form>.

function updateTweets(tweets) { var tweetsSelection = document.getElementByld("tweets'

for

(var i = 0; i < t weets.length;

i++)

tweet = tweets[i];

8 случае с каждым т вит ом в массиве твитов мы сделаем следующее.

{ ^

— ■*

var option = document.createElement("option’ ) ;

Извлекаем твит из массива. ^ — Создаем новый элемент option.

< ------------- Задаем

option.text = tweet.text;

для его te x t значение tweet.

option.value = t w eet.t e x t .replace ("\"", "'")

также задаем для его value аналогичное значение, но т оль­ ко немного обрабатываем при этом ст р0Ку с целью замены двойных кавычек одинарными (чтобы избежать проблем ,

•А

tweetsSelection.options.add(option)

tweetsSelection.selectedlndex

ч

Наконец мы заботимся о т о м j что первым будет идти выбранный т вит , п у ­ тем присваивания свойству selectedlndex элемента <select'> значения О (номер перво­ го элемента o ptio n , который в нем содержится).

Затем берем новый элемент option и до­ бавляем его в tweetsSelection в <form>.

Т т % ц * С* *°РматиР°вания

После того как мы продела­ ем это с каждым т вит ом, у нас получится элемент <select>j содержащий option для каждого твита.

дальше ►

357


тестирование tweetshirt с твиттером

TwectShlrt

Tecm-драйб TweetShirt

L t j ^ r o ■'■»:ca Kxo-Bcn/HTHLS^c-jhin^indcxJhD

С ] (QlS£*4£_J_ _ g;^

П роведем пебольш ой тест-драйв. Убедитесь, что вы добавили весь соответствующ ий код в tweetshirt. j s и index .html. Также удостоверьтесь, что вы используете имя пользователя Твиттера, у которого имею тся све­ жие твиты , в вашем URL-адресе script src (благодаря чему вы сможете быть уверепы в том, что обязательпо Selectbackgroundcolor:{ ; увидите твиты !). Загрузите страпицу и щ елкпите па Circlcs or squares? Гммы*» (;•{ элемепте для вы бора твитов. Вот что мы видим: Select Lexl a iliir:

М е н ю выбора твитов

с НАСТОЯЩИМИ т $итами. Класс.

J^lck a tweeu j (jPrnviw)

Если вы поклонник Твиттера, носите футболки TweeiShirl

^ (

Ребята, это здорово. Мы можем Л рисовать квадраты и круги, а Джим позаботился об извлечении твитов из Твиттера! ) А что дальше?

Планшетный к о м п ь ю ­ т ер Фрэнка Д ж им : Мы почти достигли цели. Н еобходимо разобрать­ ся с текстом, которы й будет отображаться. У пас имею т­ ся два сообщ ения: Я повелся на этот твит... и ...а в результате получил эту паршивую м а й к у !, а также твит, которы й пользователь вы берет для отображ епия. Сей­ час нам нужно понять, как обеспечить их отображ епие, не говоря уже о прим енении стилизации к тексту. Ф рэнк: Полагаю, что мы можем вставить текст в canvas, а затем прим енить к нему CSS? Д ж о: Не думаю, что все будет происходить имеппо так. Как известно, canvas является областью для рисовапия, и я не думаю, что мы сможем поместить в пего текст и стилизовать его; пам придется рисовать текст в canvas. Д ж пм : Недавпо я получил хорош и й урок и па этот раз павел справки, какой API-иптерф ейс предпазпачеп для работы с текстом. Д ж о: Это хорош о, по сам я пока еще пе смотрел что к чему; как оп работает?

358

глава 7


раскрываем в себе художника

Джпм: Помпиш ь метод arc? С его помощью пам и придется рисовать весь текст. Фрэпк: Ты что, шутишь? Похоже, теп ерь мы провозим ся весь уикепд. Джпм: Как я тебя подловил! Если серьезпо, то существует метод fillText, которы й п рипим ает текст для рисовапия в canvas паряду с п озиц и ей х, у, где оп будет рисоваться. Джо: Звучит довольпо просто. А как пасчет разли чи й в стиле? Н асколько я помпю оригипал-макет, ш ри ф т текста твита в пем был курсивпый, а остальпого текста —полужирпый.

Джпм: Н ам нужпо еще пемпого покопаться, поскольку существуют разпообразпы е методы для задапия вы равпивапия, ш риф тов и стилей, по я пе очепь хорош о зпаю, как их использовать. Фрэпк: Если подумать, то я, возможпо, мог бы помочь, по как это сделать без CSS? Джпм: П рости, по как сказал Джо, это API-иптерф ейс для рисовапия в canvas, и оп пе использует HTM L или CSS.

Джо: Тогда давайте остаповимся па даппом API-иптерфейсе, после чего можем попробовать парисовать текст «Я повелся па этот твит...» в canvas. Фрэпк, присоединяйся к пам, все пе так уж и плохо, и я увереп, что пам пригодятся твои зпапия в области ш риф тов, стилей и тому подобпого.

Фрэнк: К онечно, я к вашим услугам!

Нам необходимо нарисовать т е к с т «Я повелся на э т о т т вит ...» над реальным т в и т о м пользователя в левом верхнем у гл у

Ч

Я ------------------------------------------повелся на этот твит...

Тбит алы будем рисо ‘ ват* зЫсъ, посередине.

А за т е м мы нари су­ ем «...а в р е зу л ь т а т е получил э т у паршивую м айку!» справа внизу, под т е кс т о м твита.

...ав результате получил эту паршивую майку!

Select background color. Circles o r Squares?

(wbtej

fg'Vdes] t )

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

Select text c o lo r Peek a tw e e t: tp rew e w j

[@ stArbuzzceo you're о^a^shiirt #tweetsi

3 м еню выбора т вит о в у нас уже и м ею т ся варианты.

дальш е ►

359


обсуждение структуры и представления

Что меня смущает относительно рисова­ ния текста в canvas, так это то, что мы всегда акцентировали внимание на отделении содер­ жимого от представления. А в случае с canvas похоже, что они являются одним и тем же. Я хочу сказать, что они не кажутся отдельными.

Это точно подмечено. Д авайте разберемся, почему так обстоит дело. Как вы помпите, ca n v a s является инструментом, позволяю щ им представлять графику в браузере. Все в ca n v a s считается представлепием, а не содержимым. Таким образом, несм отря на то что обы ч­ но вы рассматриваете текст — и, конечно же, твиты — как со­ держ имое, в данном случае вам следует рассматривать его как представление. О н является частью дизайна. Подобпо худож­ нику, которы й использует художественные заглавные буквы как часть своей картины , вы используете твиты как часть дизайпа футболки. Одна из главных п ричин того, что отделение представлепия и содержимого —хорош ая идея, заклю чается в том, что браузер может с умом подходить к представлению содержимого в раз­ личны х ситуациях: наприм ер, он мож ет представлять статью с новостного веб-сайта одним образом на большом экрапе и Д р у ­ гим —на экране телеф она. В случае дизайпа футболки пам пеобходимо, чтобы содерж и­ мое c a n v a s больше походило п а изображ епие: опо долж по ото­ браж аться одипаково пезависимо от того, каким образом вы будете его просматривать. Итак, давайте парисуем текст в c a n v a s и запустим паш стартап!

360

глава 7


раскрываем в себе художника

развлечения с магнитами Пришло время вашего первого эксперимента с текстом в ca n v a s . Ниже приведен начатый нами код для метода d ra w T e x t, который мы будем вызывать, чтобы нарисовать весь текст в c a n v a s для предвари­ тельного просмотра. Посмотрите, сможете ли вы завершить данный код, чтобы нарисовать Я п о в е л ся на э т о т т в и т . . . и . . . а в р е з у л ь т а т е п о л учи л э т у паршивую м а й к у ! в c a n v a s , а рисование реального твита пользователя мы оставим на потом. Проверьте свои ответы в конце главы, прежде чем идти дальше.

f u n c t i o n d r a w T e x t( c a n v a s , c o n t e x t )

{

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " _____________________ " ) ; v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ; c o n t e x t . _________________= f g C o lo r ; c o n t e x t . _____________ = " b o ld c o n t e x t . _____________ c o n te x t.

Ha данный момент размещаем КОММентаpuu т а м j где будет распола­ гаться код для рисова­ ния текста твита. }

// //

Подсказка: это позиция х, у для текста «Я повелся на этот твит...».

le m s a n s - s e r i f " ; =" l e f t " ;

20 ,

(

40)

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

И звлечь нужный ва р и а н т и з меню выбора т в и т о в Н а р исо ва ть т в и т

c o n te x t, fo n t

Подсказка: мы хот им п о ­ местить текст в правый нижний угол.

c o n te x t. c o n te x t.

(" ...а

в р е з у л ь т а т е п о л учи л э т у паршивую м а й к у ! " ,

У Мы хот им нарисовать данный текст в 2 0 пикселах от правой стороны canvas и в 4 0 пикселах от основания canvas, чтобы он уравновешивал верхнюю ст року текста.

J

Q

canvas.height-40

"Я повелся на этот твит..." дальше ►

361


более пристальный взгляд на текст в canvas

/>

К ° д под увел и чител ьны м сш екл^м Теперь, когда вам представилась возможность нарисовать свой первый текст в ca n va s, пора более пристально взглянуть на методы и свойства для работы с текстом, доступные в API-интерфейсе Canvas. Как вы поняли из предыдущего задания, это довольно низкоу­ ровневый API-интерфейс: вам приходится сообщать c o n te x t, какой текст рисовать, какую позицию выбирать и какой шрифт использовать. В данной секции мы детально рассмотрим такие свойства, как t e x t A i i g n , f o n t , t e x t B a s e iin e , а также методы f i i i T e x t и s tr o k e T e x t , благодаря чему вы превра­ титесь В эксперта ПО тексту В ca n va s!

textj^ign

Свойство t e x t A i i g n определяет, где будет находиться якорная точка для текста. Значением по умолчанию явля­ ется " s t a r t " . c o n te x t. t e x t A iig n

= " le f t" ;

Возможные значения данного свойства: " s t a r t " , " e n d " , " l e f t " , " r i g h t " и " c e n t e r " . В арианты " s t a r t " и "e n d " означаю т то же самое, что и слева и справа в языках, где все пиш ется и читается слева направо (например, англий­ ский). В язы ках же, где буквы располагаю тся справа на­ лево (например, и ври т), под значениям и " s t a r t " и "e n d " будет пониматься соответственно справа и слева.

Вырав­ нивание по левому краю

Вырав­ нивание по центру

Вырав­ нивание по право­ м у краю

filfjext u s1joW]ext Текст с заливкой

Как и в случае с прямоугольниками, мы можем обводить текст и прим енять к нему заливку. Мы указываем текст для рисования, позицию х, у и опциональны й парам етр m a x wi d t h , что обеспечит масш табирование текста, если он окажется ш ире, чем значение ma xw i d t h. context.fiiiT ext("D og",

1 00,

context.strokeT ext("C at",

100,

100,

200);

15 0,

Dog1 ^ m Текст

с обводкой

200);

Если текст окажется шире ZOO п и к ­ селов, он автоматически будет подо­ гнан посредством масштабирования.

362

глава 7


раскрываем в себе художника

follt

П ри задании значений для свойства fo n t вы мож ете прим енять тот же формат, что и в CSS, - это удобно. Если вы будете задавать все значения для данного свойства, то среди них будут следующие: стиль ш риф та, его толщ ина, разм ер, семейство —именно в таком порядке. c o n t e x t . f o n t = "2em L u c id a G ra n d e "; c o n t e x t . f i l l T e x t ( " T e a " , 100, c o n te x t.fo n t = " i t a l i c

1 0 0 );

b o ld 1 .5 e m T im e s ,

c o n te x t. f i l l T e x t (" C o ffe e " ,

100,

s e r if" ;

1 5 0 );

В специф икации рекомендуется использовать только векторны е ш риф ты (растровы е ш риф ты не очень хорош о отображ аю тся).

textj}as e W

Свойство t e x t B a s e li n e устанавливает точки вы равнивания в случае со ш риф том и определяет линию располож ения ваших букв. Ч тобы увидеть, как эта лин и я влияет на текст, попробуйте начертить ее в той же точке х, у, где вы рисовали текст. ^

c o n te x t.m o v e T o ( 100,

100);

c o n t e x t . l i n e T o (2 5 0 ,

1 0 0 );

c o n t e x t . s t r o k e () c o n t e x t . t e x t B a s e li n e

alphabetic

Alphabet

c o n te x t.b e g in P a th ( ) ;

= " m id d le " ;

c o n t e x t .f illT e x t ( " A lp h a b e t" ,

100,

'

100);

A lp h a b e t

b o tto m

A lp h a b e t ^

m iddle

Alphabet ^

top

-

Возможные значения данного свойства: " t o p " , " h a n g in g " , " m i d d le " , " a l p h a b e t i c " , " id e o g r a p h ic " и " b o tto m " . Значением по умолчанию является " a lp h a b e t ic " . П о­ экспериментируйте с разны ми значениями, чтобы выяснить, какое именно из них вам требуется (а также загляните в специф икацию для получения дополни­ тельных сведений). оальше ►

363


рисование текста

Применение drawText Теперь, когда вы узпали еще об одпом API-иптерф ейсе, паберите код, пад которы м вы работали в п р е­ дыдущем упраж пепии «Развлечепия с магпитами». Вот как оп будет выглядеть после того, как таблички с кодом окажутся па своих местах: fu n c t io n

d r a w T e x t( c a n v a s , c o n t e x t )

v a r s e le c tO b j

{

= d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r " ) ;

v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ; c o n te x t. f i l l S t y l e

= f g C o lo r ;

c o n t e x t . f o n t = " b o ld c o n te x t. t e x t A lig n

le m s a n s - s e r i f " ;

= " le f t" ;

c o n t e x t . f i l l T e x t ( "Я п о в е л с я на э т о т т в и т " ,

20,

40)

Через несколько мгновений мы помест им сюда код для рисования текста твита... c o n t e x t . f o n t = " b o ld c o n te x t. t e x t A lig n

le m s a n s - s e r i f " ;

= " r ig h t" ;

c o n t e x t . f i l l T e x t ( "а в р е з у л ь т а т е п о л у чи л э т у паршивую м а й ку ! c a n v a s .w id t h - 2 0 , c a n v a s . h e i g h t - 4 0 ) ; }

Н апечатав даппы й код, обповите фупкцию p r e v ie w H a n d le r с целью вы зова фупкции d ra w T e x t и проведите тестирование, загрузив даппы й код в своем браузере. Вы долж пы увидеть прим ерпо то же самое, что и мы: Вот наш текст. У нас получился т екст , имеющий полужирный шрифт без засечек и корректное местоположение. пы е*

AT

Я по в е л с я на это т тви т...

а в р е зу л ь тате пол учил э ту п ар ш и в у ю м айку!

Select background color; j ммыИЦ Circles or equine*'* | Нем** «Н

Sekul ibxI ^riun 04rt 1i) Pick a tw c c c | Если вы поклонник Твиттера, носите футболки TweetShirt

'Prwvtwj

364

глава 7

/ О

А внизу

у нас полу­ чился текст с вырав­ ниванием по правому краю.

г Возьми в руку карандаш Попытайтесь самостоятельно завершить на­ писание функции d ra w T e x t. Вам необходимо извлечь выбранный твит, задать курсивный шрифт с засечками, который немного круп­ нее (1 .2 е т ), чем шрифт по умолчанию, а так­ же убедиться в том, что текст будет выровнен по левому краю, и разместить его в точке х = 30, у = 100. Это последний шаг перед тем, как мы увидим в работе TweetShirt!

Н а п и ш и т е свой код в в е р х у и не з а г л я д ы в а й т е на с л е д у ю щ к , с т ран и ц у ! (Мы серьезно!)


раскрываем в себе художника

Завершаем написание функции drawText Вот приводивш ийся чуть выше код, паписапие которого заверш или мы. Ну что, каков результат, если сравпить его с паписаппы м вами? Если вы еще пе пабрали свой код, то используйте код, приведеппы й пиж е (либо свою версию , если предпочитаете), и перезагрузите ф айл i n d e x . h t m l. Наш тест-драйв мы продемонстрируем вам па следующей страпице. f u n c t io n

d r a w T e x t( c a n v a s , c o n t e x t )

v a r s e le c tO b j

{

= d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r " ) ;

v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;

Нам не потребуется выравнивать текст твита по левому краю , выравнивание по-преж нем у будет обеспечиваться отсюда.

v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

c o n te x t. f i l l S t y l e

= f g C o lo r ;

c o n t e x t . f o n t = " b o ld c o n te x t. t e x t A iig n

le m s a n s - s e r i f " ;

= " le f t" ;

c o n t e x t . f i i i T e x t ( "Я п о в е л с я на э т о т т в и т . . . " ,

20 ,

40)

И зв л е ка е м н у ж н о м п а р а м е т р

и3 м е н ю выбора твитов. selectObj = document.getElementByld (11tweets11) index = selectObj.selectedlndex;

крупный курсивный шрифт с засечками...

З а д а е м <5олее

var tweet = selectObj[index].value; context.font = "italic 1.2em serif"; context.fiiiText(tweet, 30, 100);

c o n t e x t . f o n t = " b o ld c o n te x t. t e x t A iig n

■и рисуем т екст , имеющий позицию 3 О, НОО.

le m s a n s - s e r i f " ;

= " r ig h t" ;

c o n t e x t . f i i i T e x t ( " . . . a в р е з у л ь т а т е п о л у чи л э т у паршивую м а й к у ! " , c a n v a s .w id t h - 2 0 , c a n v a s . h e i g h t - 4 0 ) ;

О

Фрэнк, скорее вы­ бирай предварительный просмотр. Я хочу увидеть наше приложение T w eetS h irt в работе!

дальше ►

365


запуск tweetshirt

Небольшой тест-драйв, о затем — JfteW AJC ЗАПУСК! Надеемся, что вы видите то же самое, что и мы! Здорово, не правда ли? Про­ ведите тестирование интерфейса с целью проверки качества созданного программного продукта: попробуйте всевозможные комбинации цветов и фигур, замените имя пользователя дру­ гим по своему усмотрению.

9 П П

T*-e«5Mrt

■«“Til"*!©!*»:/

i.'TetiUtKn.inaeic.iKr

Я повелся на этот твит..

На футболке при предвари тельном просмотре отобража­ ется твит. Здорово!

Если вы поклонник Твиттера, носите футболки Tweetshirt

а в результате получил эту паршивую майку! Sekct background color: ( Ч1й« ?«j Circles or squares'* 1arete* i: j Se'ect Uixt декхт P ic k 4 tWeCC 1 Если вы поклонникТвиттера, носите футболки Tweetshirt

Вам кажется, что вы по-настоящему готовы переходить к запуску стартапа Tweetshirt? Давайте сделаем это!

г

Да! Все работает! Мы готовы к за­ пуску стартапа!

Ребята, не хочу вас разоча­ ровывать, но вы еще не все сделали. Вы также должны были поместить изображение птицы Твиттера на футболку!

Т Помните основательницу TweetSkirt.com ?

366

глава 7

С i f a 1 G:og)e


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

о Давайте сей­ час вместе прой­ демся по нему...

В первую очередь пам пужпо изображ епие. Мы поместили файл t w i t t e r B i r d . p n g в папку TweetShirt. Ч тобы добавить его в c a n v a s , пам спачала потребуется JavaScript-объект Im age. Вот как оп создается: ^ --------- ‘

Создаем объект Image.

var twitterBird = new I m a g e (); ^—

twitterBird. s rc = "twitterBird.png";

И задаем в качестве его источника изображение птицы Твиттера.

Следующий шаг уже долж еп показаться вам вполпе естествеппым. Н ам пужпо парисовать изображ епие в c a n v a s , используя метод объекта c o n t e x t с имепем, как вы уже догадались, d ra w lm a g e .

context.drawlmage(twitterBird, 20, 120, 70, 70); ^

Используем метод drawlm age.

3 от наш объект Image.

^

Кром е того, указываем значения координат местоположения х, у, ширины и высоты.

Об изображ епиях вам пужпо зпать еще одпу вещь: опи пе всегда загружаются мгповеппо, по­ этому вам будет пеобходимо удостовериться в том, что изображ епие полпостью загрузилось, преж де чем вы приступите к его рисовапию . Как мы ждем, пока что-то загрузится, перед тем как п редприпять действие? Мы реализуем для этого обработчик o n lo a d : Здесь мы говорим: «Когда изо бражение загрузится, выполнить

twitterBird.onload = function

()

{

данную функцию».

context.drawlmage(twitterBird, 20, 120, 70, 70); V -'

Рисуем изображение в canvas, используя метод draw lm age объекта context. дальше ►

367


добавление изображения

Посмотрите, сможете ли вы собрать функцию d r a w B ir d из всех тех кусочков, которые нам предоставила Джуди. Функция d ra w B ird принимает canvas и c o n te x t и рисует изображение птицы в ca n va s. Исходите из того, что с помощью данной функции мы должны разместить " t w i t t e r B i r d . p n g " в месте с координатами х = 20, у = 120, при этом ширина и высо­ та будут равны 70 пикселам. Мы уже написали за вас объявление метода и первую строку. Решение данного упражнения вы найдете в конце главы.

f u n c t io n

d r a w B ir d ( c a n v a s ,

v a r tw itte r B ir d

c o n te x t)

{

= new Im a g e ( ) ;

Свой код напишите здесь.

Убедитесь, что вы добавили вызов функции drawBird в функцию preview Handler. }

Еще один mecm-драйВ Дважды проверьте свой код и проведите еще один тест-драйв! Здорово, теперь наше при­ ложение действительно выглядит отшлифо­ ванным. Сделайте несколько попыток; попробуйте вы­ брать Circles (Круги) или Squares (Квадраты) в меню Circles or squares? (Круги или ква­ драты?). Вы заметите, что мы использовали изображение в формате PNG с прозрачным фоном, чтобы круги и квадраты были видны, если они окажутся позади изображения птицы. Здорово, мы значительно пре~ успели в разработке классного приложения. Но, как уже от м е ­ чалось ранее, мы рассчитываем на вас в реализации всего необхо­ димо для ведения торговли через Интернет и выполнения заказов, связанных с футболками, и т. п.

368

глава 7

^

T.VCCtShlrr

Я повелся

ЛОКЛ°ННиКТвиттера’ носитеФутболки T.ee,Shirt •ав результате получил эту паршивую майку!

Select


раскрываем в себе художника

4acm°

ЧаДаБаеМые В опросы

Мы раньше не сталкивались с объектом im a g e . Вы ис­ пользовали его при добавлении изображения в c a n va s. А что он собой представляет? Почему его нельзя было создать с помощью

d o c u m e n t. c r e a t e E le m e n t ( " im g " )?

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

0 : Оба упомянутых вами метода позволяют создавать объекты

также будут корректно отображаться в браузере. Однако в canvas

Image. JavaScript-конструктор Im age предоставляет более пря­

они выглядят не так хорошо. К сожалению, в настоящее время в

мой путь создания изображений из JavaScript и дает нам больший контроль над процессом загрузки (например, позволяет исполь­ зовать обработчик для получения уведомления, когда загрузка изображения завершается). Наша цель заключается в создании изображения, а также в том, чтобы убедиться, что оно уже загрузи­ лось, прежде чем мы приступим к его рисованию в canvas. Объект Im age позволяет сделать это оптимальным путем.

API-интерфейсе Canvas нет функции для преобразования данных сущностей обратно в соответствующие символы, поэтому вам придется делать это самостоятельно. ^

J А можно ли сделать в c a n va s что-нибудь необычное, напри­

мер снабдить текст или фигуры тенью? Q J Да! С помощью ca n va s вы можете делать массу необычных

которые трудности по сравнению с HTML. Что-то сложнее базовых фигур, по-видимому, действительно будет сложно нарисовать.

вещей, и эффект отбрасывания тени относится к их числу. Как вы и могли ожидать, создание тени осуществляется путем присваива­ ния значений соответствующим свойствам c o n te x t . Например, чтобы задать степень размытия, необходимо присвоить требуемое

Q j Вы, несомненно, пишете код графики, когда программируете

ca n va s. В отличие от браузера, который вместо вас заботится о массе деталей вроде добавления элементов на веб-страницу (благодаря чему вам не нужно самим все рисовать), вам придется говорить can vas, где все должно размещаться. Однако ca n va s обеспечивает широкие возможности создания графики почти что любого типа (в настоящий момент — 2D). Мы пребываем на на­ чальном этапе существования c a n v a s ; вероятно, библиотеки JavaScript-KOfla смогут облегчить создание графики в c a n v a s в будущем. В случае с очень длинными твитами я заметил, что часть такого твита, выходящая за край c a n v a s , просто исчезает из виду. Как это исправить? 0 : Сначала нужно выяснить количество символов, содержащих­ ся в твите, и если оно будет превышать определенное число, то разбить данный твит на несколько строк и рисовать каждую из них отдельно в c a n v a s . Мы включили соответствующую функцию s p l i t in t o L in e s в код, доступный по адресу wickedlysmart.com.

значение свойству c o n t e x t . s h a d o w B lu r. Местоположение тени задается с помощью свойств c o n t e x t . shadow O f f s e t x и c o n t e x t . shadow O f f s e tY , а чтобы установить цвет, нужно присвоить значение свойству c o n t e x t . shadow C olor. К прочим возможностям canvas относится рисование градиентов, вращение фигур и закругление углов прямоугольников.

В

I Что еще интересного можно делать в случае с canvas?

0 : Много чего! В следующих главах мы расскажем еще о паре способов использования c a n v a s . Кроме того, вы определенно захотите более подробно исследовать API-интерфейс Canvas, для чего можете зайти по адресу http://dev.w3.org/html5/2dcontext/. А будет ли все создаваемое в ca n va s работать и на моем мобильном устройстве или мне придется переписывать его для мобильных пользователей? 0 : Если на вашем мобильном устройстве установлен современ­ ный браузер (на всех устройствах вроде Android, iPhone и iPad

Я также заметил, что в некоторых твитах имеются HTMLсущности вроде " и &атр;. Что все это значит?

как раз имеются такие браузеры), то все будет отлично работать

0 : API-интерфейс Twitter, используемый нами для извлечения твитов в виде JSON-данных, преобразует символы, которые поль­ зователи печатают в своих твитах, в HTML-сущности. Вообще-то

заключается в том, что, поскольку вы рисуете «сырые» пикселы,

(масштабирование страницы может быть отключено, однако функ­ циональность сохранится). Замечательная особенность ca n va s все создаваемое вами будет везде отображаться одинаково (то есть во всех браузерах, которые поддерживают canvas).

дальше ►

369


Для этого придется еще потрудиться. Н а самом деле ca n v a s призван быть простой поверхностью для рисования. Когда вы создаете фигуру, ca n v a s видит ее как группу пикселов. О н ничего не знает об особеппостях того, что вы рисуете, и не отслеж ивает никаких фигур, а просто соз­ дает пикселы, которы е вы говорите ему создать (если вам зпакомы такие терм ины из области граф ики, как «растровое р и ­ сование» и «векторное рисование», то вы пойм ете, что ca n va s осущ ествляет растровое рисование).

Если вам захочется обходиться с прямоугольпиками в своем ca n v a s как с набором объектов, которы й можпо будет сохра­ нить (или, возможно, вы захотите перемещ ать его или мани­ пулировать им), то вам потребуется сохрапять ипф орм ацию о фигурах и контурах по ходу рисования их в canvas. Вы сможе­ те сохранить эти данны е в JavaScript-объектах. Н априм ер, если вы захотите отследить произвольны е круги, парисоваппы е вами в ca n va s при работе над TweetShirt, вам потребуется со­ хранить координаты м естополож ения х, у, зпачепия радиуса и цвета каждого конкретного круга, чтобы вы смогли воссоздать его позже. П охоже, что это и есть плап действий, которы й вам п уж еп ...;)


раскрываем в себе художника

Поздравляю, ребята, вам удалось это сделать! Созданное вами при­ ложение работает даже на моем iPad, так что оно идеально подойдет для клиентов, находя­ щихся в дороге. Я впечатлена. У нас намечается вечеринка по поводу запуска стартапа Tw eetS hirt, поэтому присоединяйтесь к нам.

Основательница T w e e ts h irt.сот рада видеть, что созданное нами веб-приложение работает на ее iPad и iPhone! Если она рада , то и мы рады.

дальше ►

371


обзор canvas

КЛЮЧЕВЫЕ МОМЕНТЫ ■

« J O ' -------------------

canvas — это элемент, который вы размещаете в сво­

ей странице с целью создания области для рисования. ■

ca n va s не будет иметь стиля по умолчанию или со­

пока не нарисуете что-нибудь в нем или не добавите

canvas. Контур нельзя будет увидеть до тех пор, пока

У

вы не обведете его или не примените к нему заливку.

вас на странице может иметься более одного ■

Для создания треугольника необходимо начать контур с ПОМОЩЬЮ b e g in P a th , а ЗЭТвМ ИСПОЛЬЗОВЭТЬ moveTo

можно было обращаться с использованием JavaScript.

и lin e T o для рисования контура. Для соединения двух

Для задания размеров элемента c a n va s следует ис­

точек контура используйте c lo s e P a th .

пользовать его атрибуты w id t h И h e ig h t .

Чтобы нарисовать круг, начертите 360-градусную дугу. Начальный угол будет 0°, а конечный — 360°.

Все, что вы захотите поместить в c a n v a s , будет рисоваться с применением JavaScript.

Контур — это невидимая линия или фигура, которую

рамку для него с помощью CSS).

canvas. Вам, конечно же, потребуется присвоить каж­

Для рисования произвольных фигур или дуг сначала

вы чертите для определения линии или области в

дому из них уникальный идентификатор, чтобы к ним

не существует. Чтобы нарисо­

необходимо начертить контур.

держимого, пока вы не снабдите его им (таким образом, вы не увидите c a n v a s на веб-странице до тех пор,

Метода f i l l C i r c l e

вать круг в c a n v a s , вам потребуется начертить дугу.

Углы задаются в canvas с использованием радианов,

Для рисования в c a n v a s вам сначала нужно будет

а не градусов, поэтому нужно преобразовать градусы

создать контекст. В настоящее время вашим един­

в радианы, чтобы задать начальный и конечный углы.

ственным выбором является контекст 2d, однако в бу­

2% радианов.

360 градусов =

Чтобы нарисовать текст в canvas, используйте метод

дущем возможно появление и других типов контекста. ■

Контекст необходим ДЛЯ рисования В ca n va s потому, что он обеспечивает специфический тип интерфейса (например, 2d и 3d). Вы сможете выбирать нужный

fiiiT e x t. ■

ТИП Интерфейса ДЛЯ рИСОВаНИЯ В ca n va s. ■

Обращаться к c a n v a s следует с использованием свойств и методов объекта c o n te x t .

Объекта c o n te x t . ■

c o n t e x t , оно применяется на протяжении всего про­ цесса рисования, пока вы не присвоите этому свойству

но воспользоваться методом c o n t e x t . f i l l R e c t .

другое значение. Например, изменение значения свой­

Он создает прямоугольник с заливкой цветом.

ства f i l i s t y l e

Чтобы нарисовать контур прямоугольника, вместо

создаваемых вами после присваивания этому свойству

f i l l R e c t используйте МвТОД s tr o k e R e c t.

нового значения.

Используйте f i l l S t y l e

И s t r o k e S t y l e ДЛЯ ИЗ-

и обводки, которым является черный.

" # 0 0 0 0 0 0 ", " r g b ( о ,

о,

0) " ) . Не забывайте за­

глава 7

Добавление изображений в c a n v a s осуществляется

Чтобы добавить изображение в ca n va s, вам сначала потребуется создать объект Im age и убедиться, что

Вы можете задавать цвета, используя тот же са­

ключать значение f i l i s t y l e в кавычки.

повлияет на цвет фигур и текста,

с ПОМОЩЬЮ метода d ra w lm a g e .

соответствующее изображение полностью загрузилось.

мый формат, что и в CSS (например, " b l a c k " ,

372

Когда вы задаете значение для свойства объекта

Чтобы нарисовать в c a n v a s прямоугольник, нуж­

менения задаваемого по умолчанию цвета заливки

При рисовании текста в c a n v a s вам будет нужно указывать позицию, стиль и пр., используя свойства

Рисование в c a n va s сродни растровому рисованию в программах для работы с графикой.


раскрываем в себе художника

Ьеовилль — здесь ты узнаешь обо всем первым П осле экскл ю зи в н о го и н те р в ь ю м ы м ож ем сообщ ить, ч т о э л е м е н т ы <canvas> и <video> н е п р о с т о д е л я т д р у г с д р у г о м о д н и и те ж е в е б -с т р а н и ц ы ... О н и , н а п р и м е р , с м е ш и в а ю т св о е с о д е р ж и м о е .

Трой А рм строн г Ш Т А Т Н Ы Й А В Т О Р « В Е Б В И Л Л Ь С К О Г О КУР ЬЕР А » <video> говорит: «Это правда, мы наладили тесные взаимоотноше­ ния. Видите ли, я довольно простой парень, ко то р ы й умеет вос­ производить видео, причем делает это очень хорош о. Однако это п очти все, чем я занимаюсь. Но благодаря <canvas> все изменилось. Я облачаюсь в пользовательские элементы управления, я фильтрую свое видеосодержимое, я одновременно показываю несколько ви­ деоизображений». За комментариями мы обратились к <canvas>. Является ли он тем, кто стоит за тегом <video>? От <canvas> мы услышали следующее: «Что ж, <video> сам по себе очень хорошо справляется, ну там, знаете, с декодированием всех этих видеофайлов, сжатых опреде­ ленными кодеками, с поддержкой частоты кадров в секунду и тому подобным. Это большая работа, с ко то р о й мне никогда не удалось бы справиться. Однако с моей помозцыо он может избежать своего обы чного, осмелюсь даже сказать, «скучного» способа воспроизве­ дения видео. Я даю ему средства для исследования всех креативны х возможностей по объединению видео с веб-приложениями».

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

Ч то ж, кто бы мог такое предположить? Полагаю, что впереди нас ждут интересные вещи, которы е станут результатом партнерства <canvas> и <video>! М ож но ожидать, что последствия этого откровения мы будем наблю­ дать в главе, посвящ енной элементу <video>, когда его многообещ аю­ щее партнерство с <canvas> будет подвергнуто пристальному внима­ нию общественности.

оальше ►

373


кроссворд

U I M L 5 - it occ B t a Мы с п етерп еп и ем ждем следующей главы, где сможем подробпее погово­ рить о сепсациоппой повости, касаю щ ейся < c a n v a s > и < v id e o > . А вы тем врем епем закрепите свои повы е зпапия о c a n v a s , разгадав пеболы ной кросс­ ворд (возможпо, за чаш кой чая).

По горизонтали

По вертикали

2.

1. Данный метод объекта c o n t e x t создает прямоугольник.

Свойство, для которого мы задавали значение с целью заливки фигуры цветом. 5. Несуществующий метод, который Джим пытался использовать для рисования кругов. 6. Сообщить о завершении загрузки чего-либо можно с помощью обработчика____________ . 8. Для рисования кругов следует применять метод____________ . 9. Мы осуществляем ее для того, чтобы сделать контур фигуры видимым. 10. Хотите узнать, какой параметр был выбран? Тогда вам может потребоваться данное свойство. 11. Невидимая линия, которую вы чертите с целью нарисовать фигуру. 13. Мы выравнивали текст . . . а в р е з у л ь т а т е п о л учи л э т у паршивую м а й к у ! по_____________краю. 14. В круге 360____________ . 15. Все в c a n va s является____________ .

374

глава 7

3. < c a n v a s > и ____________ хорошо сочетаются друг с другом. 4. Объект, включающий методы и свойства для рисования

В ca n va s. 5. Используйте данный метод для рисования текста в canvas. 6. Наилучшее место для размещения хорошего твита. 7. Чтобы переместить карандаш при черчении контура в точку с координатами 100,100, используйте____________ (100,100). 12.

Мы думаем в градусах, a c a n v a s — в __________ .


раскрываем в себе художника

(Т А Н Ь браузером. Решение ] е п е р ь , к ° г д а у Бас е с т ь и н т е р ­ ф ей с, В ы полните п о в ед е н н ы е

Представьте, что вы используете этот интерфейс для выбора зна­ чений в случае со своей футболкой.

Здесь JaVa^cript—о п е ^ а т ^ ы и н а п и Ш и т е Значение д л я к а ж д о г о эл ем ен ­ т а и н терф ей са.

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " b a c k g r o u n d C o lo r " ) ; v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;

white

v a r b g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " s h a p e " ) v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;

circles

v a r shape = s e l e c t O b j [ i n d e x ] . v a l u e ;

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r ” v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

b la c k Не забывайте, что значение^ парам е­ тра может отличаться от текста, который вы видите в элементах управления; в нашем случае это как раз касается первых букв текста.

Обратите внимание, что в случае с каждым значением меню мы и з­ влекаем элемент select, в кот ором содержится соответствующий парам ет р , находим выбранный парамет р с помощью свойства selectedlndex и извлекаем значение этого параметра.

Select background color: [ White t ] Во

^

^

м ’ коглТ

' ^

Circles ОГ squares?

[ Neither

t j

При необходимости еще раз взгляните на H T M L , чтобы увидеть значения параметров.

Select text color: [ Black 11 ] Pick a tweet: [ ■; ] ( Preview)

дальше ►

375


решение упражнения

Развлечения с магнитами, решение Воспользуйтесь своими псевдомагическими способностями программиста для размещения в нуж­ ной последовательности приведенных ниже табличек. Вам нужно написать псевдокод для функции d ra w S q u a re . Данная функция принимает c a n v a s и c o n t e x t и рисует в c a n va s один квадрат произ­ вольного размера. Вот наше решение этого упражнения.

fu n c tio n

d ra w S q u a re

(

' {

Одну из табличек мы уже уизтьстили разместили за вас в нужном месте.

вычислить

произвольную ширину для квадрата

вычислить произвольную позицию X для квадрата внутри ca n va s вычислить произвольную позицию у для квадрата внутри canvas

Р а з м е с т и т е здесь таблички с п с е в д о ­ кодом в нужной п о ­ с л е д о в а т ел ь н о с т и !

Задать для fillstyle значение " lig h tb lu e " нарисовать квадрат, имеющий позицию х г у и ширину w

Возьми в руку карандаш Решение

fu n c t io n

Чтобы при каждом нажатии кнопки Preview (Предварительный про­ смотр) мы наблюдали в ca n va s только новые квадраты, потребует­ ся залить фон ca n v a s цветом, выбранным пользователем в меню " b a c k g r o u n d C o lo r " . Сначала реализуем функцию для заливки c a n v a s выбранным цветом. Ниже приведен код, в котором вам необ­ ходимо устранить пробелы. Вот наше решение этого упражнения.

f illB a c k g r o u n d C o lo r ( c a n v a s ,

c o n te x t)

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld (" var

in d e x =

s e le c tO b j . s e le c t e d ln d e x ;

var

b g c o lo r

= s e le c t O b j . o p t io n s [ in d e x ]

I c o n te x t. f i l l S t y l e

=

глава 7

i

b a c k g r o u n d C

o t o r - )

t

д дя заливки ф он а ц в е т о м МЫ р и с у е м . v a l u e ; п р я м о у г о л ь н и к , к о т о р ы й за п о л н я е т

ц в е т о м п о л н о с т ь ю весь canvas.

и ^ С 0 \ 0 \ Г ;

c o n t e x t . f i l l R e c t (0, 0 ,

376

^

{

ca n va s.w id tk, canvas-height)


раскрываем в себе художника

СТАНЬ браум ром . Решение п о в е д е н н ы й н и ж е Вызов ме-щ°да ale и H anuinuine все со о г^ве ш —

сщВутоЩие значения, KoiiioJ^bie х а р а к т е р и з о в а т ь Круг, а хпакж е u3o£pa3uine ду1Ч), со5ДаВаеМу!° В реЗуЛь-шагца эгцоГо Bj>i3oBa.

context.arc(100, 100, 75, degreesToRadians(270), 0, true); Начинаем здесь

черт им против часовой стрелки И

Радиус = 75* пикселов

Конечный угол = О0

Дуга

Начальный угол = 2 7 0 °

Umak, у нас е сть контур! U что теперь? ажнение "Piешение

Теперь вы будете использовать этот контур для рисования линий и заливки своей фигуры цветом, конечно же! Создайте простую НТМ1_5-страницу с элементом c a n v a s и наберите весь приводившийся чуть ранее код. Затем проведите тестирование.

c o n te x t c o n te x t c o n te x t c o n te x t c o n te x t

. b e g in P a t h ( ) ; .m o v e T o (1 0 0 , 1 5 0 ); . l i n e T o (2 5 0 , 7 5 ) ; . l i n e T o (1 2 5 , 3 0 ) ; . c lo s e P a t h ( ) ;

Вот код} приводившийся ранее

c o n t e x t . lin e W i d t h = 5 ;

Задать толщину линии для рисования поверх контура.

c o n te x t . s t r o k e ( ) ;

Нарисовать линию поверх контура.

c o n te x t . f i l l S t y l e c o n te x t • f i l l 0 ;

= "re d "

Задать красный цвет для заливки треугольника. Применить к треугольнику заливку красным цветом.

Загрузив веб-страницу Triangle , мы увидим вот это (для рисо­ вания мы создали canvas разм е­ ром ЗОО х ЗОО пикселов). у

дальше ►

377


решение упражнения

Перерыв, решение

il

X> У = 'Z-OO) 2 5 0 радиус = ZS Пора применить на практике ваши новые знания о дугах и контурах для создания улыбающейся рожицы. Устра­ ните пробелы в приведенном ниже коде, который позво­ лит нарисовать улыбающееся лицо. Мы предусмотрели для вас подсказки относительно того, где на диаграмме должны располагаться глаза, нос и рот.

ЪОО, 3 0 0 длина носа

Вот наше решение этого упражнения:

fu n c t io n

d ra w S m ile y F a c e ()

*

)

*> у = 4 0 0 , 2.s o

|

угол = 2 0 °

{

v a r c a n va s = d o c u m e n t. g e tE le m e n tB y ld ( " s m i l e y " ) ;

у = зоо, з so радиус = 7 s

v a r c o n te x t = c a n v a s . g e tC o n te x t( " 2 d " ) ;

c o n t e x t . b e g in P a t h ( ) ; c o n t e x t .a r c ( 3 0 0 , c o n te x t . f i l l S t y l e

300,

200,

0, d e g re e s T o R a d ia n s (360

= " # ffffc c ";

c o n te x t •f i l l ( ) ; c o n te x t . S tro k e ( ) ;

tr u e

К р' уг ...... лица. мы Здесь уже устранили за вас ооин из пробелов. внимание , М Ы ' Обратите " ~I ^ми/нипиЬ; применили к кругу заливку желт ым цветом.

Левый глаз. Центр Левый глаз. Центр круга имеет координаты х = 2 0 0 , и = 2SO оади2 5 , начальный цгол О. конечный Mn-f-u р I *- о э х J

c o n t e x t b e g in P a th о Р 5вод“ м конт ур , чтобы получить очертания круга ( н о ^ е з з а л и в к и у ^ ' c o n te x t a r с ( 2 0 0 ,

2 5 0 , 2 5 , О, dcgrCCS~ToRacliaiAS(3G?0), t r u e ) ;

c o n te x t S tro k e о ;

&

c o n t e x t b e g in P a th () ; c o n t e x t a r c (4 0 0 , Z S O ,

7 - 5

c o n te x t s tr o k e ( ) ,

Правый глаз. Такой Же, как и левый, но с координатой X = 40 0 . Мы используем

, О, degireesToRadians(3<bO), t r u e ) ; направление против часовой стрелки (значение true) (при рисовании полного круга направление неважно).

П О Л Ь З и Р . А Л 1ЛЛ rw/o'Tn^'z./ Это нос. Мы используем m oveTo(300, з ОО) для перемещения пера в точку х ' '' У - 3(9(9, чтобы начать создание линии c o n t e x t . m oveTo (ЗОО, ЪОО) ; о ' uZm b Т при™еняем "™ Т о (3 0 0 , 3SO), поскольку нос будет ' c o n t e x t . ИпеТо (ЪОО, Ъ 50) ; имет ь длину s o пикселов. После этого обводим конт ур c o n t e x t .s tro k e о ; Чтобы у нас получилось более правдоподобное улыба­

c o n t e x t . b e g in P a t h ( ) ;

ющееся лицо, начинаем и заканчиваем чертить края У рта на 2 0 ° ниже оси X. Это означает, что начальный X угол будет равен 2 0 °, а конечный составит г<ЬО°.

c o n t e x t . b e g i n P a t h () ; c o n te x t

0 Х С (

300,

c o n t e x t s t r o k e () ;

378

глава 7

350,

75

,

d e g re e s T o R a d ia n s

( 2 0 )

,

d e g re e s T o R a d ia n s

(К Ь О )

,

fa ls e );

Направление — против часовой стрелки (значение false), ^ поскольку нам нужен улыбающийся рот (не забывайте, что начальная точка находится справа от центра рта).


раскрываем в себе художника

Развлечения с магнитами Пришло время вашего первого эксперимента с текстом в c a n va s. Ниже приведен начатый нами код для метода d ra w T e x t, который мы будем вызывать, чтобы нарисовать весь текст в c a n v a s для предвари­ тельного просмотра. Посмотрите, сможете ли вы завершить данный код, чтобы нарисовать Я п о в е л ся на э т о т т в и т . . . и . . . а в р е з у л ь т а т е п о л у чи л э т у паршивую м а й ку ! в c a n v a s , а рисование реального твита пользователя мы оставим на потом. Вот наше реш ение этого упражнения. f u n c t i o n d r a w T e x t( c a n v a s , c o n t e x t )

{

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ("

fo r e g r o u n d e d or

v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ; f i l l S t y l e | = f g C o lo r ; fo n t

c o n te x t.

/ /

\

=

" b o ld

le m s a n s - s e r i f " ;

Подсказка: это позиция x, у s-^ д л я текста «Я повелся на V этот твит...».

te x t A iig n

" le f t" ;

fiiiT e x t i

" я повелся на этот твит..."

И звлечь выбранный т в и т и з меню выбора т в и т о в --

20 ,

40);

Подсказка:

МЫ

будем испоЛЬ

зовать курсивный шрифт На данный / / Н а р исо ва ть т в и т с засечками для твита, од­ момент мы нако нам необходимо, чтобы размещаем ^ этот текст имел полу ком мент а Жирный шрифт Helvetica. рии т а м > c o n t e x t . f o n t = " b o l d l em sans-serif In . где будет Подсказка: мы хот им поместить c o n te x t. t e x t A iig n распола­ J = текст в правый нижний угол. гаться код c o n t e x t . f i i i T e x t I ( " . . . а в р е з у л ь т а т е п о л у чи л э т у паршивую м а й к у ! " , для рисова ния текста c a n v a s .width-20 i~' - c a n v a s . height-4^Jj ' твита. } M w х о т и м нарисовать данный ^ текст в ZO пикселах от правой стороны canvas и в 4 0 пикселов от основания canvas , чтобы он ур а в­ новешивал верхнюю строку текста.

Лишние магнитные таблички fillCircle

fillRect

дальше ►

379


решение упражнения

пражнение решение

Посмотрите, сможете ли вы собрать функцию d r a w B ir d из всех тех кусочков, которые нам предоста­ вила Джуди. Функция d r a w B ir d Принимает ca n va s И c o n te x t И рисует изображение ПТИЦЫ В canvas. Исходите ИЗ ТОГО, ЧТО С ПОМОЩЬЮ данной функции МЫ ДОЛЖНЫ разместить " t w i t t e r B i r d . p n g " вместе с координатами х = 20, у = 12 0, при этом ширина и высота будут равны 70 пикселам. Мы уже на­ писали за вас объявление метода и первую строку. Вот наше решение этого упражнения.

Свой код на п и ­ шите здесь

f u n c t i o n d r a w B ir d ( c a n v a s , c o n t e x t ) v a r t w i t t e r B i r d = new Im a g e ( ) ; tw itte r B ir d s r c

=

Не забудьте доба­ вить вызов d ra w B ird в свою функцию preview Handler!

{

(ft w i t t e r 8 i i r d . p n g n;

tw itte r B ir d .o n lo a d

=

fu n c tio n Q {

c o n te x t.d r a w lw a g e ttw itte r B iir d j 2 0

,

% 20, 7 0 , 7 0 );

1;

U r M L § - K r occ® T A - Г еШение

380

глава 7


раскрываем в себе художника

Пасхальное яйцо В Tw/eetShirt Итак, вы сгенерировали отличны й предварительны й просм отр TweetShirt. А что тенерь? Если вы действительно захотите превра­ тить свой дизайн в изображ ение на футболке, то сможете сделать это! Каким образом? Вот небольш ое дополнение, которое вам нужно внести в код, — насхальное яйцо в TweetShirt. Оно п ревра­ ти т ваш дизайн в изображ ение, нолностью готовое к выгрузке на сайт, нозволяю щ ий нанечатать его на настоящ ей футболке (в И н­ терн ете таких сайтов существует целое множество). Как это сделать? Элементарно! Мы можем воспользоваться мето­ дом toD a ta U R L объекта canvas. Взгляните на пример: Мы создали новую функцию makelmage, чтобы добавить данную возможность.

J

f u n c t i o n m a k e lm a g e ()

{

v a r c a n v a s = d o c u m e n t. g e tE le m e n tB y ld ( " t s h i r t C a n v a s f c a n v a s . o n c lic k

= fu n c t io n

()

Г

Извлекаем объект canvas...

{

w in d o w . lo c a t io n = c a n v a s . to D a ta U R L ( " im a g e /p n g " )

^

f

A

...и добавляем обработчик событийj чтобы щелчок на элементе canvas приводил к гене-

Мы задаем генерируемое изо L nP0C“ M canvaS C°]_ дать изображение в ф ор Р ж а н и ю изображения, бражение в качестве значения мате PNG из пикселов, window .location в случае с брау­ нарисованных в canvas. ^ Следует от мет ит ь, что зером, благодаря чему на ст р а ­ PNQ является единствен­ нице в браузере вы увидите ным ф ормат ом, который именно это изображение. должен поддерживаться Тенерь нросто добавьте вызов make Im age в функцию w in d o w .o n lo a d , браузерами , поэт ому им ен­ и ваш c a n v a s отны не сможет генерировать изображ ения, когда вы но его мы и рекомендуем будете щелкать на нем. П роведите тестирование. И дайте нам знать, вам использовать. >

если создадите футболку с изображением! w in d o w .o n lo a d = f u n c t i o n ()

{

v a r b u t t o n = d o c u m e n t. g e tE le m e n tB y ld ( " p r e v ie w B u t t o n " ) ; b u t t o n . o n c lic k

= p r e v ie w H a n d le r ;

make im age ( ) ;

— _ обеспечьте вызов makelmage для добавле-

ния обработчика событий onclick для cav\vas> и ваше пасхальное яйцо будет готово.

}

Некоторые браузеры не позволят извлекать изображение из canvas, если вы выполняете данный код из file://. Ды не

I

оСШ о^оЖ Ньх!

Выполняйте данный код, используя localhost:// или онлайнсервер, если хотите, чтобы он работал во всех браузерах..

дальше ►

381



8 телевидение для нового поколения ♦

*

Элемент video...

...и наш особый гость—элемент canvas

Нам больше не нужны плагины. Элемент v i d e o отныне является полно­ ценным членом HTML-семейства: просто вставьте его в свою страницу — и вы обеспечите прямую поддержку воспроизведения видео на большинстве устройств. Однако v i d e o — нечто значительно большее, чем просто элемент: это APIинтерфейс JavaScript, позволяющий управлять воспроизведением, создавать пользовательские видеоинтерфейсы и интегрировать видео с остальными HTMLэлементами совершенно новыми способами. Говоря об интеграции... как уже отмечалось ранее, между v i d e o и c a n v a s существует связь, — вы увидите, что объединение этих элементов открывает новые возможности по обработке видео в режиме реального времени. В этой главе мы научимся внедрять элемент v i d e o в веб-страницу, а затем поговорим об использовании соответствующего

API-интерфейса JavaScript. Вы будете поражены тем, что можно сделать с по­ мощью небольшого количества разметки, JavaScript и элементов v i d e o и c a n v a s .


анонс webville tv

Знакомство с Webville TV Webville TV —это содерж имое, которого вы жда­ ли, нанрим ер: «Пункт назначения - планета Зем­ ля» (D estination Earth), «Нападение 50-футовой женщины» (The Attack of the 50’ W om an), «Нечто» (The T hing), «Капля» (The Blob), и не будет лиш ­ ним вклю чить сюда образовательны е фильмы 1950-х годов. Однако это всего лишь содерж и­ мое, а что касается технологий, то ож идаете ли вы здесь чего-то меньш его, чем НТМЬ5-видео? Это, конечно же, лиш ь наше видение нроблемы, и если мы хотим трансф орм ировать его в нечто реальное, то нам но требуется создать Webville TV. Н а нескольких следующих страницах мы бу­ дем заниматься созданием Webville TV «с нуля», иснользуя НТМЬ5-разметку, элемент video и не­ много JavaScript.

Webville T V , на Ю О % созданное с применением технологии HTML5.

Скоро в вашем браузере!

384

глава 8


телевидение для нового поколения

Разберемся с HTML-разм еткой... Э то ведь уже глава 8, ноэтому не будем медлить! Д авайте сразу нристуним к нанисанию HTM L-разметки:

Вполне стандартный HTMLS.

< ! d o c ty p e h tm l> к Г '" "

< h tm l la n g = " e n " > <head> < t it le > W e b v ille

T V < /t it le >

<m eta c h a r s e t = " u t f - 8 "> <1±пк r e l= " s t y le s h e e t" h r e f = " w

He забудьте CSS-файл для обеспечения красиe b v i l l e t v . c s s "> вого внешнего вида.

< /h e a d > <body>

Небольшое изображение, чтобы все было похоже на настоящий телевизор.

< d iv i d = " t v " > < d iv id = " t v C o n s o le " > < d iv i d = " h i g h l i g h t ">

< im g s r c = " im a g e s / h ig h l ig h t . p n g "

a lt= " h ig h lig h t fo r tv " >

< / d iv > < d iv id = " v id e o D iv " > < v id e o c o n t r o ls

a u t o p la y s r c = " v i d e o / p r e r o l l .m p4" w id th = " 4 8 0

p o s t e r = " im a g e s / p r e r o ll p o s t e r . j p g "

h e ig h t = " 3 60"

id = " v id e o " >

< / v id e o > < / d iv > < / d iv > < / d iv >

А вот наш элемент <video>

для воспроизведения видео. Ъолее ' пристально на него мы взгля­ нем через несколько мгновений...

< /b o d y >

Если у вас возникли проблемыj перевер­ ните страницу!

< / h tm l>

Включите э т о т «телеВизор» и протестируйте его... Здесь нужно нозаботиться о некоторы х вещах: вонервых, наберите весь нриведенны й чуть выше код и сохраните его в ф айле w e b v ille tv .h tm l; во-вторых, загрузите на свой комнью тер соответ­ ствующий CSS-файл, скачайте видеоф айлы и номестите их в каталог video. Сделав это, загрузите страницу, но еле чего откиньтесь на снинку стула и смотрите. ^

Все необходимое загрузите, посетив страницу h ttp : // wickedlysmart. com/hfktml5

i Вот что мы видим. Если вы наведете указатель мыши на экран, то по­ явится набор эле­ ментов управления, предназначенных для того, чтобы вос­ производить видео} ставить на паузу , регулировать звук, осуществлять по­ иск в видео. дальше ►

385


форматы видео могут вызывать проблемы

Я не вижу никакого видео. Я трижды проверил код и расположил видео­ файлы в нужном каталоге. Есть идеи?

Да, возможно, дело в формате видео. Н есм отря на то что разработчики браузеров со­ гласны с тем, что элемент <video> и API-интерф ейс Video схожи в HTML5, не все из них сходятся во м нении насчет фактического формата самих видео­ файлов. Н анрим ер, если вы используете браузер Safari, то нредночтительны м для вас будет ф орм ат кодирования Н.264, а если C hrom e —то WebM и т. д.

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

В коде, нанисанием которого мы только что зани­ мались, в качестве ф орм ата кодирования предпо­ лагался Н.264, работаю щ ий в Safari, Mobile Safari, In tern et E xplorer версии 9 и выше. Если вы иснользуете другой браузер, загляните в свой каталог v id eo , где найдете видеоф айлы трех отличаю щ ихся тинов с трем я разны ми расш ирениями: MP4, OGV и WEBM (что они означают, рассмотрим позже). В случае Safari вы уже долж ны использовать MP4 (которы й содерж ит Н.264). П ри иснользовании Google C hrom e следует прим е­ нять ф орм ат WEBM, для чего нужно зам енить зна­ чение атрибута s r c следующим: src = " v id e o /p re ro ll.w e b m " Если же вы иснользуете Firefox или O pera, то заме­ ните значение атрибута s r c на такое: s r c = " v i d e o / p r e r o l l . ogv" А если вы работаете с In te rn e t Explorer версии 8 или ниж е, вам не новезло, —но стойте-ка, это же гла­ ва 8! Как вы до сих нор мож ете пользоваться браузе­ ром In tern et Explorer 8 (или ниже)? О бновите его! Н о если вам необходимо узнать, как обеснечить р е­ зервное содерж имое для пользователей, у которы х установлен In tern et Explorer 8, нотерните, но сколь­ ку мы еще дойдем до этого.

386

глава 8

\

Попробуйте

сделать так для качала, а чуть позже мы вер­ немся к этому.


телевидение для нового поколения

Как работает элемент video? И так, вы все настроили, и у вас на странице воснроизводится видео. Однако нрежде, чем мы двинемся дальше, давайте взглянем на элем ент video, которы й иснользован в наш ей разметке:

Если атрибут, controls присутствует , проигрыва/ — тель предоставит пользователю элементы управления (

для контроля над воспроизведением видео и аудио.

<video controls autoplay

Благодаря атрибуту autoplay воспроизведение видео запускаться по завершении загрузки страницы. ----- -

src=,,video/preroll .mp4" width="480" height="360"

,

Исходное местоположение видео

—. Ширина и высота видео

на странице

poster=" images/prerollposter .jpg" id— video > </video>

_ Картинка , которая отображается,

когда видео не воспроизводится.

^

Идентификатор для эле­ мента video> чтобы мы могли обращаться к нему позже из JavaScript.

Еще один полезный совет из HTML5 руководства города Вебвилль.

Правила видеоэтикета: свойство autoplay Несмотря на то что a u t o p l a y может оказаться луч­ шим выбором в случае с такими сайтами, как YouTube и Vimeo (или даже Webville TV), дважды подумайте, прежде чем задавать его в своем теге < v i d e o > . Пользователь зачастую желает сам решать, должно ли воспроизводиться видео при загрузке вашей страницы.

дальше ►

387


обзор атрибутов элемента video

Пристальный взгляд на атрибуты элемента video... Давайте внимательнее взглянем на наиболее важные атрибуты элемента video: яге controls

А трибут controls является логи ческим. Либо он есть, либо его нет. Если он присутствует, то

А трибут s r c подобен s r c элемента <im g> — это U R L -адрес, ко то р ы й сообщает элементу video, где искать ф айл-источник. В данном случае таким файлом является v i d e o / p r e r o ll. m p 4 (если вы загрузили на свой компью тер код, используемый в этой главе, то сможете найти данны й видеофайл, а также два других в каталоге v id e o ).

L

браузер добавит свои встроен^ „ы е элементы управления в об­ ласть отображения видео. Здесь возможны вариации в зависиI мости от браузера, поэтому проверяйте, ка к они будут выглядеть

src определяет, какой видео­ файл будет здесь воспроиз­ водиться.

pielo

высота

в каждом браузере. Вот ка к они выглядят в Safari.

ширина

ащо

t Л о ги ч е ски й атрибут a u t o p la y дает браузеру команду начинать воспроиз­ ведение видео, как только у него будет достаточно данных. В случае с нашими демонстрационны ми видеофайлами вы, вероятно,увидите, что их воспроизведе ние запускается п о чти сразу. poster

ватель

1+1 1

Браузер обычно отображает один кадр видео в качестве постерного изображения для представления этого видео. Если вы уда­ лите атрибут a u to p la y , то будете наблю­ дать данное изображение, пока не нажмете кн о п ку воспроизведения. Браузер сам решает, какой кадр показывать; зачастую он просто показывает первы й кадр видео... ко торы й нередко оказывается полностью черным. Если вы хотите, чтобы в данном случае выводилось определенное изобра­ жение, вам потребуется создать его, а затем задать, используя атрибут p o s te r .

loop, ко то р ы й представляет собой еще один л огический атрибут, обеспечивает автомати­ ческий повтор воспроизведения видео после того, как его проигры вание завершается.

388

Ви де оп р ои гр ы -

глава 8

1

Л о ги ч е с ки й атрибут p r e lo a d обычно используется для тщательного контроля над загрузкой видео в целях оптимиза­ ции. Браузер, по большей части, решает, какой объем видео загружать, исходя, например, из того, был ли задан атри­ бут a u to p la y , а также ориентируясь на пропускную способность канала поль­ зователя. Вы можете изменить данное поведение, присвоив p r e lo a d значение попе (видео не будет загружаться до тех пор, пока пользователь не нажмет кн о п ­ ку воспроизведения), либо m e ta d a ta (метаданные видео будут загружаться, но без видеосодержимого), либо a u to , которое позволит браузеру самостоя­ тельно приним ать решение.

widlh, height А трибуты w id t h и h e ig h t определяют ш ирину и высоту области отображения видео (также известной как область просмотра). Если вы зададите значение для p o s t e r , то постерное изображение будет подвергаться масштабированию в соответствии с указанными вами ш и р ино й и высотой. Видео также будет масштабироваться, но сохранит соотно­ шение ш ирины и высоты (например, 4:3 или 16:9), поэтому при наличии дополнительного пространства по бокам либо сверху и снизу видео станет выводиться в ТВ-формате L etter Box либо P illa r Box с целью п одгонки под размеры области отображения видео. Вы должны стараться обеспечивать со­ ответствие родным размерам видео, если требуется наилуч­ шая производительность (браузеру не придется заниматься масштабированием в режиме реального времени).

Т В -ф ор м ат P illar Box

> ■

773-ф орм ат L e tte r Box

— в


телевидение для нового поколения

Элементы управле­ ния в каждом браузере выглядят по-разному; хотя при использова­ нии решений вроде Flash в их внеш­ нем виде, по крайней мере, наблюда­ лась согласованность.

Да, элементы управления отображением HTML-видео в каждом из браузеров вы­ глядят по-разному. В неш ний вид ваших элементов унравления определяю т те, кто реализует браузеры. Эле­ менты управления зачастую выглядят неоди­ наково в разны х браузерах и онерационны х системах. В н екоторы х случаях, н ан ри м ер на план ш етн ом ком пью тере, они долж ны выглядеть и вести себя по-другому, носкольку само устройство работает иначе (и хорош о, что об этом за вас уже позаботились). Вместе с тем мы понимаем, что в случае, скажем, на­ стольных браузеров было бы ненлохо иметь согласованно выглядящие элементы унравле­ ния, однако все это не является формальной частью специф икации HTML5. В некоторы х ситуациях нодход, работаю щ ий в одной онер а ц и о н н о й систем е, м ож ет расходи ться с основны м и н ри н ц ин ам и и н те р ф ей са поль­ зователя другой ОС. П росто знайте, что эле­ менты унравления могут различаться, а если вами будет двигать глубокая м отивация, то м ож ете реали зовать пользовательские эле­ м енты унравлен ия для своих нрилож ени й . Этим мы займемся позже...

дальше ►

389


обзор форматов видео

Что необходимо знать о форматах видео Н ам бы хотелось, чтобы все было четко и ясно, как в случае с элементом v id eo и его атрибутами, но, как оказалось, с форматами видео в И н терн ете небольш ой беснорядок. Что же такое ф орм ат видео? М ожно рассма­ тривать его следующим образом: видеоф айл содерж ит две части —видео и аудио, н ри этом каждая из них закодирована (чтобы умень­ ш ить разм ер и обеснечить возмож ность бо­ лее эф ф ективного воснроизведения файла) с иснользованием онределенного кодека. Кодек в больш инстве случаев м ож ет оказы­ ваться тем, с чем будут согласны далеко не все, — одни разработчики браузеров отдают нредночтение кодеку Н.264, вторы м очень нравится VP8, а третьи лю бят альтернатив­ ные реш ения с откры ты м исходным кодом, нанрим ер T heora. Все это еще больше услож­ няется тем, что файл, содерж ащ ий закоди­ рованны е с номощью онределенного кодека видео- и аудиоданные (он назы вается кон­ тейнером) , им еет собственны е ф орм ат и имя. Таким образом, у нас нолучается настоящ ая меш анина из технических терм инов. У нас мог бы быть больш ой и счастливый мир, если бы все разработчики браузеров до­ ф говорились между собой о едином ф орм ате для иснользования в И н терн ете, но, нохоже, этого не случится, и на то есть ряд техниче­ ских, политических и ф илософ ских нричин. Однако вместо того чтобы откры вать здесь дискуссию, мы нросто ностараемся дать вам достаточны й объем знаний но этой теме, чтобы вы смогли нриним ать собственные реш ения о том, как обеснечить ноддержку для своей целевой аудитории. Д авайте взглянем на наиболее нопулярны е кодеки. В настоящ ее врем я существуют три сонерника, нытаю щ ихся нравить м иром (И нтернета)...

390

глава 8

Три разных формата видео, используемых в основных браузерах. Э то

контейнер..

{ Контейнер WebM Видео, закодированное кодеком VP8

^

...содер­ жащий закоди­ рованные видеои аудиоданные.

Аудио, закодированное кодеком Vorbis

Видео, закодированное кодеком Н.264

AAC Audio Encoding

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

Контейнер Ogg Видео, закодированное кодеком Theora

Аудио, закодированное кодеком Vorbis

t

Каждый формат вклю ­ чает тип контейнера (например j VJebM, МР4-, Ogg) и используемых ви­ део- и аудиокодеков (на­ прим ер , VP8 , Vorbis).

СпецификацияHTML5допускает прпмепеппелюбогоформатавпдео. Всезавпсптотреализациибраузера, котораяиопределяет, какиеформа­ тыдействительноподдерживаются.


телевидение для нового поколения

Претенденты Если вы собираетесь ноставлять содерж имое для ш ирокого круга пользователей, то вам нридется предусмотреть наличие видеоф айлов более чем одного формата. С другой стороны , если вы нацеливаетесь, нанрим ер, только на пользователей A pple iPad, возможно, вам удастся обой­ тись лиш ь одним ф орм атом видео. В настоящ ее врем я существуют три основны х нретендента.

Контейнер M P4 с Видео Н . 2 6 4 и аудио ААС

Контейнер 1Л/еЬМ с Видео VP8 и аудио Vorbis

Н .2 6 4 л и ц е н з и р о в а н г р у п п о й M P E G -L A .

W e b M б ы л с о з д а н к о м п а н и е й G o o g le

С у щ е с т в у е т б о л е е о д н о г о т и п а Н .2 6 4 ,

дл я и спо л ь зо в ан и я в со четан ии с вид ео,

ка ж д ы й из ко то р ы х и зв ес те н как

закодированны м с пом ощ ью V P8.

проф иль.

W e b M /V P 8 п о д д е р ж и в а е т с я б р а у з е р а м и F ir e fo x , C h r o m e и O p e r a .

М Р 4 /Н .2 6 4 п о д д е р ж и в а е т с я б р а у з е р о м S a f a r i и In te r n e t E x p lo r e r в е р с и и 9 и в ы ш е

В и д ео ф ай л ы в ко нтей н ер н ом ф о р м ате

Т а кж е и м е етс я п о д д е р ж ка со с то р о н ы

W ebM им ею т р асш и рени е W E B M .

н е к о то р ы х в е р с и й б р а у з е р а C h ro m e .

Контейнер Ogg с Видео Theora и аудио Vorbis T h e o ra — это ко д е к с о ткр ы ты м

Я64

ИСХОДНЫМ КОДОМ.

н

В и д е о , з а к о д и р о в а н н о е с его п о м о щ ь ю ,

индустрии, но не правящий чемпион ...

о б ы ч н о с о д е р ж и т с я в O g g -ф а й л е ,

_

^Ь им ец

Theora. А л ьт ер­ нативное решение с от крыт ым исход­ ным кодом.

ко то ры й и м е ет р асш и р е н и е O G V. O g g /T h e o r a п о д д е р ж и в а е т с я б р а у з е р а м и F ir e fo x , C h r o m e и O p e r a .

г VPS — претендент , за спиной которого стоит Google, при эт ом поддерживается браузерами других разра­ ботчиков и набирает силу...

дальше ►

391


управление форматами видео

Как Жонглировать всеми этими форматами... Итак, в мире ф орматов видео присутствует н екоторы й беснорядок, но что нам делать? В зависимости от ваш ей целевой аудитории вы мож ете реш ить обеснечить наличие видео только в одном ф орм ате либо в нескольких. В любом случае вы сможете иснользовать один элемент < s o u rc e > (не путать с атри­ бутом src) на каждый ф орм ат внутри элем ента < v id e o > , чтобы обеснечить набор видеоф айлов, каждый из которы х будет иметь свой собственны й формат, и дать возмож ность браузеру вы бирать видеоф айл именно в том форм ате, которы й он ноддерживает. Н анример: Обратите внимание, что мы удаляем ат рибут src из тега <video> ...

I

■■■и добавляем мри тега <source>, каж­ дый из которых имеет собственный атрибут src, указывающий путь к ви­ деофайлу в отличающемся формате.

< v id e o s r c = " v i d e o / p r e r o l l .m p4" id = " v id e o " p o s te r = " v id e o / p r e r o llp o s t e r . jp g "

c o n t r o ls

w id t h = " 4 8 0 " h e i g h t = " 3 6 0 "> < s o u rc e s r c = " v id e o / p r e r o l l. m p 4 " > < s o u rc e s r c = " v id e o / p r e r o ll. w e b m " > < s o u rc e s r c = " v i d e o / p r e r o l l . o g v "> < p > S o rry ,

y o u r b ro w s e r d o e s n 't s u p p o r t th e v id e o

< / v id e o >

e le m e n t< /p >

горюхи и двигается

г x браузер натИ^ Ы[Л, Ст файл в форма Сообщение, которое выведет вниз, пока не о воспроизвести. браузерл если он не поддер­ \ живает элемент video. 3 случае с каждым <source> браузер загружа­ ет метаданные видеофайла, чтобы проверить, сможет ли он его воспроизвести (этот процесс бывает длительным, однако его можно облегчить йраУзеРа " слЛ' бедующ ую страницу)

КЛЮЧЕВЫЕ МОМЕНТЫ Контейнер

^ЛЯ

Я — это формат файлов, используемый для «упаковки» видео-, аудио- и ме­

таданных. Среди распространенных контейнерных форматов можно назвать MP4, WebM, Ogg и Flash Video.

Кодек —

это программный инструмент, используемый для кодирования и декодирования

видео и аудио в определенном формате. К числу популярных веб-кодеков относятся Н.264, VP8, Theora, ААС и Vorbis. Браузер сам решает, какое видео он сможет декодировать. При этом среди разработчиков браузеров нет согласия относительно единого формата видео, поэтому если вы хотите обеспечить поддержку для каждого пользователя, вам придется позаботиться о наличии видеофайлов в нескольких форматах.

392

глава 8

Л г


телевидение для нового поколения

Как обеспечить еще большую конкретизацию для своих форматов видео Сообщив браузеру местонолож ение своих ф айлов-источников, вы даете ему набор различны х вариан­ тов, из которы х он сможет вы брать нодходящ ий. Однако веб-обозревателю нридется нровести кое-какое «расследование», нреж де чем у него нолучится точно онределить, сможет ли он воснроизвести со­ ответствую щ ий файл. Вы мож ете номочь своему браузеру, сообщив ему дополнительную инф орм ацию о тине MIME и (онционально) о кодеках ваших видеофайлов:

файлj путь к которому вы указываете в src, на самом деле является контейнером , содержащим фактическое видео (и аудио, а также метаданные). ^

Параметр codecs определяет, какие кодеки были использовлны для кодирования видео Видеокодек и аудио с целью создания за л кодированного видеофайла / Аудиокодек *

< s o u rc e s r c = " v i d e o / p r e r o l l . o g v " t y p e = ' v id e o / o g g ;

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

I

codecs= :" t h e o r a ,

v o r b is " '>

J Это тип MIME видео- Обратите внимание на двойные файла Он определяет кавычки вокруг значения параметра контейнерный формат, codecs. Они подразумевают , что значение атрибута type нам следует заключить в одинарные кавычки.

Мы можем обновить наш и элементы <source> с целью вклю чения в них и нф орм ации о тине для каждого из трех тинов видеоф айлов, которы е у нас имею тся, как но казано далее: < v id e o i d = " v id e o " p o s t e r = " v i d e o / p r e r o l l p o s t e r . jp g "

c o n t r o ls w id t h = " 4 8 0 " h e i g h t = " 3 6 0 ">

< s o u rc e s r c = " v i d e o / p r e r o l l .m p4" t y p e = ' v id e o /m p 4 ; c o d e c s = " a v c l. 42E01E, m p 4 a . 4 0 .2 " '> < s o u rc e s r c = " v id e o / p r e r o ll. w e b m " t y p e = ' v id e o /w e b m ; < s o u rc e s r c = " v i d e o / p r e r o l l . o g v " t y p e = ' v id e o / o g g ; < p > S o rry , < / v id e o >

c o d e c s = "v p 8 ,

c o d e c s = " th e o r a ,

v o r b i s " '> v o r b is " '>

y o u r b ro w s e r d o e s n 't s u p p o r t th e v id e o e le m e n t< /p >

f

Если вы не будете знать значений параметров codecs, можете о т ­ бросить их и указать только тип MIME. Это обеспечит чуть меньшую эффективность , однако, по большей частиj все будет в порядке.

Значения параметра codecs в случае с MP4 будут более замысловатыми, чем в случае с двумя осталь­ ными контейнерными форматами , поскольку ко­ дек Н.Я64 поддерживает разнообразные профили с настройками кодирования видеофайлов для разных пользователей (например , у одних из них может иметься канал с высокой пропускной способностью, а у других - с низкой). Таким образом , чтобы задать здесь правильные значения, вам необходимо знать подробности о том, как видео было закодировано.

Когда вы будете разбираться с кодированием видеоф айлов, вам нридется узнать подроб­ ности о разнообразны х вариантах нарам етров ty p e для иснользования в вашем элементе < s o u rc e > . Д ополнительную инф орм ацию о данны х нарам етрах вы сможете найти но адресу h t t p : / / w ik i. w h a t w g . o r g / w i k i/ V i d e o _ t y p e _ p a r a m e t e r s .

дальше ►

393


вопросы о кодировании и воспроизведении видео

Ч а с т° Задаваем ы е B o llp o C b l видео для последующего размещения в Интернете. Если f t * ™ . — жайшие несколько лет мы придем к единому контей­ нерному формату или типу кодека? Разве на это не указывает наличие у нас стандартов?

вы собираетесь заняться серьезной обработкой видео, используйте программы Final Cut Pro или Adobe Premiere, в которых имеются встроенные производственные инстру­ менты. Наконец, если вы хотите осуществлять доставку свого видео посредством сети Content Delivery Network

Q j Вряд ли в ближайшее время появится формат, кото­

(CDN), то знайте, что многие CDN-компании также предла­

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

широкий выбор разнообразных вариантов.

ровать свою судьбу в сфере видео, и заканчивая комплекс­ ными проблемами с интеллектуальной собственностью. Комитет по стандартам HTML5 осознал это и решил не

экранном режиме? Удивительно, что в соответствую­

определять формат видео в спецификации HTML5. Таким образом, несмотря на то что HTML5, в принципе, поддер­ живает (или, по крайней мере, агностически воспринимает) все эти форматы, в действительности разработчикам брау­ зеров решать, что они будут, а что не будут поддерживать.

гают услуги по кодированию. Таким образом, у вас имеется

Могу ли я воспроизводить свое видео в полно­ щем API-интерфейсе нет свойства для этого. Q j Данная функциональность еще не была стандарти­ зирована, однако в Интернете можно найти способы вос­ производить полноэкранное видео с помощью некоторых браузеров. Часть браузеров предусматривают наличие

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

элемента управления для проигрывания видео во весь экран (например, на планшетных компьютерах), который

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

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

ветствующую поддержку.

оказаться ограниченным по соображениям безопасности

наделяет данной возможностью элемент v id e o . Однако в полноэкранном режиме, список того, что с ним можно

(как это бывает с видеоплагинами). С чего мне начать, если я захочу заняться коди­ рованием собственного видео?

А как насчет звука в моем видео? Можно ли ис­ пользовать API-интерфейс для управления уровнем

Q j Существует масса программ для захвата и кодиро­ вания видео. А уж какую из них вам выбрать, зависит от типа видео, захват которого вы хотите производить, и того, как вы собираетесь использовать конечный результат. На тему кодирования видео написаны книги, так что будьте готовы войти в мир новых акронимов и технологий. Вы можете начать с несложных программ вроде iMovie или Adobe Premiere Elements, которые позволяют кодировать

394

глава 8

громкости? Q j Конечно можно. Вы можете присваивать свойству

v o lu m e значение с плавающей точкой в промежутке от 0 . О (звук отключен) до 1 . О (максимальная гром­ кость звука). Просто используйте объект v i d e o для задания значения для этого свойства в любое время:

v id e o .v o lu m e = 0 . 9 ;


телевМ е н и ед л я н о ап ° п°коления

* 4

ВАША СЛЕДУЮЩАЯ МИССИ Я: РАЗВЕДКА ПОДДЕРЖКИ ВИДЕО

.

Щь c o b e p iu e h u o

С ЕК РЕТН О

ПОРУЧАЕТСЯ ОПРЕДЕЛИТЬ Т Е К У Щ И М У Р О В Е Н Ь ПОДДЕРЖКИ ВИДЕО В КАЖДОМ ИЗ ПРИВЕДЕННЫХ НИЖЕ Б Р А У З Е Р О В (ПРИМЕЧАНИЕ: НУЖНУЮ ИНФОРМАЦИЮ ВЫ СМОЖЕТЕ О Т Я С К А Т Ь ПО АДРЕСАМ HTTP: //E N .W IK IP E D IA .O R G /W IK I/H T M L 5 _ V ID E O , HTTP://CANIUSE.COM/#SEARCH=VIDEO) ПРИНИМАЙТЕ ВО ВНИМАНИЕ НОВЕЙШИЕ В Е Р С И И БРАУЗЕРОВ. ПО КАЖДОМУ Б Р А У З Е Р У , ПРИВЕДЕННОМУ В С Т О Л Б Ц Е «ВИДЕО/БРАУЗЕР», ОТМЕТЬТЕ ВИДЕОПАРАМЕТРЫ, К О Т О Р Я Е ОН ПОДДЕРЖИВАЕТ. ПО ВОЗВРАЩЕНИИ ПРЕДСТАВЬТЕ ОТЧЕТ ДЛЯ П О Л У Ч Е Н И Я Н О В О Г О ЗАДАНИ Я! ВАМ

Устройства под управлением операционных систем iOS и Android (среди прочих) Ч'

дальше ►


Нет проблем. Существует ряд методик для п ереклю чения на другой проигры ватель видео, если тот, которы й вы нредночитаете (будь то проигры ватель видео HTML5, или Flash, или другой), не поддерж ивается. Н иж е вы найдете прим ер того, как можно вставить свое Flash-видео в качестве резервного содерж имо­ го, заменяю щего НТМЬБ-видео в ситуациях, когда браузер не знает, как воспроизвести НТМЬб-видео. Ясно, что данная область быстро меняется, ноэтому заглядывайте в И н терн ет (в котором разм ещ ается более свежая инф орм ация, чем нриводим ая в кни­ гах), чтобы использовать новейш ие и наилучшие методики. Вы также сможете найти снособы сделать резервны м не Flash-видео, а НТМЬБ-видео, если п редпочтете отдавать п ри ори тет Flash-видео. < v id e o p o s t e r = " v id e o . j p g "

c o n t r o ls >

< s o u rc e s r c = " v id e o .m p 4 " > < s o u rc e s r c = " v id e o .w e b m " > < s o u rc e s r c = " v id e o . o g v "> < o b je c t > . . .< /o b je c t> < / v id e o >

Вставьте свой элемент <object> в элемент <video>. Если браузер не узнает элемент <video>, то буде использоваться элемент <object>.


телевидение для нового поколения

Я слышал, там будут A PI-интерфейсы? Как вы видите, иснользуя разметку и элемент < v id e o > , можно много чего сделать. Однако эле­ мент < v id e o > также нредоставляет нам богаты й

API-интерфейс, которы й можно иснользовать для реализации всевозмож ны х интересны х новедений и взаимодействий, связанны х с видео. Вот краткая сводка некоторы х методов, свойств и собы тий эле­ м ента < v id e o > , которы е могут вас заинтересовать (их исчерпы ваю щ ий неречень вы найдете в специ­ ф икации):

Вызывайте эти методы play

воспроизводит ваше видео

pause

ставит ваше видео на паузу загружает ваше видео

load

используйте эти свойства

г

videoWidth

loop

videoHeight

muted

currentTime

paused

duration

readyState

ended

seeking

error

volume

Это свойства объекта эле­ мента <video>. Одним из них вьч можете присваивать зна­ чения (например, loop и muted), другие же предназначены только для чтения (например, currentTime и error). Это события, которые вы сможете обрабатывать, если захотите, до­ бавив обработчики событий, вызов которых будет происходить при наступлении события, прослушива­ ние которого вы ведете.

canPlayType помогает программно определить , какие типы видео вы сможете вос­ произвести

¥

&

^П ер ехв аты вай те эти события play

abort

pause

waiting

progress

loadeddata

error

loadedmetadata

timeupdate

volumechange

ended дальше ►

397


как работает плейлист

Немного «программирования» содержимого Webville TV До настоящ его момента у нас но Webville TV демонстрировалось только одно видео. Нам бы хотелось запрограм м ировать раснисание, но кото­ рому будет воспроизводиться нлейлист видеоф айлов. Донустим, в случае с Webville TV нам требуется сделать следующее:

Показать аудитории небольшое предварительное шоу, ну там, знаете, рекламу «кока-колы» и попкорна, правила поведения для зрителей и т. д. 7 /и h i m l’ cf Ouulilij

£%

Пункт нашчения планета Земля

Показать наш первый ролик под названием «Популярны ли вы?» (Are you Popular?). Поверьте, он вам понравится.

А затем показать гвоздь нашей программы — полно­ цветный фильм «Пункт назначения — планета Зем­ ля» (Destination Earth). Созданный Американским институтом нефти, какой же посыл он в себе несет? Посмотрите — и узнаете.

Возьми в руку карандаш У вас может возникнуть соблазн взглянуть на спецификации разметки < v id e o > ; чтобы узнать, как определить плейлист. Что ж, для этого вам потребуется код, поскольку элемент < v id e o > позволяет определять только одно видео. Если бы вы находились на необитаемом острове и вам требовалось реализовать плейлист исключительно с использованием браузера, элемента < v id e o > , свойства s r c , методов lo a d и p la y , а также свойства ended, то как бы вы сделали это (у вас есть возможность использовать любые типы данных JavaScript, какие пожелаете)?

Подсказка: событие ended наступает, когда видео достигает конца и его воспроизведе­ ние завершается. К а к и в случае с любым другим событием, у вас может иметься обработчик, вызов которого будет происхо дить при наступлении данного события.

398

глава 8

подсматривайте решение этого у п р а ж нения!


телевидение для нового поколения

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

У вас может возникнуть соблазн взглянуть на спецификации разметки

< v id e o > , чтобы узнать, как определить плейлист. Что ж, для этого вам потре­ буется код, поскольку элемент < v id e o > позволяет определять только одно видео. Если бы вы находились на необитаемом острове и вам требовалось реализовать плейлист исключительное использованием браузера, элемента < v id e o > , свойства src, методов lo a d и p la y , а также свойства ended, то как бы вы сделали это (у вас есть возможность использовать любые типы данных JavaScript, какие пожелаете)? Вот наше решение этого задания:

Mbi сохраним плейлист в виде массива. Каждый элемент в нем будет представлять собой видео для воспроизведения.

Псевдокод плейлиста Создать массив playlist с видео Извлечь v id e o из объектной модели документа (DOM).

<iS' £ <Ь

Задать обработчик событий в отношении v id e o ДЛЯ обработки События " e n d e d " .

£

*

Создать переменную p o s i t i o n =

/Qj

о.

&

ft

&

Задать в качестве источника видео ПОЗИЦИЮ О В p l a y l i s t .

Массив playlist

Воспроизвести видео.

Собы тие

ended

Каждый раз, когда воспроиз­ ведение видео завершается, наступает событие ended...

...что приводит к вызову обработчи­ ка событий ended.

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

Псевдокод обработчика со бы ти й ended Увеличить значение p o s i t i o n на 1. Задать в качестве источника видео следующую ПОЗИЦИЮ В p l a y l i s t Воспроизвести следующее видео

до конца плей­ листа, мы можем либо остановиться, либо снова вернуться к первому видео.

Дойдя

дальше ►

399


реализация плейлиста

Реализация плейлиста Webville TV Тенерь мы воспользуемся JavaScript и API-интерф ейсом Video для реализа­ ции плейлиста Webville TV. Н ачнем с добавления ссылки на JavaScript-файл в w e b v i l l e t v . h t m l ; нросто добавьте данную строку в элемент <head>: < s c r ip t

s r c = " w e b v ille tv . js " > < /s c r ip t >

И удалите эту строку из имею щ егося у вас элем ента <video>: < v id e o c o n t r o ls

a u t o p l a y s r c = ffv i d e o / p r e r o l l .m p411 w id th = " 4 8 0" h e ig h t = " 3 60"

p o s t e r = " im a g e s /p r e r o llp o s te r . jp g " < / v id e o >

id = " v id e o " >

’S

^

Удаляем атрибуты autoplay и src из тега <video>.

Также удалите все элементы <source>, с кото­ рыми вы, возможно, экспериментировали. А тенерь создайте новы й файл с именем webvilletv. js. К роме того, давайте онределим ряд глобальных нерем енны х и функцию, которая будет вы зы ваться носле нолн ой загрузки страницы:

^ v a r p o s itio n

= 0;

-------- Еще нам потребуется переменная для размещения массива

va r p la y lis t; var

Сначала определим переменную, чтобы следить за тем, какое видео мы воспроизводимj мыприсвоим ейимя position.

., v id e o ;

playlist с видео. г ^ ^

' А также переменная для размещения ссылки на элемент video.

w in d o w .o n lo a d = f u n c t i o n ()

{

М ы создадим массив playlist с тремя видео.

p l a y l i s t = [ " v i d e o / p r e r o l l .m p 4 ", " v id e o / a r e y o u p o p u la r .m p 4 ", " v id e o /d e s tin a tio n e a r th .m p 4 " ] ; v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v id e o " )

v i d e o . a d d E v e n t L is t e n e r ( " e n d e d " , n e x tV id e o ,

Извлекаем элемент video. fa ls e ) ;

И добавляем обработчик событии ended для video. Да, это выглядит иначе, чем мы привыкли (потерпите немного — мы поговорим об этом на следующей странице). v id e o .s r c = p l a y l i s t [ p o s i t i o n ] ; v id e o , lo a d ()

,

v i d e o . p l a y () ;

з а г р у Ж а е м

э т о

чего воспроизводим его!

} 400

И

Теперь мы задаем для scr значение g виде первого видео.

глава 8


телевидение для нового поколения

Так что там с кодом того обработчика событий? Раньш е мы всегда нросто нрнсванвали функцию обработчика, вызываемую н ри наступлении соответ­ ствующего собы тия, свойству (нанрим ер, o n lo a d или o n c l ic k ) , как ноказано далее: video.onended = nextVideo; Однако на этот раз мы собираем ся ностунить немного но-другому. Почему? А нотому, что на момент нанисания книги ноддерж ка всевозмож ны х свойств собы тий в объекте v id e o была немного неравно­ мерной. Э тот недостаток даст нам возможность п родем онстрировать еще один снособ регистрации, касаю щ ийся событий: a d d E v e n tL is te n e r , которы й является общим методом, ноддерж иваемы м многи­ ми объектами для реги страци и в случае с различны м и событиями. Вот как он работает: о

^

,

Вы можете использовать метод addEventListener для добавления обработчика событий.

(Ьинкиия которую мы будем вызывать при wy ч > rv а * события наступлении соотве у Щ ■I'

^

video.addEventListener ("ended11, nextVideo, false) ;

Объект, на котором м« прослцшиваем определенное тбьнллие сооытие

Событие, прослушивание которого ведем. Обратите внимание на то. что мы не ставам on перед именем х а Г Г события, как в случае с обработчика. ■> ми, при задании которых использцем о ~ п , I ,\ свойства (например, onload).

контролирует проХинцтяе методы п о у е н и * событии, если задано значение true. Всегда зада„ „ с , , байте здесь значение false (если только л ~ вы не пишете продвинутый код), Г

Помимо того факта, что нрим енение метода a d d E v e n tL is te n e r является немного более замысловатым, чем н ростое добавление обработчика нутем присваивания функции свойству, он работает во многом так же. Итак, вернем ся к нашему коду!

Как написать обработчик «конца видео» *

1

*

^

Н ам осталось лиш ь нанисать обработчик для собы тия ended, наступающего нри заверш ении военроизведения видео. Вызов данного обработчика будет нроисходить каждый раз, когда видеонроигры ватель будет достигать конца текущего видеоф айла. Вот как мы наниш ем функцию n e x tV id e o (добавьте ее в файл w e b v i l l e t v . j s ): f u n c t i o n n e x tV id e o ()

{

J

Г Сначала увеличиваем позицию в массиве playlist.

p o s itio n + + ; if

( p o s itio n p o s itio n

} v id e o .s r e

>= p l a y l i s t . le n g t h ) Q ,

По достижении конца плейлиста мы про возвращаемся в его начало, для чего задаем для position значение О.

= p la y lis t [p o s itio n ]}

v id e o , lo a d () ; v i d e o . p l a y () ;

{

Данный обработчик не будет вызывать ся, если пользова тель поставит видео на паузу либо если видео воспроизводится в зациклен ном режиме (что можно обеспечить, ъадав соответ­ ствующее значение свойства loop).

^ — Теперь

а л ы задаелл в качесп/\ве источника следующее видео, которое будет воспроизводить проигрыватель.

Наконец, загружаем и запускаем воспроизведение следующего видео. дальше ►

401


тестирование плейлиста

Еще один тест-драйВ ... Вы мож ете новерить, что мы готовы к тест-драйву? Все, что мы сделали, — это воспользовались соответ­ ствующим API-интерфейсом , чтобы обеснечить ви­ део для воснроизведения, носле чего нозаботились о наличии слушателя собы тий, готового к обработке ситуации, возникаю щ ей но заверш ении нроигры ван и я видео (что он и делает нутем зануска воснроиз­ ведения следующего видео в нлейлисте). Убедитесь, что вы внесли необходимы е изм енения в свой HTM Lфайл, нанечатайте новы й JavaScript-код и нроведите тест-драйв.

Все работает! Но как мы решим, какой формат видео воспроизводить, когда будем исполь­ зовать код для загрузки источника видео?

Хороший вопрос. Когда мы использовали множ ественны е теги < s o u rc e > , мы мог­ ли рассчиты вать, что браузер пройдется но одному или более форматам видео и решит, сможет ли он воснроизвести какойлибо из них. Теперь при использовании кода мы нросто даем элементу v id e o единственны й вариант выбора. Так как же нам проверить и узнать, какие ф орм аты видео ноддерж ивает брау­ зер, чтобы убедиться в том, что мы обеснечили наиболее нодходящ ий из них? Для этого мы можем воспользоваться методом c a n P la y T y p e объ­ екта v id e o . Он приним ает ф орм ат видео и возвращ ает строку, которая дает понять, насколько браузер уверен в том, что он смо­ ж ет воспроизвести данны й тип видео. Существуют три стенени уверенности: вероятно, может быть, уверенности нет. Д авайте бо­ лее пристально взглянем на canPlayType, а затем доработаем код нашего плейлиста, чтобы задействовать в нем данны й метод.

ТВы почесываете затылок , произнося:

«Вероятно? Может быть? почему этот метод не возвращает true или false»? С нами было то же самое! Через несколько мгновений вы узнаете , что под всем эт им понимается...

А

402

глава 8


телевидение для нового поколения

Как работает метод canPlayType О бъект v id e o предусматривает наличие метода c a n P la y T y p e , которы й мож ет онределять, насколько вы­ сока вероятность того, что вам удастся воспроизвести тот или и н ой ф орм ат видео. М етод c a n P la y T y p e нриним ает то же самое онисание ф ормата, которое вы иснользовали в случае с тегом < s o u rc e > , и воз­ вращ ает одно из трех значений: нустую строку, "maybe" или "p ro b a b ly " . Вот как осущ ествляется вызов c a n P la y T y p e :

Будет возвращена пустая строка, если браузер поймет, что не сможет воспроизве­ сти видео.

^ ' п е р е д а д и м только краткое описание Если в качестве результата с м о ж е м формата, то получить лишь " ” или " maybe".

video.canPlayType ("video/ogg")

video.canPlayType('video/ogg; codecs="theora

,

vorbis"')

t Однако если мы передадим определенный тип с кодеком , то сможем получить в ответ "maybe" либо " probably ".

Будет возвращена строка "maybe", если браузер по­ считает, что ему, возможно, удастся воспроизвести видео. Будет возвращена строка "probably", если браузер будет уверен в том, что сможет воспроизвести видео.

О братите внимание, что браузер будет уверен больше, чем "m a y b e ", только в том случае, если вы наряду с тином MIME укажите значение нарам етра co d e c s . Также обращ аем ваше внимание на то, что возвращ аемого зн ачен ия " I 'm a b s o l u t e ly s u re " не существует. Даже если браузер знает, что сможет воспроизвести тип видео, но-нрежнему не будет никаких гарантий, что он сможет воспроизвести фактическое видео: нанрим ер, битрейт видео мож ет оказаться слишком высоким и браузеру не удастся декодировать его. ^

использование canPlayType

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

Мы собираем ся иснользовать c a n P la y T y p e для онределения того, какой ф орм ат видео будет прим е­ няться в случае с видео Webville TV. Вы уже знаете, что у нас имею тся три версии каждого файла: MP4, WebM и O g g , и в зависимости от иснользуемого вами браузера одни из них будут работать, а другие нет. Создадим новую функцию, которая будет возвращ ать расш ирение ф айла (" .m p 4 ", " .webm" или " . o g v " ), нодходящ ее для вашего браузера. Мы станем указывать только тины MIME (" v id e o /m p 4 " , " v id e o / webm" и " v id e o / o g g " ) без зн ачен ий c o d e c s , ноэтому возможны ми возвращ аемы ми зн ачен ия у нас будут "m aybe" или нустая строка: M ы знаем , что сможем получить на­

зад только значение "maybe" либо пустую строку, поэтому сможем удостовериться f u n c t i o n g e tF o r m a tE x te n s io n () { лишь в т о м j что в случае с нашим соот­ i f ( v i d e o . c a n P la y T y p e ( " v id e o / m p 4 " ) != ) { ветствующим типом не окажется воз­ r e t u r n " .m p 4 " ; вращена пустая строка. } e ls e i f ( v id e o . c a n P la y T y p e ( "v id e o /w e b m " : " " ) { \^М ы будем проверять каждый — из типов и возвращать со­ r e t u r n " .webm" ; ответствующее расширение } e ls e i f ( v id e o . c a n P la y T y p e ( " v id e o / o g g " ) ') { ^ файлаj если браузер скажет: re tu rn . ogv" «Я может быть , и смогу его T При большинстве вариантов использования , если воспроизвести», вы не будете знать значений codecs , вполне доста­ точно будет уверенности " maybe ". дальше ►

403


снова разбираемся с форматами

интеграция функции getFormatExtension Тенерь нам необходимо внести ряд изм енений в функции w in d o w .o n lo a d и n e x t v id e o с целью задей­ ствовать g e tF o r m a tE x te n s io n . Сначала мы удалим расш ирения файлов из ф айловы х имен в плейлисте (носкольку вместо этого мы будем нрим енять g e tF o r m a tE x te n s io n для их вы яснения), а затем вызовем g e tF o r m a tE x te n s io n там, где мы задали свойство v i d e o . s r c : w in d o w .o n lo a d p la y lis t :

f u n c t i o n ()

{

[" v id e o /p r e r o ll" , " v id e o / a r e y o u p o p u la r " ,

Удалите расширения файлов. Теперь мы будем выяснять их программным пут ем .

" v id e o / d e s tin a tio n e a r th " ] ; v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ; v i d e o . a d d E v e n t L is t e n e r ( " e n d e d " , n e x t v i d e o , f a l s e ) ; v id e o .s r c = p l a y li s t [ p o s i t i o n ]

y

+ g e tF o r m a tE x te n s io n ()

v id e o . lo a d ( ) ; v id e o .p la y ( ) ;

'

И конкатенируйте резуль­ т ат getForm atExtension с файловым именем ис­ точника нового видео.

}

И нроделайте то же самое в n e x tv id e o : f u n c t io n

n e x t v i d e o ()

{

p o s itio n + + ; if

( p o s i t i o n >= p l a y l i s t . le n g t h ) p o s itio n

{

= 0;

}

v id e o .s r c = p l a y li s t [ p o s i t i o n ]

+ g e tF o r m a tE x te n s io n ()

v id e o . lo a d ( ) ; v id e o .p la y ( ) ;

Здесь мы делаем то же самое — конка­ тенируем результат getForm atExtension с файловым именем источника видео.

U проведение mecm-драйва... Добавьте функцию c a n P la y T y p e и внесите п родем онстриро­ ванны е чуть выше изм енения, носле чего перезагрузите свой файл w e b v i l l e t v . h t m l . Ну как, работает? Тенерь ваш код снособен вы яснять наиболее нодходящ ий формат. Если вы захо­ тите узнать, какое видео выбрал браузер, нонробуйте добавить код a l e r t в функции w in d o w .o n lo a d и n e x tv id e o ; внесите его в ниж ню ю часть каждой функции носле v i d e o . p l a y ( ) : a l e r t ( " P la y in g

" + v id e o . c u r r e n tS r c ) ;

К акой файл воснроизвел ваш браузер?

404

глава 8

h ttp ://(o c a lh


телевидение для нового поколения

_

Часщо

^адаБ аеМ ы е

Б о Ц р о сьх < s o u rc e > в объекте v id e o (как если бы вы набрали их в своей разметке). Благодаря этому у вашего объекта v id e o будет не­

Если я программно задаю источник своего видео и canPlayType возвращает «maybe», но воспроизведение все же не происходит, как это можно исправить?

сколько вариантов на выбор, и вам не придется заниматься напи­ санием более сложного кода для обработки ошибок. Мы не станем делать этого в данной главе, однако знайте о таком способе дать вашему объекту v id e o несколько вариантов на выбор, причем посредством кода, а не разметки.

О

Исправить это можно двумя путями. Первый состоит в том, чтобы перехватывать соответствующую ошибку и предоставлять объекту v id e o другой источник (о перехвате ошибок мы поговорим в конце главы). Второй заключается в использовании объектной модели документа (DOM) для написания сразу нескольких тегов

дыне

^ V

epG ° ° g /e Chrome

Вам может пот ребо­ ват ься уст ановит ь Ii ] ) У Д ь т е c Целью обеспечен ^ ” ия Quicktime для воспроиз­ °С 2 Ц о р о ^ Н ы ! ПаСНОСти°' ведения видеоф айлов с расширением MP4 Данные ограничения не пп в браузере Safari. торые операции vid e o + T ™ ™ * * * °овеРШать не'ко

Программа Quicktime зачастую устанавливается по умолчанию, но если она все же не была инсталлирована, вы можете загрузить ее отсюда: http://www. apple, com/quicktim e/do wnload/.

Ч ^ у и и Цу какфТс°(тТ ^ Г Г ' * * * £ ?

дет выглядеть как

?,)

ваш и ^ - а д р ес бу-

главы Кр К МЫ 6удвМ ПостУпать Т о с ^ ’ //)з Подоб"о

5

3

г = 3

5

£

Й

£

г

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

О ^ Д ь ш е

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

Если вы работаете в операционной системе Mac OS или Linux, то, скорее всего, используете Apache. Вы можете модифицировать файл h t t p d . c o n f (если у вас имеется корневой доступ) либо создать файл .h ta c c e s s в каталоге, где располагаются ваши видеофайлы, и добавить в него следующие строки: A ddType v id e o / o g g

. ogv

A ddType v id e o /m p 4

. mp4

A ddType v id e o /w e b m

. webm

Этот код сообщит серверу, как подходить к загрузке файлов с данными расширениями. Вы можете установить Apache в операционной системе Windows и произвести аналогичные манипу­ ляции. В случае с серверами IIS рекомендуем заглянуть в онлайн-документацию Microsoft и найти там «Конфигурирование типов MIME в IIS» (Configuring MIME types in IIS). дальше ►

405


наше послание вам

Я неустанно твержу, что здесь речь идет не только о JavaScript... Необходимо видеть общую картину. Создание веб-приложений подразумева­ ет использование разметки, CSS, JavaScript и его АР1-интерсрейсов.

В какой-то момент нам уже придется относиться к вам как к настоящим разработчикам. В этой книге мы (надеемся) номогаем вам делать каждый шаг —мы находимся рядом, чтобы нодхватить вас, нреж де чем вы унадете, и убедиться в том, что в вашем коде были расставле­ ны все точки над i. Однако быть настоящ им разработчиком номимо всего остального означа­ ет нонимать код, нанисанны й другими людьми, уметь увидеть главное за массой второстеп ен ­ ных деталей и разбираться в запутанности того, как все объединяется в одно целое. В оставш ейся части главы мы нредоставим вам возмож ность сделать все это. Далее нриведен нрим ер, которы й наиболее близок к реальному веб-нриложению из всего того, что нам до­ водилось видеть до настоящ его момента, нри этом он вклю чает массу составны х частей, ак­ тивное иснользование API-интерф ейсов и большое количество кода, которы й обеснечивает обработку множ ества реальны х деталей. Тенерь мы не можем разбирать каждую часть, разъ­ ясняя вам каждый нюанс, как обычно это делали (иначе книга разрослась бы до 1200 стра­ ниц); мы и не хотим этого делать, но скольку вам необходимо н риобретать навы ки объедине­ н и я всех кусочков «мозаики» без нас. Н е беснокойтесь, носкольку мы но-нрежнему будем рядом и расскажем, что именно делать, однако вы долж ны учиться восприним ать код, читать его, разбираться в нем, а затем донолнять и изменять его для того, чтобы он делал то, что вам необходимо. Таким образом, на про­ тяж ении следующих трех глав мы хотим, чтобы вы ногрузились в нриводим ы е нрим еры , изучили их и «вбили» код себе в голову. Да... вы к этому готовы!

406

глава 8


телевидение для нового поколения

Нам требуется Ваша помощь! Свежая новость... мы но лучили контракт на создание программного обеснечения комнании Starring You V ideo для их новы х видеокабинок. Ч то это такое? Это новейш ие кабинки с нодд ерж кой HTM L5 для заниси видео со общений: клиент заходит в уединенпую кабинку и записы ­ вает свое видеосообщ ение. Затем он сможет разнообразить свое видео, иснользуя настоящ ие киноэф ф екты ; в его распоряж ен и и будет сения-фильтр Old-tim e western (С ения), черно-белый фильтр Film n o ir (О чень тем ны й) и даже фильтр не от м ира сего Sci-fi (И н верти рован ное ви­ део). П осле этого клиент сможет отнравить свое сообщ ение другу. Мы реш или действовать и взяли на себя обязательство создать видеои н терф ейс и систему обработки видеоэф ф ектов. Однако есть одна нроблема. Видеокабинки не будут достунны в течение следующих ш ести не­ дель, а когда они нрибудут, код уже долж ен быть готов. Таким образом, мы за это время соби­ раемся обзавестись демоблоком с частичной функциональностью и несколькими тестовы ми видеоф айлами и нанисать весь код, иснользуя их. Когда мы закончим, реб ята из Starring You Video смогут нросто н рим енить наш код к только что снятому реальному видео. И, конечно же, не забы вайте, что сделать все это нам необходимо с иснользованием HTML5. И так, мы надеемся, что вы с нами, но скольку мы ноднисали контракт!

Заходите, снимайте видео, стилизуйте его и отправляйте своим друзьям.

дальше ►

407


исследуем видеокабинку starring you video

Заходите В Видеокабинку, и даВайте осмотримся... Н иж е ириведеи наш демоблок с и нтерф ей сом пользователя. Там им еется видеоэкран, на котором поль­ зователи смогут просм атривать свое видео. У них будет возмож ность н рим енить фильтр (нанример, Old-tim e w estern или Sci-fi) и но смотреть, как он работает, но еле чего они смогут отнравить видео дру­ зьям. Возможность заниси видео у нас нока отсутствует, ноэтому мы предусмотрели наличие тестовы х видеоф айлов, с которы м и можно будет работать. Н аш а нервая задача —обеснечить работоспособность кнонок, а затем мы займемся нанисанием видеоф ильтров. П реж де чем мы нристуним, взгляните на интерф ейс: Интерфейс демоблока. 8 центре располагается окно проигрывателя для просмот ра видео.

Применяйте свой любимый эффект : O ld -tim e w estern , Film n o ir или Sci-fi.

408

глава 8

Элементы управления , чт о­ бы воспроизводить> ставить на паузу и проигрывать видео в зацикленном реж им е , а также отключать звук.

Выбирайте тестовое видео. Иаил демоблок предлагает на выбор два таких видео.


телевидение для нового поколения

РаспакоВка демоблока Н а следующий день наш демоблок был доставлен самолетом, и настало врем я раснаковать его. П охоже, что мы нолучили функциональны й блок с уже нани санной нростой HTM L-разметкой и JavaScript-кодом. Д авайте сначала взглянем на HTM L ( v id e o b o o t h . h tm l) . Внереди вас ждут несколько страниц «заводского» кода, нросм отром которого мы займемся, а затем нерейдем к настоящему коду. J T

HTMLS ■ конечно же

^

оме м о г^ вся стилизация

<! doctype html>

ОЫЛа сделана 3(Х H a d Вот СО -

<html lang=Mе п п>

ответствующий CSS -файл.

<head> <title>Starring YOU Video Booth</title>

д вот Ja va S crip t-файл, который нам

J

потребуется для размещения большей части написанного кода. Чуть позже мы Clink rel=Mstylesheet" href = пvideobooth, c s s 11> /"взглянем на него более подробно, и, п о хоже, что они уже написали здесь код для <script src= "videobooth. j s nx / s c r i p t > ^ контроля над кнопками в интерфейсе. </head> -

<meta charset="utf-8">

<body>

Вот главный интерфейс, где у нас имеется сама консоль, которая разделена на область отображения видео и панель Управления с тремя наборами кнопок, сгруппированных в "effects", "controls" и "videoSelection".

<div id= "booth”> <div id="console"> <div id="videoDiv">

Y-

<video id="video" w idth=n720" height=" 480мX / video> </div>

*ч _

<div id=" dashboard" > <div id="effects">

Они уже установили видеопроигры­ ватель. это хорошо, поскольку он нам понадобится.

<a class="effect" i d = " n o r m a l " X / a > <a class="effect" i d = " w e s t e r n " X / a > <a class="effect" i d = " n o i r " X / a > <a class="effect" id=" scifi" X / a > </div>

\

Вот все эффекты Это всего лишь H TM L-якоря. О привязке к ним мы пого­ ворим чуть позже...

J

<div id="controls"> <a class="control

id="play"X/a>

<a class="control

id=" pause" Х / а >

<a class="control

id="loop"X/a>

<a class="control

id="mute"X/a>

И элементы управления проигрывателем

</div> <div i d = "videoSelection"> <a class="videoSelection" id="videol"></a> <a class="videoSelection" id="video2"></a>

два демовидео для тестирования И

</div> </div> </div> </body> </html>

дальше ►

409


рассмотрение имеющегося кода

Рассмотрение остальной части «заВодского» кода Тенерь взглянем на весь JavaScript-код, которы й мы нолучили с «завода», вклю чая код для конф игурирования кнонок (мы только что его рассматривали в соответствующ ем HTM L-файле) и код для каждого обработчика кнонки (которы й на текущий момент заботится о том, чтобы назад «отжимались» именно те наж атые кнонки, что и пужно). Мы рассмотрим весь этот код нрежде, чем начнем добавлять свой собственны й код.

• - S

А сейчас переходим k JavaScript... Д авайте откроем JavaScript-файл ( v id e o b o o th , j s ) . П охоже, что все кнонки в и н терф ей се работают, нросто они но ка не делаю т ничего интересного. Мы знаем, как они сконфигурированы , но скольку эти кнонки будут вызы вать код, которы й нам необходимо нанисать (нанример, для воснроизведения видео или для нросм отра видео с нрим енением фильтра, обеснечиваю щ его тот или и ной эф ф ект). Чуть ниж е вы найдете функцию, вызов которой нр о исходит но заверш ении загрузки страницы . В слу­ чае с каждым набором кнонок ( " e f f e c t s " , " c o n t r o ls " и " v id e o s e le c t io n " ) код нроходится но кнонкам и нрисваивает обработчики собы тий c l i c k якорны м ссылкам. Д авайте взглянем на это: функция, которая будет вызываться после полной загрузки страницы w in d o w .o n lo a d = f u n c t i o n () { ^ v a r c o n t r o lL i n k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . c o n t r o l " ) f o r ( v a r i = 0 ; i < c o n t r o l L i n k s . l e n g t h ; i+ + ) { c o n t r o l L i n k s [ i ] . o n c l i c k = h a n d le C o n t r o l;

"f

}

v a r e f f e c t L i n k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " а . e f f e c t " f o r ( v a r i = 0 ; i < e f f e c t L i n k s . l e n g t h ; i+ + ) { e f f e c t L i n k s [ i ] . o n c lic k = s e t E f f e c t ; ^ . }

Каждый оператор совершает цикл по элементам одной из группы кнопок. 3 случае с оЬраЬотчи ком onclick для каждой кнопки в элементах управления проигрыва­ телем задается обра­ ботчик handleControl.

случае с обработчиком ля effects задается setEffect.

v a r v id e o L in k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . v i d e o S e le c t io n " f o r ( v a r i = 0 ; i < v i d e o L i n k s . l e n g t h ; i+ +I-) { ^ ^ ^ наконец, в случае с обраv i d e o L i n k s [ i ] . o n c l i c k = s e tV id e o ;

ботчиком для videoSelection задается setVideo.

}

p u s h U n p u s h B u t to n s ( " v id e o l" , p u s h U n p u s h B u tto n s ( " n o r m a l" ,

[]); []);

< r

Сделав всю подготовительную работ у, мы исполь­ зуем вспомогательную функцию, чтобы визуально « о т ж ат ь» назад кнопки "v id e o l" и "norm al" (без применения фильтров) в интерфейсе.

С методом d o c u m e n t. q u e r y S e le c t o r A ll вы ранее не сталкивались; он аналогичен d o cu m e n t.g e tE le m e n ts B y T a g N a m e , за исклю чением того, что вы осущ ествляете выборку элементов, соответствующ их селектору CSS. Д анны й метод возвращ ает массив объектов элементов, соответствующ их аргументу в виде указанного селектора CSS. v a r e le m e n tA r r a y = d o c u m e n t. q u e r y S e l e c t o r A l l ( " s e l e c t o r " ) ;

410

глава 8


телевидение для нового поколения

Взгляд на обработчики кнопок Итак, JavaScript-код заботится о конф игурировании всех кнонок, чтобы н ри щелчке нользователя на них нроизош ел вызов соответствующ его обработчика. Д авайте взгля­ нем на ф актические обработчики, начав с обработчика для кнонок нроигры вателя (Play (В оснроизведение), Pause (Пауза), Loop (В оснроизведение в зацикленном реж и­ ме) и M ute (О тклю чить звук)), и носмотрим, что они делают: Первое, что мы делаем в данном обработчике, это вы­ ясняем, кто совершил вызов обработчика, для чего извле­ каем идентификатор элемента, который это сделал. f u n c t i o n h a n d le C o n t r o l (е) { ^ v a r id = е . t a r g e t. g e tA ttr ib u te (" id " ) ; if

( i d == " p la y " ) { p u s h U n p u s h B u tto n s ( " p la y " ,

} e ls e i f ( i d == " p a u s e " ) { p u s h U n p u s h B u tto n s (" p a u s e " ,

Выяснив идентификатор j мы узнаем, какой элемент это был: "play", "pause", "loop" или "mute". В зависимости от того, какая это окажется кнопка, мы изменим инт ер. фейс, чтобы он отражал нажат ую кнопку. Например, если была нажата кнопка Pause (Пауза), — в этом случае кнопка Play (Воспроизведение).

[" p a u s e " ])

[" p la y " ])

} e ls e i f ( i d == " lo o p " ) { i f ( is B u tto n P u s h e d ( " l o o p " )) { p u s h U n p u s h B u tto n s ( " " , [ " l o o p " ] ) , } e ls e { p u s h U n p u s h B u t to n s ( " lo o p " , [ ] ) ;

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

}

} e ls e if

i f ( i d == "m u te ") { ( is B u tto n P u s h e d ( " m u t e " ) ) { p u s h U n p u s h B u tto n s ( " " , [ " m u t e " ] ) , } e ls e { p u s h U n p u s h B u tto n s (" m u te " , []; }

}

f

к

Весь эт от показанный код является косм ет и­ ческим и лишь изменяет внешний вид кнопок с нажатого состояния на ненажатое. У нас пока от сут ст вует код для выполнения чегото реального, например для воспроизведения видео. Его нам и предстоит написать.

Разные кнопки обладают разной семан­ тикой. Например, Play (Воспроизведе­ ние) и Pause (Пауза) подобны настоящим радиокнопкам, в то время как Mute (О т клю чит ь звук) и Loop (Воспроизведе­ ние в зацикленном режиме) сродни кно п­ кам -переключателям.

Все это, конечно, здорово, однако где будет располагаться наш код? Д авайте нодумаем: когда пользова­ тель нажмет кнонку, нанрим ер Play (В оснроизведение), нам не только пужно будет обеснечить обнов­ ление и н терф ей са (для чего у нас уже им еется код), но и предусмотреть вы нолнение дополнительного кода, которы й действительно что-то делает, нанрим ер запускает воснроизведение видео. Д винемся дальше и взглянем на два других обработчика (для задания видеоэф ф ектов и тестового видео), и вам станет внолне ясно (если уже не стало), где именно будет располагаться наш код... дальше ►

411


задание обработчиков кнопок

Обработчики setEffect и setVideo О бработчик s e t E f f e c t обрабаты вает ваш выбор эф ф екта: нанрим ер, нрим еняем ы е эф ­ ф екты могут вообщ е отсутствовать (нри вы боре "n o rm a l") либо быть " w e s te rn " , " n o ir " или " s c i f i " . Аналогичным образом, обработчик s e tV id e o обрабаты вает ваш вы бор тестового видео нод ном ером 1 или 2: Он работает т ак же, как обработчик kandleControl: мы извлекаем идентифи­ катор осуществившего вызов элемента (кнопки, кот орую нажал пользователь), fu n c t io n s e tE f fe c t ( e ) { а затем соответствующим образом v a r id = e . t a r g e t. g e tA ttr ib u te (" id " ) ; обновляем интерфейс. А здесь будет i f ( i d == " n o r m a l" ) { располагаться p u s h U n p u s h B u tto n s ( " n o r m a l" , [ " w e s t e r n " , " n o i r " , " s c i f i " ] ) ; наш код. } e ls e i f ( i d == " w e s t e r n " ) { p u s h U n p u s h B u tto n s ( " w e s t e r n " , } e ls e i f ( i d == " n o i r " ) { p u s h U n p u s h B u tto n s ( " n o i r " , } e ls e i f ( i d == " s c i f i " ) { p u s h U n p u s h B u tto n s ( " s c i f i " ,

[ " n o r m a l" ,

[ " n o r m a l" ,

[ " n o r m a l" ,

" n o ir " ,

" s c if i" ] ) ;

"w e s te rn ",

" s c if i" ] ) ;

"w e s te rn ",

" n o ir " ] ) ;

}

3 каждом случае мы добавим код для об­ работки реализации соответствующего фильтра, обеспечивающего спецэффекты. То же самое справедливо и для setVideo; мы выясняем, какая кнопка была нажата, и обновляем интерфейс. f u n c t i o n s e t V id e o (е) { v a r id = е . t a r g e t. g e tA ttr ib u te (" id " ) ; i f ( i d == " v i d e o l " ) { p u s h U n p u s h B u t to n s ( " v id e o l" , [ " v i d e o 2 " ] ) ; } e ls e i f ( i d == " v id e o 2 " ) { p u s h U n p u s h B u tto n s ( " v id e o 2 " , [ " v i d e o l " ] ) ; }

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

412

глава 8


телевидение для нового поколения И не забывайте, что если вы не хотите набирать приводимый в книге код, можете целиком загрузить его, посетив адрес h ttp ://w ic k e d ly sm a rt.c o m /h fh tm ls.

А Bom U 8 СП0 М 02 <1ГП6 ЛЬНЫ6 функции

И для нолноты (либо если вы соверш аете 11-часовой н ерелет на Фиджи, не имея н ри этом достуна в И нтернет, и у вас возникло ж елание заняться набором всего этого кода): pushUnpushButtons забот и т ся о состояниях кнопок. Он п рини ­ м а е т ар гум ен т ы в виде значения id кнопки, кот орая будет в ы ­ глядет ь нажатой, а также значения id одной или более кнопок в массиве, которые б уд ут выглядеть ненажатыми. f u n c t i o n p u sh U n p u sh B u tto n s (id T o P u sh, if

( id T o P u s h

!= " " )

idA rrayT oU npush)

{

{

, Ж ат ия не я вляет ся п у с т ы м .

<

п . И з в л е к а е м э л е м е н т a n c h o r с ис~ п о л ь з о в а н и е м данного значения id...

v a r a n c h o r = d o c u m e n t . g e t E l e m e n t B y l d ( id T o P u s h ) ; v a r t h e C l a s s = a n c h o r . g e t A t t r i b u t e ( " c l a s s ") ; if

(! t h e C l a s s . i n d e x O f ( " s e l e c t e d " ) > = 0 ) ^ ^ „ lff th e C la ss = th e C la ss + " s e le c te d " ; a n c h o r . s e t A t t r i b u t e (" c l a s s ",

Сначала мы убеж даем ся в т о м , ч т о значение id кнопки для н а -

4

---------- ...и и зв л е к а е м а т р и б у т class.

{

Мы « н а ж и м а е м » кн опку n y „ ___________ т е м добавления класса "s e l e c t e d " c r ----------✓л / & a n c h o r и... th e C la ss);

v a r n ew lm age = " u r l ( i m a g e s / " + i d T o P u s h + " p r e s s e d . p n g ) " ; бы OHO пбрбКрЫЛО

a n c h o r . s t y l e . b a c k g ro u n d lm a g e = n e w lm a g e ; }

. .. о * « > в л « м ф о н о во е

9 c P1

fo r

3

“ ИНГ „

(v a r i

= 0;

i

oSpa.WM. « “ У

"° е" % Э е « С о д “ » в < .~ е .« С р а ж е н u t ■ p a ^ p r e s s e « ■ Чтобы кнопки выглядели ненажатыми, мы соверш аем цикл по < id A r ra y T o U n p u s h . l e n g t h ; i+ + ) { * \ м а с с и в у з н а ч е н и й i d кнопок, K O -

a n c h o r = d o c u m e n t. g e tE le m e n tB y ld (id A rra y T o U n p u s h [ i ] ) ; т орые должны приобрести такой

вид, извлекая каждый anchor... th e C la s s = a n c h o r . g e t A t t r i b u t e ( " c l a s s " ) ; if

( t h e C la s s . in d e x O f ( " s e l e c t e d ” ) > = 0 )

{

x

••-Уоеждаемся,

что кнопка действи мельно нажата (если это так, mo

К

th e C la s s = th e C la s s . r e p la c e ( " s e le c t e d ” , a n c h o r . s e t A t t r i b u t e ( " c la s s " ,

" " ) ; У Hee

t h e C la s s ) ;

& уд ет

и м е т ь с я

к ла с с

■■■Удаляем

" se le c ted "

из

" s e le c te d ." )..,

c la ss...

a n c h o r . s ty le .b a c k g r o u n d lm a g e = " " ;

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

^

} }

fj=u n c .t i •o n

• т > 4- 4is B u t to n PI-»u s 1h e dл/('idл)\

isButtonPushed п р о с т о п р о в е р я е т , наж ат а ли кнопка. О н п р и н и м а е т id э л е м е н т а anchor... ...извлекает anchor...

v a r a n c h o r = d o c u m e n t. g e tE le m e n tB y ld ( id ) ;

_

_

,

I, ,

... i

ff4

v a r th e C la s s = a n c h o r . g e t A t t r i b u t e ( " c l a s s " ) ; re tu rn }

( t h e C la s s . in d e x O f ( " s e l e c t e d ” ) > = 0 ) ;

,

^ —

...извлекает class данного anchor . . .

...и возвращает tru e , если у anchor имеется класс “selected". дальше ►

413


ранний тест

Запах ноВой демомашины... пришло Время mecm-gpaiiBa! Мы нанисали не слишком много кода, однако мы читаем имею щ ийся код и вникаем в него, и это хорош о. И так, за­ грузите ф айл v id e o b o o t h . h t m l в своем браузере и восполь­ зуйтесь кнонками. Х орош енько протестируйте их. Также добавьте несколько a l e r t в функции обработчиков. П ро­ чувствуйте, как все это работает. Когда вы вернетесь, мы нристуним к нанисанию кода, которы й заставит кнонки работать но-настоящему. Протестируйте все эти кнопки, при этом обратите внимание на то, что одни из них подобны радиокнопкам, а другие сродни кноп­ кам - переключателям.

^ .В озьми в руку карандаш решение к данному заданию вы найдете, пролистав вперед две страницы ..

Пометьте, какие из приведенных ниже кнопок подобны пере­ ключателям (то есть являются независимыми), а какие — радио­ кнопкам, когда нажатие одной кнопки будет приводить к тому, что остальные перестанут быть нажатыми). Также напишите рядом с каждой кнопкой имя соответствующего обработчика. Мы уже сде­ лали это за вас для двух пар кнопок:

Play (Воспроизведение) и Pause (Пауза) подобны радиокнопкам и не могут быть выбраны одновременно. 414

глава 8

Loop (Воспроизведение в зацикленном режиме) и Mute (Отключить звук) подобны кнопкампереключателям и могут использоваться независимо от других кнопок.


телевидение для нового поколения Кажется, я что-то пропустила... Как вы проводили из­ влечение из элементов <div> с использо­ ванием якорных тегов <а>, чтобы в интер­ фейсе были кнопки?

Все благодаря мощи CSS. Ж аль, что эта книга не назы вается «Изучаем програм м ирование на HTM L5 с использованием JavaScript и CSS» (H ead First HTML5 P rogram m ing with JavaScript 8c CSS), но тогда она содерж ала бы 1400 страниц, не так ли? Нас, конечно же, можно было бы угово­ рить написать продвинутую книгу по CSS... А если серьезно, то мощь разм етки направлена на структуру, a CSS — на представление (если это новая для вас тема, то загляните в книгу «Изучаем HTM L, XHTM L и CSS»). То, что мы делаем, не является таким уж сложным; опиш ем все вкратце для тех, кому лю бопы тно. Мы задаем карт инку с консолью видеокабинки (без кнопок) в качестве фонового изображения для элемента <div> с id в виде console.

Элемент <video> располагается в <diV>j который пс зиционируется о т ­ носительно консоли Кром е того , мы производим абсо­ лютное позициони­ рование элемента <video>j чтобы он оказался в центре консоли.

Мы позиционируем <div> с id в виде dashboard относительно консоли , а затем позициониру­ ем элементы <div> для каждой группы кнопок относительно панели управления.

Каждый элемент <div> группы кнопок получает фоновое изображение для всех ненажатых кнопок.

Если вам захочется подробно исследовать CSS, загляните в файл videobooth.css.

Каждый якорь "button" позициониру­ ется в <div> для определенной группы и получает ширину и высоту, чтобы совпадать по размерам с кнопкой , которой он соответствует. Когда пользователь щелкнет "b u tto n ", мы снабдим данный якорь фоновым изо­ бражением нажатой кнопки , которое перекроет собой ненажатую кнопку.

дальше ►

415


решение упражнения

-.Возьми в руку карандаш Пометьте, какие из приведенных ниже кнопок подобны переключате­ лям (то есть являются независимыми), а какие — радиокнопкам (когда нажатие одной кнопки будет приводить к тому, что остальные переста­ нут быть нажатыми). Также напишите рядом с каждой кнопкой имя соот­ ветствующего обработчика. Вот наше решение этого упражнения.

Все эти кнопки подобны радиокнопкам ; мы даем пользователю возмож­ ность применять к видео только один э ф ­ фект за раз.

416

глава 8

Кнопки для выбора

Play (Воспроизведе­ ние) и Pause (Пауза) подобны радиокноп­ кам и не могут быть выбраны одновременно .

Loop (Воспроизве­ дение в зациклен­ ном режиме) и Mute (Отключить звук) подобны кнопкам -пе­ реключателям и м о ­ гут использоваться независимо от других кнопок.

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


телевидение для нового поколения

Подготовка демоВидео... v v v

l^ bl создадим этот

П реж де чем мы реализуем элементы унравления button, нам нотребуется видео для их тестирования, и, как можно судить но кнонкам, сотрудники S tarring You Video нрислали нам два демовидео. Создадим объект для разм ещ ения двух видео, а затем добавим код для нашего обработчика onload, чтобы задать источник объ­ екта video (точно так же, как мы делали в случае с Webville TV).

°^ьект &ля разме щения двух * и демовидео. Вскоре мы вернемся к этому и объясним вам все подробнее.

var videos = {videol: пvideo/demovideolп , video 2 : "video/demovideo 2

Извлекаем элемент video и з а w in d o w .o n lo a d = f u n c t i o n ()

{

^

даем

в

п е р в о е

к а ч е с т в е ви д ео

v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ;

\щ е

v i d e o . s r c = v i d e o s . v i d e o l + g e tF o r m a tE x te n s io n () ;

КО б у д е т

v i d e o . l o a d () ;

fo r

(v a r i

= d o c u m e n t. q u e r y S e l e c t o r A l l ( " а . c o n t r o l " ) ;

= 0;

i

< c o n tr o lL in k s . le n g th ;

c o n t r o lL in k s [ i] .o n c lic k

i+ + ) {

= h a n d le C o n t r o l;

j v a r e ffe c tL in k s

= d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . e f f e e t " ) ;

fo r

i

(v a r i

= 0;

< e f f e c t L in k s . le n g th ;

i+ + )

его

и с т о ч н и к а

м а с с и в е ,

р а с ш и р е н и е ,

^ _______________ ^

v a r c o n t r o lL i n k s

в

и м е ю -

к о т о р о е

М ОЖ -

в о с п р о и зв е с т и .

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

{

e f f e c t L i n k s [ i ] . o n c lic k = s e t E f f e c t ; }

v a r v id e o L in k s fo r

(v a r i

= 0;

= d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . v i d e o S e l e c t i o n " ) ; i

< v id e o L in k s . le n g th ;

i+ + )

{

v i d e o L i n k s [ i ] . o n c l i c k = s e tV id e o ; }

p u s h U n p u s h B u t to n s ( " v id e o l" ,

[] ) ;

p u s h U n p u s h B u tto n s ( " n o r m a l" ,

[] ) ;

ВН И М АТЕ ЛЬН О ПРО Ч ИТАЙ ТЕ!

Ч тобы не допустить небреж ности, не забы вайте, что в Webville TV есть функция g e tF o r m a tE x te n s io n , но не этот код! Поэтому открой те файл w e b v i l l e t v . j s , сконируйте и вставьте данную функцию в код своего н рилож ения Video Booth. И еще один небольш ой аснект: в коде Video B ooth у нас нет глобального объ­ екта v id e o , ноэтому добавьте данпую строку в верхню ю часть своей функции g e tF o r m a tE x te n s io n , чтобы иенравить это: ^ v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ;

^

Добавьте данную строку в верхнюю 4 a C m t>

Ф У ^ Ц и и

getForm atExtension.

дальше ►

417


поддержка пользовательских элементов управления видео

Реализация элементов управления Видео

Сейнас мы стираемся реализовать все эти кнопки.

П риш ло время заняться кнонками! Важно отметить, что в данном нроекте мы собираемся реализовать

собственные элементы унравления видео. То есть вместо того чтобы иснользовать встроенны е элемен­ ты унравления видео, мы сами будем контролировать данное взаимодействие. Таким образом, когда пользователям нотребуется воспроизвести, ноставить н а наузу видео, отклю чить в нем звук или даже н роиграть его в зацикленном реж име, они будут нрим енять наш и пользовательские элементы унравле­ н и я b u t t o n , а не встроенны е. Это также означает, что мы будем делать все это нрограммно с номощью соответствующ его API-интерфейса. Сейчас мы не собираем ся идти до конца, носкольку это означало бы реализацию , н анрим ер, кнонок N ext (Далее) и Previous (Назад), смысла в которы х в данном п ри ­ лож ении нет, номы могли бы это сделать при необходимости. Н а нростом нрим ере реализации небольш ой нанели унравления вы сможете нонять идею и развить ее дальше, если нож елаете. И так, нристуним. Как насчет того, чтобы начать с кнонки Play (В оснроизведение), а затем двипуться от нее внраво, к кнонке Pause (Пауза), носле нее —к Loop (В оснроизведение в зацикленном реж им е), а за­ тем —к M ute (О тклю чить звук))? Н айдите обработчик h a n d le C o n tr o l и добавьте туда следующий код:

f u n c t i o n h a n d le C o n t r o l (е) { v a r id = е . ta r g e t. g e tA ttr ib u te (" id " ) ; v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ; if

( i d == " p la y " ) { p u s h U n p u s h B u tto n s ( " p la y " , i f ( v i d e o . ended) { v id e o . lo a d () ;

[" p a u s e " ]) ; \

}

v i d e o . p l a y () ; } e ls e i f ( i d == "p a u s e " ) { p u s h U n p u s h B u tto n s (" p a u s e " ,

[" p la y " ]);

} e ls e if

i f ( i d == " lo o p " ) { ( is B u tto n P u s h e d ( " l o o p " )) { p u s h U n p u s h B u tto n s ( " " , [ " l o o p " ] ) ; } e ls e { p u s h U n p u s h B u tto n s ( " lo o p " , [ ] ) ; }

} e ls e if

i f ( i d == "m u te ") { ( is B u tto n P u s h e d ( " m u t e " )) { p u s h U n p u s h B u tto n s ( " " , [ " m u t e " ] ) ; } e ls e { p u s h U n p u s h B u tto n s (" m u te " , [ ] ) ;

}

418

глава 8

Нам необходима ссылка на объект video. Это должно быть довольно просто для вас. Если пользователь щелкнет на кнопке Play ( Воспроизведение), то произойдет вызов метода play в отношении объекта video. Но хот им предупредить, что здесь имеется один сложный м о ­ мент , который может оказаться хлопотным: если бы мы воспроиз­ водили видео и позволили ему п р о ­ играться до конца, то для того, чтобы опять запуст ит ь его, нам сначала пришлось бы снова его загрузить. Мы проверяем, что видео проигралось до конца (а не было просто поставлено на паузу), поскольку в данном случае нам п о ­ требуется лишь снова загрузить его. Если оно было поставлено на паузу, мы сможем воспроизвести его, не прибегая к загрузке.


телевидение для нового поколения

Реализация остальных элементов управления Видео Реализуем остальные элементы унравления — они настолько нросты , что чуть ли не сами могут нанисать свой код:

f u n c t i o n h a n d le C o n t r o l (е) { v a r id = е . ta r g e t. g e tA ttr ib u te (" id " ) ; v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) if

( i d == " p la y " ) { p u s h U n p u s h B u tto n s ( " p la y " , [ " p a u s e " ] ) ; v id e o . lo a d ( ) ; v id e o .p la y ( ) ; } e ls e i f ( i d == " p a u s e " ) { p u s h U n p u s h B u tto n s (" p a u s e " , [ " p l a y " ] ) ; v id e o . p a u s e ( ) ; } e ls e if

i f ( i d == " lo o p " ) { ( is B u tto n P u s h e d ( " l o o p " )) { p u s h U n p u s h B u tto n s ( " " , [ " l o o p " ] ) ; } e ls e { p u s h U n p u s h B u tto n s ( " lo o p " , [ ] ) ; }

v id e o .lo o p = ! v id e o .lo o p ; } e ls e if

i f ( i d == " m u te ") { ( is B u tto n P u s h e d ( " m u t e " )) { p u s h U n p u s h B u tto n s ( " " , [ " m u te " ] ) ; } e ls e { p u s h U n p u s h B u tto n s (" m u te " , [ ] ) ; }

v id e o .m u te d = ! v id e o .m u t e d ; }

Если пользователь пост а­ вит видео на паузу, то бу­ дет задействован метод pause объекта video. воспроизведения видео в за ­ цикленном режиме у нас в объекте video имеется логическое свойство loop. Мы просто присваиваем ему соответствующее значение...

Для

...для чего, чтобы было еще интереснее , используем ло­ гический оператор ! («не»), который просто меняет за нас логическое значение. з случае с m ute все происходит аналогичным образом'- мы п р о ­ сто меняем текущее значение свойства m ute , когда пользо­ ватель нажимает кнопку Mute (О т клю чит ь звук).

Еще один mecm-драйВ! Убедитесь, что вы внесли в код все нриведенны е выше изменения. Загрузите v id e o b o o t h . h t m l в браузере и протестируйте элементы унравления b u t t o n . Вы долж ны видеть, как запускается воснроизведение видео, иметь возмож ность ставить его на наузу, отклю чать в нем звук и даже нроигры вать его в зацикленном реж име. Вы, конеч­ но же, но ка не сможете вы брать другое демовидео или добавить эф ­ фект, однако вскоре мы дойдем и до этого! дальше ►

419


разбираемся с событием ended объекта video

ДорабатыВаем один нюанс... Нам необходимо доработать один небольш ой нюанс, чтобы кнонки действи­ тельно работали так, как надо. Вот вариант иснользования: допустим, вы вос­ производите видео и нри этом не нажали кнонку Loop (В оснроизведение в за­ цикленном реж им е), в результате чего нроигры вание видео осущ ествляется до конца и затем заверш ается. В силу нашего нодхода к реализации кнонка Play (В оснроизведение) будет оставаться в нажатом состоянии. А не будет ли лучше, Наша кнопка Play (Воспроизведение) если она вернется в исходное нолож ение и будет готова к новому нажатию? пока не является на Иснользуя собы тия, мы можем легко обеснечить данное нов едение. Н ачнем Ю О % такой, какой с добавления слушателя собы тий ended. Внесите данны й код в ниж ню ю часть она должна быть. обработчика onload: video.addEventListener("ended", endedHandler, false); Тенерь наниш ем обработчик, вызов которого будет нроисходить каждый раз, когда воснроизведение видео будет заверш аться нри достиж ении конца видеофайла: function endedHandler() { pushUnpushButtons("", ["play"])

Нам нужно лишь сделать т а к , ч т о ­ бы кнопка Play (Вос­ произведение) снова приобрела ненажатое состояние. И все!

Мы задаем обработчик для события "ended", который будет вызы­ ваться по завершении воспроизведения видео (но НЕ когда видео будет ст авиться на паузу!).

U еще один mecm-драйВ... И так, внесите изм енения, сохраните код и перезагрузите страницу. Запустите видео, дайте ему нроиграться до конца и не наж имайте кнонку Loop (В оснроизведение в зацикленном реж им е). В результате вы долж ны увидеть, как в конце кнонка Play (В оснроизведение) сама вернется в исходное нолож ение.

Кнопка Play (Воспроизведение) вернется в исходное п о ­ ложение сразу же по завершении проигрывания видео. 420

глава 8


телевидение для нового поколения

Переключение меЖду тестовы м и Видео д н м о в и д ш ) No

Мы уже добавили объект для разм ещ ения наш их двух тестовы х ви­ део и даже раснолагаем двумя кнонками для вы бора между ними. Каждой кнонке нрисвоен обработчик setVideo. Д авайте взглянем на код, которы й нозволит нереклю чаться между этими видео: Вот наш объект с двумя видео, который мы приводим снова в качестве напоминания, чтобы вы смогли по нят ь, как мы собираемся его использовать... ^

4

1 ,

Д1<М 0Ш ЦШ ) \ IV

1

2

J

1

var videos = {videol: "video/demovideol", video2: "video/demovideo2"} function setVideo (e)

д gQM снова т ш 0Ьр а 6 о т т к .

{

var id = e .t a r g e t .getAtt r i b u t e ("id"); var video = d o c um e n t .getElementByld("video”) ;

if

О п я т ь -т а к и , нам т ребует ся ссылка на объект video.

(id == "videol”) { pushUnpushButtons("videol" ,

} else if

(id == "video2")

{

pushUnpushButtons("video2" ,

video.src = videos[id]

["v i d e o 2 "]);

["videol"]);

+ getFormatExtension();

video, load () ; video .pi ay () ;

pushUnpushButtons("play", ["pause"]);

Мы удостоверяемся, что кнопка Play (Воспроизведение) нажата, поскольку за п у с т и м проигрывание видео, когда пользователь щ елкнет на кнопке для выбора нового видео.

З а т е м мы обновляем кнопки т е м же п у т е м , что и раньше, никаких изменений здесь нет. Д а л ее мы используем id кнопки (а т р и б ут id элем ент а anchor) для извлечения со от вет ст вуй к - ющего имени видеофайла и прибавляем расширение, под­ держиваемое нашим браузером. О бр ат и т е внимание, что мы применяем скобочную нотацию в случае с объектом videos, и с­ пользуя ст року id в качестве имени свойства.

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

Внесите изменения и проведите тест-д р а й в ! Внесите данны е изм енения в вашу функцию setV id eo , а затем перезагрузите страницу. После этого у вас долж на ноявиться возмож ность легко нереклю чаться между источникам и видео.

дальше ►

421


интервью с элементом video

Интервью недели:

Признания элемента video

Head First: Д обро ножаловать, Video. Сра­ зу нерейду к вонросу, которы й всех и н тере­ сует, и заклю чаться он будет в отнош ениях между Вами и элементом canvas. Элемент Video: Ч то Вы имеете в виду? Head First: Вы якобы кутите ночи н анролет в вихре удовольствий, завтракаете вместе но утрам. Нужно ли еще что-то говорить? Video: Здесь следует отметить, что у нас с Canvas сложились нрекрасны е взаим оотно­ ш ения. Canvas отображ ает свое содерж и­ мое в весьма п ривлекательной в визуаль­ ном плане манере, а я являю сь «рабочей видеолош адкой». Я разбираю сь с кодеками и доставляю видеосодерж имое в браузер. Head First: Ч то ж, это не совсем тот от­ вет, на которы й я рассчиты вал, но он меня устраивает. Ладно, элемент canvas нрекрасно снравляется с отображ ением 2Б-граф ики, а Вы —с отображ ением видео. И что? В чем здесь и стинная связь? Video: Как и в любых взаимоотнош ениях, когда вы объединяете две вещ и и имеете на выходе нечто большее, чем сумма двух частей, то вы нолучаете нечто особенное. Head First: Ч то ж, а не могли бы Вы вы ра­ зиться более конкретно? Video: Это нростая конценция. Если вы хотите делать что-то еще номимо обы чно­ го воснроизведения видео (нанример, осу­ щ ествлять обработку своего видео, либо задействовать пользовательские оверлеи, либо одноврем енно выводить несколько видеоизображ ений), то вам нотребуется иснользовать canvas.

422

глава 8

Head First: Все это звучит здорово, однако видео требует больших вы числительны х ресурсов для обработки. Я имею в виду, что н ри этом нроходит огром ны й н оток дан­ ных. Как JavaScript, язы к сценариев, смо­ ж ет сделать здесь что-либо реальное? Нанисание JavaScript-кода — не то же самое, что програм м ирование на нативном языке. Video: О, для вас это будет сю рнризом... Вы см отрели носледние тесты производи­ тельности JavaScript? Он уже является бы­ стрым, и его скорость с каждым днем повы ­ шается. Самые блестящ ие снециалисты но виртуальным машинам в индустрии уснешно работаю т над этой нроблемой. Head First: Да, но что с видео? Д ействи­ тельно ли с ним все обстоит так? Video: Д ействительно. Head First: Н е могли бы Вы нривести нримеры того, что можно сделать с номощью JavaScript, canvas и video? Video: Конечно. Вы мож ете обрабаты вать видео в реж им е реального времени, ин­ спектировать характеристики видео, из­ влекать данны е из видеокадров, модиф и­ ц ировать видеоданные путем, нанример... вращ ения, м асш табирования видео или даже и зм енения никселов. Head First: Н е могли бы Вы нам нов едать, как это можно сделать в коде? Video: Я еще верпусь к Вам, чтобы обсу­ дить данны й вонрос, мне тут нросто ностунил звонок от Canvas... Нужно бежать...


телевидение для нового поколения

Время спецэффектов Н е н ора ли нам добавить видеоэффекты ? Мы хотим нрим енять эф ф екты к нашему оригинальному видео, такие как Film noir, Oldtim e w estern и даже Sci-fi. Н о если вы взглянете на API-интерф ейс Video, то не найдете там каких-либо методов для н рим енения эф ­ фектов либо снособов добавить их нанрямую. Так как же мы будем добавлять эти эффекты ? Н емного но думайте над тем, как мы могли бы добавить эф ф екты в наше видео. Не беснокойтесь, если вы нока еще не знаете, как обрабаты вать видео, нросто обдумайте вы сокоуровневы й дизайн.

Starring You Video Заметки no разработке...

Мы х о т и м прим енят ь к на ­ ш ему оригинальному видео такие эф ф ек т ы , как Film noirj O ld -tim e w estern и Sci-fi.

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

К ак вы сможете до­ браться до пикселов, образующих каждый кадр видео?

Как вы сможете от обра­ зи т ь видео, когда обра­ ботаете все его пикселы с целью применения о п р е ­ деленного эф ф екта?

Д о п у с т и м , вам необхо димо написать функцию для реализации каждого эф ф ект а, — как она бу­ дет выглядеть?

\

идеи напиш ите здесь.

дальше ►

423


план реализации спецэффектов

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

Кнопки все еще ждут, когда мы их подключим.

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

Временный буфер, который и н т е ­ ресно выглядит...

Мы немного изучим особенности видеообработки и познакомимся с методикой на основе применения временного буфера для добавле­ ния наших эффектов.

Мы реализуем временный буфер, используя canvas (хо т ит е — верьте, х о т и ­ т е — нет)!

Мы реализуем временный буфер, который даст нам возможность увидеть совместно в дей­ ствии video И canvas.

Мы реализуем по одной функции для каждого эффекта: western, noir И scifi.

function n o i r ( p o s , г, g, b, data)

{

} К '' И наконец, мы соединим все воедино и прове­ дем тестирование!

Измененные п и к ­ селы мы будем отображать, как вы уже дога­ дались, в canvas.

lO T W T V P M Теперь вы знаете, что мы собираемся реализовать функцию, которая будет обрабатывать каждый эффект. Возьмем, к примеру, эффект Film noir. Как вы будете выбирать тот или иной цветной пиксел из видео и делать его черным либо белым? Подсказка: каждый пиксел включает три компонента: г (red — красный), g (green — зеленый) и ь (blue — синий). Если бы у нас был доступ к этим составным частям, то чтобы мы могли сделать?

424

глава 8


телевидение для нового поколения

Пора обеспечить работоспособность кнопок для применения эффектов Сначала легкая часть: мы нодклю чнм соответствующ ие кнонки и сделаем так, чтобы они работали. Н ачнем с создания глобальной н ерем ен ной effect Function. О на будет содерж ать функцию, которая сможет извлекать данны е из видео и нрим енять к ним фильтр. То есть в зависимости от желаемого эф ф екта нерем енная effect Function будет содерж ать функцию, которая знает, как обрабаты вать виде­ оданны е и делать их черно-белыми либо н рим енять к ним сению или инвертирование. Итак, добавьте эту неременпую в верхню ю часть своего файла: var e f f e ctFunction = null;

Мы станем нрисваивать этой функции соответствующ ее значение каждый раз, когда пользователь бу­ дет щелкать н а кнонке для н рим ен ен ия эф ф екта. Сейчас мы воспользуемся такими именами функций, как western, noir и scifi, а сами эти функции наниш ем немного нозже. 8 от снова наш обработчик setEffect. Как вы по м нит е его вызов происходит всякий р а з>когда пользователь щ елкает на кнопке для применения эффекта. f unction setEffect (е)

{

var id = е .t a r g e t .g e t A t t r i b u t e ("id"

if

(id == "normal")

/

При каждом нажатии кнопки пользоват елем мы будем присва­ ивать переменной effect Function значение в виде соот вет ст вую щ ей функции (все эти функции нам еще предст оит написать). Если пользователь ре ш и т не п р и ­ менят ь э ф ф ек т ы j то есть выберет "normal", мы присво­ им значение null.

{

pushUnpushButtons("normal",

["western",

effectFunction = null; } else if

(id == "western")

{

p u s h U n p u s h B u t t o n s (" w e s t e r n " , ["normal",

}

*

"scifi"])

*■— 8 иных случа ях мы будем else if (id == "noir") { >/ присваивать p u s h U n p u s h B u t t o n s (" n o i r " , ["normal", "western", "scifi"]) eff ectFunction значение в виде effectFunction = noir; имени с о о т ­ else if (id == "scifi") { вет ст вую щ ей p u s h U n p u s h B u t t o n s (" s c i f i " , ["normal", "western", "noir"]) ф ункциил которая effectFunction = scifi; займ ет ся п р и ­ менением опреде­ Нам по-преж нему нужно написать все эти функции ленного эффекта. для применения эффектов. Д авай т е п о см от рим как осуществляется обработка видео, чтобы мы смогли п р им енит ь к нему эффекты! effectFunction = western;

}

"noir",

у

Итак, мы можем нереходить к изучению врем енного буфера, носле чего вернемся и носмотрим, как дан­ ные функции внисы ваю тся в общую картипу и как осущ ествляется их нанисание! дальше ►

425


обзор процесса обработки видео

Как происходит обработка Видео Ранее мы обеснечнлн снособ нрнсванвать функцию глобальной н ерем ен ной ef f ectsFunction в резуль­ тате наж атия пользователем кнонок для н рим ен ен ия эф ф ектов в интерф ей се. Сейчас возьм ите эти сведения и ненадолго отлож ите их у себя в нодсознании, носкольку нам нредстоит заняться тем, как мы на самом деле собираемся брать и обрабаты вать видео в реж им е реального времени с целью добав­ лен и я эф ф ектов. Д ля этого нам нотребуется «дотяпуться руками» до никселов видео, изм енить их для достиж ения ж елаемого нами эф ф екта, а затем как-то вернуть на экран. П редусматривает ли API-интерф ейс Video какой-нибудь снособ обработки видео до того, как оно будет отображено? Нет. Однако он дает нам снособ добраться до никселов, ноэтому остается лиш ь выяснить, как их обработать и отобразить. П остойте, никселы? О тображ ение? П омните главу 7? Элемент canvas! Все верно, ранее мы кое-что уноминали об «особых взаимоотнош ениях», установивш ихся между эле­ ментами video и canvas. Давайте взглянем н а один из снособов, но средств ом которы х элементы video и canvas могут работать сообща. ^ ^ Подробности сенсационной н о-

^

в ости, наконец, раскрыты!

ф

Видеопроигрыватель декодирует и воспроизводит видео «за кули­ сами».

)

(2 ) Видео копируется кадр за кадром в (скрытый) буферный c a n v a s и подвергается обработке.

Ц вета оригинального видео Обработка цветов видео с преобра­ зованием их, например, в черно-бе­ лые, в буферном canvas. / З а т е м мы копируем обра­ ботанный кадр из б уф ер ­ ного canvas в canvas о т о ­ бражения. ' Если говорить кратко, то мы берем каждый кадр видео и преоб­ р азуем из цветного в черно-белый, после чего отображаем его.

©

426

глава 8

После того как кадр обработан, он копируется В другой c a n v a s отображения для просмотра.


телевидение для нового поколения

Как обрабаты вать Видео с использованием Временного буфера

3 а сценой

У вас мож ет возникпуть вонрос: ночему мы иснользуем два canvas —для обработки и отображ ения ви­ део. Почему бы нросто не найти снособ обрабаты вать видео н ри его декодировании? М етодика, которую мы здесь иснользуем, является н роверен н ой и н озволяет м иним изировать визуаль­ ные неноладки во врем я интенсивн ой обработки видео и изображ ений: она известна как использование временного буфера. Путем обработки кадров видео в буфере с но следующим конированием их всех сразу в canvas отображ ения мы минимизируем визуальные нроблемы. П ош агово разберемся, как будет работать наша реализация врем енного буфера.

ф

Браузер декодирует видео в серию кадров. Каждый кадр — это прямоугольник с пикселами, который представляет собой мо­ ментальный снимок видео в определенный момент времени. Один кадр видео

(3 } П о мере декодирования каждого из кадров мы копируем его в c a n v a s , который выступает в роли временного буфера.

Целиком копируем кадр в canvas.. ?

^

Временный буфер

дальше ►

427


использование временного буфера

Мы совершаем итерацию по времен­ ному буферу, пиксел за пикселом, передавая на обработку каждый пик­ сел нашей функции e f f e c t F u n c t i o n .

©

После того как все пикселы во вре­ менном буфере будут обработаны, мы скопируем их из временно-бусрерного c a n v a s в c a n v a s отображения.

Как только данные во временном буфере будут обработаны...

...мы извлечем изображение \ из временного буф ерноJ го canvas и скопируем все ^ в canvas отображения.

Затем мы повторяем данный процесс для каждого кадра по мере того, как он декодируется объектом v i d e o . 428

После извлечения пикселных данных из canvas мы обращаемся к ним по одному пикселу зл раз и обра батываем их п у т е м м а н и п у л и ­ рования значениями RGB в случае с каждым пикселом.

глава 8

И конечно же, это будет canvas, который вы р е ­ ально увидите!


телевидение для нового поколения

Реализация временного буфера в canvas Как вы уже знаете, чтобы реализовать врем енной буфер в canvas, нам необходимо два canvas: нервы й, в котором мы будем нроизводить свои вы числения, и второй, где будут отображ аться результаты. Соз­ дание этих двух canvas мы начнем в HTM L-файле videobooth.html. О ткройте данны й файл, найдите там <div> с id в виде "videoDiv" и добавьте два элем ента canvas нод <video>: <div id="videoDiv"> <video id="video" width="720" height="480"></video> <canvas id="buffer" width="720" height="480"></canvas> <canvas id="display" width="720" height="4 8 0 " Ж / canvas> </div>

Mw добавляем два элемента один буфера Ка ' д е РЫ*' “грат ь Роль

О брат ит е внимание, что они будут точно такого же ^

“ ем ен” vide°-

Позиционирование элементов video и canvas У вас мог возникнуть вонрос насчет н озиц и они рован и я данны х элементов; мы собираем ся располо­ ж ить один из них новерх другого. Таким образом, внизу будет располагаться элемент video, новерх него — буферный canvas (buf f е г Canvas), новерх которого в свою очередь будет находиться canvas отображ ения (displayCanvas). Мы воспользуемся CSS, чтобы сделать это; хотя мы не слишком много говорим о CSS в данной книге, если вы откроете videobooth.css, то увидите, как осущ ествляется нози ци он ирован и е этих трех элементов: Элемент <div> с id в виде videoDiv позиционируется о т н о - ^ сительно элемент а, в кот ором он располагается (<div> с id div#videoDiv { в виде console), в г г о пикселах от верха и в г я о пикселах position: relative; ~~ от левой границы, в р е зу л ь т а т е чего он оказывается в ценwidth: 72Opx; '■*------ - т р е элемент а <div> с id в виде console. Д а я w idth и height height: 48Opx; мы задаем значения, аналогичные значениям w idth и height top: 18Opx; элемент а <video> и двух элемент ов <canvas>. left: 190px;

} video { background-color: black;

}

<video> является первым э лем ент ом в <div> с id в виде videoDiv, по эт ом у он автоматически позиционируется вверху слева в <div>. Мы задаем black в качестве значения цвета фона, из-за чего при выводе видео в ТВ -ф о р м а т е Letter Box или Pillar Box полосы по его краям будут черного цвета.

div#videoDiv canvas { position: absolute; top: Opx; left: Opx;

}

К двум э лем ент ам <canvas> в <div> с id в виде videoDiv п р и м е ­ няется абсолютное позиционирование относительно videoDiv (их родительского элемента), поэт ом у, позиционируя э л е ­ м ент ы <canvas> в О пикселах от верха и О пикселах от левого края, мы располагаем их в т о м же м ест е, что и элементы <video> и videoDiv. дальше >

429


реализация обработки кадров

Написание кода для обработки Видео У нас имеется элемент v id eo , а также буфер, которы й является canvas, и еще один canvas, в котором будут отображ аться итоговы е видеокадры. К роме того, эти элементы располагаю тся один новерх дру­ гого, в силу чего мы сможем увидеть только верхн ий canvas отображ ения, в котором будет содерж ать­ ся видео с нрим ененны м эф ф ектом . Д ля обработки видео мы воспользуемся собы тием p la y элемента v id eo , которое инициируется нри запуске во снроизв едения видео. Добавьте данны й код в конец о бработчика onload: \с.0гда видео начнет воспроизЛ водиться, произойдет вызов v i d e o .addEventListener("play", processFrame, false); функции processFrame. В функции processFram e мы будем осуществлять обработку никселов видео и неренос их в canvas для отображ ения. Н ачнем мы с того, что убедимся в наличии достуна ко всем наш им объектам DOM: function p r o c e s s F r a m e () {

var video = d o c u m e n t .g etElementByld("video"); if

(video.paused || video.ended)

{

^

return;

}

■Сначала мы извлекаем объект video... ...и проверяем, продолжается ли все еще воспроизведение видео. Если н е т , то здесь нам больше нечего делать и мы просто выполняем return.

var bufferCanvas = document.getElementByld("buffer"); var di splayCanvas = document.getE 1ementByld ("di splay") var buffer = bufferCanvas.getContext("2d"); var display = displayCanvas.getContext("2d");

Извлекаем ссылку на оба элемент а canvas и ссыл­ ку на их context, которые нам потребуются.

Как создать буфер Д ля создания буфера нам нотребуется взять текущий видеокадр и сконировать его в буферный canvas. Как только он окаж ется в canvas, мы сможем обработать данны е в этом кадре. Таким образом, чтобы создать буфер, мы делаем следующее (добавьте данны й код в нижню ю часть processF ram e): Он п р ини м ает изображение и р и су ет его в canvas в позиции х, у с заданными шириной и высотой. ■ Помните мет од draw lm age объекта context из главы 7?

На э т о т раз мы извлекаем изображение из видео. Мы указываем video как источник, и draw lm age получает один кадр соот вет ст вую щ его видео качестве данных изображения.

b u f f e r .drawImage(video, 0, 0, buffer C a n v a s .w i d t h , b u f f e r C a n v a s .h e i g h t ) ; var frame = b u f f e r .getlma g e D a t a (0, 0, buffer C a n v a s .width, buffer C a n v a s .h e i g h t ) ;

4— (Z З1а т е м мы извлекаем данные ^изображения из context элемент а canvas и сохраняем их в переменной frame, чтобы была воз­ можность их обработать. 430

глава 8

^\ ' Здесь мы просто говорим, что нам т ребуются все данные изображения в canvas.


телевидение для нового поколения

Как обрабаты вать буфер И так, мы но лучили кадр видеоданных, но это му давайте обработаем его! Д ля обработки кадра мы будем соверш ать цикл но каждому никселу в frame.data и извлекать зн ачен ия цветов RGB, содерж ащ иеся в каждом никселе. Вообще-то никсел им еет четы ре значения — RGB и A lpha (н ен розрачн ость), однако мы не станем иснользовать Alpha. Получив зн ачен ия RGB, мы вы зовем effect Function (это функция, о которой мы говорили на с. 426, где нросили вас отложить сведения о н ей у себя в нодсознании!) с ис­ пользованием RGB-инф ормации и кадра. Добавьте данны й код в ниж ню ю часть функции pro cess Frame: b u f f e r .drawlmage(video, 0 , 0 , buffe r C a n v a s .w i d t h , displayCanvas.h e i g h t ) ; var frame = b u f f e r .getIma g e D a t a (0, 0, buffer C a n v a s .w i d t h , displayCanvas.h e i g h t ) ;

var length = f r a m e .data.length / 4;

for

(var i = 0; i < length; i++)

{

var r = frame.data[i * 4 + var g = frame.data[i * 4 + var b = frame.data[i * 4 + if

(effectFunction)

Сначала мы выясняем длину frame.data. Следует о т м е т и т ь , что данные располагаются в свойстве frame — fram e.data, a length является свойством frame.data. На самом деле длина в четыре раза п р е ­ вышает размер canvas, поскольку каждый пиксел им е ет четыре значения (RGBA). Теперь мы совершаем цикл по данным и и з ­ влекаем значения RGB в случае с каждым пикселом. Каждый пиксел заним ает четыре мест а в массиве, поэт ом у мы извлекаем г из первой позиции, g из второй и b из т рет ьей.

{

effectFunction(i, r , g, b, frame.data) ;

} } display.putImageData(frame, 0, 0)

На данном эт апе обработка frame.data уже проведена, поэт ом у мы используем мет од putlm a geP ata объекта context для размещения данных в canvas отображения. Данный мет од при ним ает данные в fram e и записывает их в canvas в указанную позицию х, у.

Мы обработали один кадр, что дальше?

З а т е м мы вызываем effectFunction (если т о л ь ­ ко значением соот вет ст вую щ ей переменной не окажется null, что бывает, когда пользова­ т ель нажимает кнопку "normal"), передавая ей позицию пиксела, значения RQB и массив frame, data, функция effectFunction обновит массив fram e.data, используя новые значения пикселов, обработанные в соот вет ст вии с т е м , какая функция для применения ф и л ьт р а была п р и ­ своена effectFunction.

Да, мы т о л ь к о что обработали один-единственны й кадр и хотим нродолж ать обработку всех кадров, нока будет идти нроцесс воснроизведения видео. Мы можем иснользовать метод setT im eo u t и нередать ему значение 0 миллисекунд, чтобы дать указание JavaScript снова вы нолнить processF ram e так быстро, как это будет возможно. Вообще-то JavaScript не станет вы нолнять функцию через 0 миллисекунд, однако обеснечит для нас самое бы строе следующее врем енное окно. Д ля этого вам пужно нросто добавить данны й код в нижню ю часть функции processFram e: Э т им мы даем иказание JavaScript s e tT im e o u t(p ro c e s s F ra m e f 0 ) ; „ . снова выполнить processFrame т ак быстро, как это будет возможно!

setT im eout аналогичен setlnterval, о>а исключением того, что вы полняется т о л ь ко один раз через заданное время в миллисекундах.

дальше ►

431


частота кадров и таймеры

Интересно, что вы используете setT im eout со значением времени 0. Что там происходит? Не долж ны л и м ы делать что-то привязанное к частоте кадров видео и л и вроде того?

Мы бы хотели, чтобы у нас была такая возможность. Вы абсолю тно правы: нам бы хотелось, чтобы вызов на­ шего обработчика происходил но одному разу в случае с каждым кадром, однако API-интерфейс Video не дает нам это сделать. Он предусматривает собы тие tim e u p d ate, ко­ торое можно использовать для обновления отображ ения текущего времени вашего видео, однако оно не имеет тенденции осуществлять обновление с той детализаци­ ей, которую вы мож ете прим енить нри обработке кадров (другими словами, все будет происходить с более низкой частотой, чем та, которую имеет видео). Поэтому вместо этого мы используем setTimeout. П ере­ давая значение 0 методу setTimeout, вы даете указание JavaScript запускать вы полнение соответствующ его обра­ ботчика так быстро, как это будет возможно. А мож ет ли это происходить бы стрее частоты кадров? Н е лучше ли вы числить врем я ож идания близко к требу­ ющемуся в случае с определенной частотой кадров? Это можно сделать, однако вряд ли обработчик действительно станет вы нолняться строго с частотой, аналогичной часто­ те кадров вашего видео, ноэтому 0 является нодходящ им приблизительны м значением. Если вы стремитесь увели­ чить производительность своего нрилож ения, то, конеч­ но же, всегда сможете нрибегпуть к н роф илированию и вы яснить онтимальны е значения. Но до тех нор, но ка у нас не н оявится более специф ический API-интерф ейс, дело будет обстоять именно так.

432

глава 8


телевидение для нового поколения

Займемся написанием эффектов Н аконец, у нас есть все необходимое для нанисания видеоэф ф ектов: мы извлекаем каждый кадр но мере его ноступления, обращ аемся к fra m e . d a ta никсел за никселом и отнравляем никселы наш ей функции, иснользуемой для н рим ен ен ия онределенного фильтра. Д авайте взглянем на ф ильтр Film n o ir (кото­ ры й в нашем варианте нросто является нричудливым названием черно-белого фильтра): Передаем функции, и с ­ пользуемой для п р и м е ­ нения ф и л ь т р а , п о зи ­ цию пиксела...

...значения пикселов красного, зеленого и синего цвета...

...а также ссылку на массив frame.data в canvas.

m

Таким образом, первое, что мы делаем, — это вычисляем значение brightness для данного пиксела, взяв за осно­ ву все его компоненты (г, b и д).

>>> является function n o i r ( p o s, r , g , b, data) { поразрядным —^ var brightness = (3*r + 4*g + b) » > 3; операт ором, if (brightness < 0 ) brightness = 0 ; который сдви­ гает биты в data[pos 0 ] = brigh t n e s s ; числовом з н а ­ А за т е м присваиваем data[pos 1 ] = brightness ; чении с цельно каждому компонент у data[pos 2 ] = brightness ; его м одиф и­ в изображении canvas дан­ кации. Ъолее ное значение brightness. подробно о \ нем вы с м о ­ Это будет и м е т ь эф ф ект задания жете узнат ь для пикселя значения, обеспечивающего из справочника Помните, что эта от т енки серого, которые с о о т в е т ­ функция будет по JavaScript. с т в у ю т общей яркости пиксела. вызываться по од­ ному разу в случае с каждым пикселом в видеокадре!

7

Tecm-драйв фильтра Film noir Д обавьте нриведенпую выше функцию в файл v id e o b o o th , j s , а затем перезагрузите свою страницу. Как только видео нач­ нет нроигры ваться, наж мите кнонку FILM NOIR, и вы увидите его в м рачном черно-белом варианте. А тенерь снова наж м ите NORMAL. Н енлохо, не нравда ли? И все это на JavaScript, в р е­ жиме реального времени!

Т

Вели задуматься, получается в неко­ т ором роде удивительная вещь. дальше ►

433


упражнение по реализации видеоэффектов

З

озьааи

в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Данная книга не посвящена обработке видео и эффектам, однако это, несомненно, увлекательная тема. Ниже приведены функции western и scifi, позволяющие применять соответствующие эффекты. Про­ смотрите код и напишите справа, как работает каждая из них. Кроме того, мы добавили к ним еще одну функцию — что она делает?

function western(pos, г, g , b, data) var brightness =

{

(3*r + 4*g + b) » >

3;

data[pos * 4 + 0] = brightness+40; data[pos * 4 + 1 ]

= brightness+20;

data[pos * 4 + 2 ]

= brightness-20;

} function scifi.(pos, r, g, b, data) var offset =

{

pos * 4;

data[offset] = M a t h . r o u n d (255 - r)

;

data[offset+1] = M a t h . r o u n d (255 - g)

;

data[offset+2] = M a t h . r o u n d (255 - b)

;

} function bw ca rtoon(pos, r, g, b, outputData) var offset =

pos * 4;

i f ( outputData[offset] < 120 ) { outputData[offset] = 80; outputData[++offset] = 80; outputData[++offset] = 80; } else { outputData[offset] = 255; outputData[++offset] = 255; outputData[++offset] = 255;

} outputData[++offset] = 255; ++offse t ;

434

глава 8

{


телевидение для нового поколения

Большой тест-д р айв о т и все! Мы заверш или работу над кодом, и он готов к отнравке в комнанию S ta rrin g You V ideo. Дважды нроверьте весь код, которы й вы нанечатали, сохраните его и загрузите v id e o b o o th , htm l. Затем развлекитесь, ноиграв со своим новы м нриложением!

В

Реж им S C I-F I

Реж им W E S T E R N

Р еж и м FILM N O IR

дальше ►

435


В ЛАБОРАТОРИИ Мы лишь поверхностно затронули тему обработки видео. Увере­ ны, что вы сможете придумать более креативные эффекты, чем те, которые были продемонстрированы. Придумайте несколько таких эффектов, реализуйте и задокументируйте их здесь. Удалось ли вам изобрести и реализовать что-то по-настоящему классное? Расскажите нам об этом, посетив wickedlysmart.com, и мы продемонстрируем плоды вашего труда другим читателям!

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

436

глава 8


телевидение для нового поколения Я знаю, что м ы почти подош ли к концу главы, однако все же хочу сп р о ­ сить: м ы загружали видео из локал ьного файла, а что изменится, если мое видео будет распола­ гаться в Интернете?

Вам лишь потребуется использовать веб-URL. Вы мож ете подставить веб-URL вместо любого из источников, которы е мы определяли локально. Н апример: <video src="h t t p :/ / w i c k e d l y s m a r t .c o m / m y v i d e o . m p 4 ">

И мейте в виду, что вероятность возникновения проблем более высока, когда ваше видео доставляется через И н терн ет (чуть позже мы поговорим о том, как с ними справляться). Кроме того, битрейт вашего видео начинает приобретать намного большее значение, когда вы доставляете его в браузер или на мобиль­ ное устройство по Сети. Как и в случае с ф орматами видео, если вы реш ите пой­ ти этим путем, общ айтесь со специалистами и занимайтесь самообразованием.

О тлично, и еще один вопрос: есть л и разница между тем, что м ы делаем, и потоковы м видео?

Да, есть, причем большая разница. П онятие «потоковая передача» используется так же часто, как понятие «ксерокс» или «носовой платок», —это общ ий терм ин, означаю щ ий до­ ставку видео из И н терн ета в ваш браузер. «П рогрессивное видео» и «потоковое видео» на самом деле являю тся техническими терминами. В данной книге мы используем прогрессивное видео, а это означает, что когда мы извлекаем видео (локально либо по С ети), мы извлека­ ем соответствующ ий файл с использованием H TTP точно так же, как HTM L-файл или изображ ение, и пытаемся декодировать и воспроиз­ вести данны й файл после его извлечения. П отоковое видео доставля­ ется с использованием протокола, которы й тонко настроен для достав­ ки видео оптимальны м путем (возможно, даже с изменением битрейта видео по мере того, как сниж ается или растет нагрузка на канал). П отоковое видео, вероятно, способно обеспечить для ваших пользова­ телей более качественное взаимодействие (и это правда) и, возможно, является более эф ф ективны м в нлане нагрузки на канал нодклю чения ваших пользователей, а также на ваш канал (что тож е нравда). В допол­ нение ко всему этому н отоковое видео облегчает защиту содержимого видео, если вам нотребуется обеснечить безонасность. дальше ►

437


video streaming

А существует ли стандарт для потокового видео в случае HTM L5?

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

Существует ряд решений. Технологии потокового видео находят массу разумных прим енений, и если вы располагаете обш ирной аудиторией либо содержимым, которое, как вам кажется, нуждается в защ ите, обратите внимание на H TTP Live Stream ing от компании Apple, Sm ooth Stream ing от M icrosoft и H TTP Dynamic Stream ing от A dobe, кото­ ры е станут хорош им отправны м пунктом. Есть и хорош ие новости: ком итет стан­ дартов начинает обращ ать пристальное внимание на потоковое видео на основе HTTP, поэтому следите за разработками в данной области.

438

глава 8


телевидение для нового поколения

Если бы это был совершенный м ир... Однако он не является таковым: мы сталкиваемся с ненриятны м и сетевыми нроблемами, несовместимы ми устрой­ ствами и онерационны м и системами и возрастаю щ ей ве­ роятностью того, что астероиды могут врезаться в Землю. С носледним мы ничего не можем но делать, а что касается нервы х двух, то знание того, что у вас возникла ошибка, — это уже нолдела, носкольку вы тогда, но крайн ей мере, смо­ ж ете что-нибудь нреднринять.

<11II НТК НАСТ У НАС ВОЗНИКЛИ ТЕХНИЧЕСКИЕ ПРОБЛЕМЫ

О бъект video вклю чает собы тие error, инициирую щ ееся но ряду нричин, которы е можно оты скать в свойстве video, error, точнее говоря, в свойстве v i d e o .e r r o r .code. Д авайте взглянем, какие тины ош ибок мы можем обнаруживать.

Ошибки MEDIA ERR ABORTED= 1 Генерируется каждый раз, когда про­ цесс передачи видео по сети отменя­ ется браузером (возможно, по требо­ ванию пользователя).

MEDIA_ERR_NETW/0RK= 2

MEDIA_ERRJ)EC0DE = 3

Генерируется каждый раз, когда передача видео по сети преры­ вается вследствие ош ибки сети.

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

MEDIA_ERR_SRC_N0T_SUPP0RTED = 4 Генерируется, когда указанный источник видео не поддерживается из-за непра­ вильного URL-адреса либо ти п источника не может быть декодирован браузером.

*Каждый muiA. ошибки также об ладает ассоциированным но м е­ р о м j который представляет со­ бой код ошибкиj сгенерированный событием error, о чем мы пого­ ворим через несколько мгновений.. дальше ►

439


обработка ошибок видео

Как использовать события error О бращ ение с ошибками является н енросты м занятием, зависящ им от вашего нрилож ения, а также от того, что окаж ется нодходящ им для вашего н рилож ения и ваших пользователей. По крайн ей мере, мы можем но мочь вам начать и указать нрав ильное нанравление. Возьмем нрилож ение Webville TV и на­ делим его способностью узнавать о том, что оно столкнулось с ош ибкой, —и если оно с н ей столкнется, то выведет для аудитории сообщ ение p le a s e s ta n d by (не меняйте настройки). Мы хотим нолучать уведомление, когда им еет место сообщ ение об ошибке, ноэтому нам нотребуется добавить слушатель собы тий e r r o r . Вот как мы сделаем это (добавьте данны й код в обработчик onlo ad в w e b v ille . j s): video.addEventListener("error", errorHandler, false); Тенерь нам нужно нанисать функцию e rro rH a n d le r, которая будет нроводить нроверку на нредмет ошибок. Если она обнаружит ошибку, то разм естит наше изображ ение с наднисью p le a s e s ta n d by (не меняйте настройки) в области отображ ения видео, сделав его ностерны м:

Когда произойдет ошибка, будет nbllfirtHrt trirnirf-l /ил 10 ir вызвана Antiuwuua функция 0errorHandler.

V

function errorH a n d l e r () {

Если происходит вызов обработчика, м ы удостоверяемся в т о м , что имела мест о ошибка, для чего обращаемся к свойству video.error, а за т е м размещ аем постерное изображение в области отображения видео.

var video = d o c u m e n t .g etElementByld("video"); if

(video.error)

{

video .poster = "images /technical difficulties .jpg" ; alert(video.e r r o r .c o d e ) ;

Kpaui-mecm!

Вы можете опционально добавить дан­ ную ст року, чтобы и м е т ь возможность увидеть код ошибки (см. предыдущую страницу, где рассказывается о цело­ численных значениях, которые р асполага­ ю тся в свойстве code).

Существует много нричин, но которы м воснроизведение видео мож ет ока­ заться неудачным, а для тестирован и я данного кода вы снециально сделае­ те так, чтобы это нроизош ло. Вот ряд советов о том, как это можно сделать: ■ нонробуйте отклю чать свою сеть в разны е моменты воснроизведения видео; ■ введите в нроигры вателе неправильны й URL-адрес; ■ нонробуйте воспроизвести в нроигры вателе видео, которое, как вам будет известно заранее, он не сможет декодировать; ■ иснользуйте нрограм м ное обеснечение для сниж ения нропускной снособности своего канала (оно существует, нужно лиш ь ноискать). И так, наберите данны й код и нроведите тестирование. Вы сможете соноставить целочисленны е зн ачен ия в диалоговы х окнах a l e r t с реальны м кодом, взглянув на коды ош ибок на с. 441. 440

глава 8


телевидение для нового поколения

Куда вы смоЖете отправиться отсюда? Задумайтесь над всем тем, что вы уже умеете делать с номощью HTM L-разметки, элем ента v id e o и, ко­ нечно же, canvas... не говоря уже о веб-службах, API-интерф ейсе G eolocation. Здорово! Мы с вами нровели классную обработку видео с иснользованием canvas, однако вы сможете нрим енить свои знания о canvas и в случае с элементом v ideo. Н иж е нриведены наш и идеи, а вы добавьте к ним свои. И нохвалите себя от нашего имени, носкольку вы это заслужили!

Создавайте основанное на времени содержимое, которое отображается только в определенные промежутки времени при воспроизведении видео. Используйте JSONP для добавления интерактив­ ности! Обеспечи­ вайте режим просмотра «картинка в картинке». Используйте свои стра­ ницы для размещения соответству­ ющей рекламы.

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

Создавайте собственные экранные элементы управления или программные указатели.

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

дальше ►

441


обзор api-интерфейсэ video

КЛЮЧЕВЫЕ "МОМЕНТЫ

ff

» ---

Вы можете воспроизводить видео путем использования элемента < v i d e o > в сочетании с несколькими про­ стыми атрибутами.

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

Атрибут a utoplay обеспечивает запуск воспроизве­ дения видео по окончании загрузки страницы, однако его следует использовать, только когда он уместен.

Метод canPlayType возвращает пустую строку (под­ держка формата отсутствует), "maybe " (если ему, воз­ можно, удастся воспроизвести видео в определенном формате) и "probably" (если он будет уверен в том, что не сможет воспроизвести видео в определенном формате).

Благодаря наличию атрибута controls браузер пре­ доставит пользователю набор элементов управления воспроизведением видео. Внешний вид элементов управления различается в разных браузерах. Посредством атрибута poster вы можете предусмо­ треть наличие своего собственного постерного изо­ бражения. Атрибут s г с содержит URL-адрес видео для воспро­ изведения. Для форматов видео и аудио существует множество «стандартов». Широко применяются три формата: WebM, МР4/Н.264 и Ogg/Theora. Изучайте свою аудиторию, чтобы понять, какие фор­ маты видео вам потребуется обеспечить. Используйте тег <source> для определения альтер­ нативных форматов видео. Используйте полностью определенные типы в сво­ ем теге <source>, чтобы сэкономить силы и время браузера. Вы сможете сохранить поддержку других видеофреймворков, например Flash, добавив резервный тег <ob j ect> в элемент video. Элемент v i d e o предусматривает богатый набор свойств, методов и событий. video поддерживает методы И свойства play, pause, load, loop И mut e ДЛЯ ПрЯМОГО КОНТРОЛЯ НЭД BOC-

произведением видео. Событие ended может использоваться для того, чтобы дать знать, когда воспроизведение видео закончится (например, для реализации плейлиста).

442

глава 8

canvas может использоваться в качестве поверхности отображения для video с целью реализации пользо­ вательских элементов управления и прочих эффектов в случае с видео.

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

Вы можете задать обработчик setTimeout для видео­ кадров; несмотря на то что он не привязывается на­ прямую к каждому кадру видео, это наилучший метод, который имеется на данный момент. Вы можете использовать URL-адрес как источник видео для воспроизведения видеофайлов, размещаемых в Сети. Некоторые браузеры задействуют политику одного источника в случае с видео, так что вам придется загружать свое видео из того же источника, откуда исходит ваша соответствующая страница. В случае с видео возникновение ошибок возможно всегда, особенно когда задействуется Сеть. Событие error может использоваться для уведомле­ ния обработчика, когда при извлечении, декодировании или воспроизведении случаются ошибки. Элемент video полагается на прогрессивно загружа­ емое видео. В настоящее время нет НТ1\/^5-стандарта для потоковой передачи видео, однако комитет стан­ дартов начинает обращать внимание на решения для передачи потокового видео на основе HTTP. На текущий момент не существует стандартного спо­ соба защиты видео, доставляемого посредством эле­ мента video.


телевидение для нового поколения

Щ

Щ

-К ^ С С В о р д

П реж де чем вы откинетесь на снинку стула и захотите еще но смотреть Webville TV, разгадайте небольш ой кроссворд для закренления изученного материала.

По горизонтали

По вертикали

I. Для обеспечения набора видео в форматах, из которых можно будет выбрать подходящий, используйте сразу _____________ элементов s o u r c e . 3. Используется для отображения обработанного видео. 4. Тип буфера, который мы использовали в случае

2. Мы смотрели____________ фильмы 1950-х годов. 5. Внешний вид элементов управления_____________ в разных браузерах. 6. Задействуйте атрибут_____________ , если вам требу­ ются встроенные средства управления видео. С can vas. 8. Что следует делать, если астероид собирается врезаться 7. Тип доставки, который элемент v i d e o использует в Землю? в случае с видео. 12. Клинту Иствуду понравился бы тип видеоэффекта, ко­ 9. Когда воспроизведение видео заканчивается, иницииру­ торый обеспечивается нажатием данной кнопки. ется данное событие. 14. То, что мы обрабатывали при каждом вызове 10. Свойство для воспроизведения видео в зацикленном setTimeout. режиме. II. Запускает воспроизведение видео так быстро, как это только будет возможно. 13. Аудиокодек с открытым исходным кодом. 15. Я могу воспроизвести данный тип видео, а ты? дальше ►

443


решение упражнения

^озьлли в руку карандаш Решение

function western(pos, г , var brightness =

Данная книга не посвящена обработке видео и эффектам, однако это, несомненно, увлекательная тема. Ниже приведены функции western и scifi, позволяющие применять соответствующие эффек­ ты. Просмотрите код и напишите справа, как работает каждая из них. Кроме того, мы добавили к ним еще одну функцию — что она делает? Вот наше решение этого упражнения.

д , b, data)

{

(3*r + 4*g + b)> »

функция для применения фильт ра

3;

data [pos * 4 + 0] = b rightness+40 ;

w estern усиливает компоненты IT (к рас-

data [pos * 4 + 1] = b rightness+20;

Hbiu) U Q (зеленый)пиксела, одновременно

data [pos *

ослабляя Компонент b (синий), Чтобы

4 + 2] = brightness-20;

}

придать видео коричневатый от т енок.

function scifi. (pos, r, g, b, data) var offset =

pos *

функция для применения фильт ра scifi

{

изменяет в обратную ст орону количе-

4;

data [of f set] = M a t h . round (255 -

r)

ство компонентов RGB каждого пиксела.

;

data [ offset+1 ] = M a t h .round (255 - g)

;

TaKUM образом, если пиксел Содержал

data [ offset+2 ] = M a t h . round (255 - b)

;

много красного3 mo т еперь его будет мало. Если же пиксел включал мало з е ­

>

леного, то т еперь его будет много. function bwcartoon(pos, r, g, b, outputData) var offset =

функция для применения фильт ра

pos * 4;

if ( outputData [of f set] < 120 ) { outputData [of f set]

=80;

b w cartoon превращ ает каждый пиксел

с компонентом IT(красный), меньшим

outputData[++offset] = 80;

t-ZO (из 2 5 5 ), в черный, а все ост аль -

outputData[++offset] = 80;

ные пикселы — в белые, придавая видео

} else { outputData [offset] = 255; outputData[++offset] = 255; outputData[++offset] = 255;

} outputData[++offset] = 255; ++offset;

444

{

глава 8

причудливый мультяшный черно-белый вид.



id И В w M ro X H S to

И

я

>

\

\

Safari

Chrome

a

s S о I 2 to to ^ c<

o' I я S

и

Tl N

Firefox

> ?

M obile Webkit

SX.cc DO i.- l s Ob to м

-s I о N

я

Opera

Internet Explorer и выше

• !

о 5 £ ^3 X Si JE s 0 1 I < T X

Internet Explorer

Э Internet Explorer

I



сохран яем

Д ан н ы е Л ^каЛ ьН с

API-интерфейс Web Storage /

Я уже устала от этого ' > тесного шкафа и от то го , что мне приходится носить один и тот же брю чны й костю м. Благодаря HTM L5 у меня будет достаточно места для

одежды, я см о гу каждый день надевать новый костю м!

^

Устали от того, что клиентские данные приходится втискивать в тес­ ные ш кау ы ф айлы cookie? В 1990-е годы такой проблемы не было, однако

сейчас при использовании веб-приложений запросы значительно возросли. Как бы вы отнеслись к тому, если бы мы сказали, что у вас есть возможность выделять по 5 Мбайт на браузер каждого пользователя? Вы, вероятно, подумали бы, что мы шутим. Однако не стоит быть скептичными, поскольку API-интерфейс HTML5 Web Storage как раз позволят это делать! Из данной главы вы узнаете обо всем, что необходимо для сохранения объектов локально на устройстве пользователя и использования их в работе ваших веб-приложений.


история браузерного хранилища

Как работает браузерное хранилище (1 9 9 5 -2 0 1 0 )

За сЦеНои

Создаете электронную корзину? Вам требуется сохранять установки пользователей на своем сайте? Или нросто нужно н рин рятать данны е, которы е долж ны быть ассоциированы с каждым из пользователей? И менно здесь встунает в дело браузерное хранилищ е. Это хранилищ е н озволяет сохранять на постоян­ н ой основе данны е, которы е мы сможем иснользовать в работе своих веб-нриложений. До настоящ его врем ени существовал только один онтим альны й вариант для сохранения инф орм ации в браузере —файлы cookie. Д авайте но смотрим, как они работают.

Когда ваш браузер извлекает веб-страницу, скажем, из pets-R-us.com, сервер может присылать файлы cookie вместе со своим ответом. Файлы cookie содержат одну или более пар «ключ — значение»:

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

1 2

С

Браузер

Браузер сохраняем файлы cookie локально. Он отправим их об­ ратно на сервер, когда будет совершать запрос о следующий раз.

448

глава 9

Веб-сервер

Cookie: pet=dog;

age=5;

Г

' color=black

Содержимое файлов cookie.

Пары «клю ч — значение». У нас имеется ключ p e t со значением dog, а также ключ аде со значением 5 и т. д.


сохраняем данные локально

Когда браузер будет совершать запрос pets-R-us.com в следующий раз, он отправит вместе с ним все файлы cookie, которые были присланы ранее.

В прош лы й раз, когда мы с вами общались, вы прислали мне эти ф айлы cookie. Я отправляю и х вам обратно.

Файлы cookie отправляют­ ся туда-сюда при каждом HTTP-запросе и ответе.

Браузер

Размер файлов cookie

ограничен

*4-Кбайтами

Веб-сервер

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

Благодарим вас. Х отим сообщить, что у нас большая распродажа товаров для собак среднего возраста.

^

Файлы cookie могут использоваться для всевозможных целей вроде настройки пользовательского взаимодействия сохранения данных напримерj в элек­ тронной корзинеj или для поддержа­ ния состояния игры.

,

Браузер

файлы cookie ассоциированы с доменом, нап р и м ер , p e ts-R -u s.co m , и будут о т ­ правляться только в э т о т домен. Таким образом, доВеб-сервер мен PetsEmporium.com никак не сможет получит ь эти файлы cookie.

дальше ►

,

449


как работает web storage

Ш Т У Р М Файлы cookie уже давно у нас под рукой, однако вам, возможно, удастся придумать способ усовершенствовать их. Отметьте флажками те пункты из приведенных ниже, которые, по вашему мнению, делают ис­ пользование файлов cookie проблематичным. |

|

Для работы доступно лишь 4 Кбайта, а моему приложению требуется хранилище большего размера.

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

Похоже, что они являются удобным способом передачи вирусов и прочего вредо­ носного программного обеспечения в мой браузер.

|

|

Мне доводилось слышать, что способ, посредством которого пары «ключ — значе­ ние» включаются в HTTP-запрос, сложно реализовать в коде.

|

|

А разве мы потенциально не отправляем личные данные туда-сюда каждый раз, когда совершаем запрос?

Не похоже, что они хорошо сочетаются с нашей разработкой, связанной с клиент­ ской стороной. Мне кажется, они предполагают, что все будет происходить на сер­ вере. Y)?v?\MWJY)viooFidY)2 K v g w?frir»K?py)dvi кэм снхудк ?н ю icihvvvios?^ oucivogoq ?l>joov iQvvivcp r?oH\Mvdgo ?oo?dv i g о\мь o w i vh ndwiowo?f-\

Я надеюсь, что H TM L5 предусматривает простой A P Iинтерсрейс клиентской стороны для сохранения данны х, которы й обеспечивает и х хранение на постоянной основе в браузере, пред­ лагает больш ий объем хранилищ а и передачу данны х на сервер только в том случае, если я этого захочу.

450

глава 9


сохраняем данные локально

Как работает Web Storage HTML5

сценой Д

И

HTM L5 предусматривает изящ пы й и простой API-иптерф ейс JavaScript в браузере для сохрапепия устойчивы х пар «ключ —зпачепие». К роме того, вы пе будете ограпичепы скудпыми 4 Кбайтами храпилища; в пастоящ ее врем я все браузеры готовы предоставить вам храпилищ е разм ером от 5 до 10 Мбайт, причем в браузере каждого пользователя. Н ТМ Ьб-техпология localStorage также создавалась с учетом веб-прилож епий (и мобильпых прилож епий!); опа озпачает, что ваше п рилож епие сможет сохрапять даппы е в браузере, чтобы спизить объем «общепия» с сервером. Д авайте посмотрим, как все это рабо­ тает (а затем пы рпем в даппы й API-иптерф ейс с головой).

Страница может сохранить одну или более пар «ключ — значение» в локаль­ ном хранилище (localStorage) браузера.

0 ^ Позднее можно будет использовать ключ для извлечения соответству­ ющего значения.

Используя С0° Г р ,_ бетстбук^ ^ значение»

Имея ключ» MW сможем т а к *

л .н о е х р а н и л и щ е .

1л з 6лече> и 3

значение

локального

xpa HwAWiMa Браузер Пара «клю ч — значение»

Браузер

Каждый современу / ный браузер обе­ спечивает локальное хранилище раз­ мером 5 Мбайт (“ ^оле-е!) для каждого домена.

localStorage Хранилище обеспечива­ ет сохранение данных на постоянной основе, даже если вы закроете окно браузера или вообще з а ­ верш ите его р аб от у.

Конечно можно, этим значением будет dog.

ПРИМЕЧАНИЕ: сервер будет продолжать за­ гружать ваши страни­ цы, а вы при этом даже сможете отправить на него немного данных, рас­ полагающихся в вашем локальном хранилище, для localStorage проведения вычислений Как и в случае с файла­ на стороне сервера. Одна­ ми cookies, ваша ст ра ­ ко с деталями локального ница сможет сохранять Хранилища будет р а з­ и извлекать лишь те бираться клиент, а не элементы, которые были сервер (как это обычно сгенерированы страница­ бывает в случае с файла­ ми, исходящими из того ми cookie). же домена. Подробно об этом поговорим позже. дальше ►

451


использование web storage

Зам етка 9АЯ себя... Вам требуется система, чтобы управиться с делами? Сложпо улучшить старую добрую систему заметок-папомипапий (более известную как клейкие заметки). Вы зпаете, как опа работает: вы записы ваете па листке бумаги нупкт «это пужпо сделать», приклеиваете его куда-пибудь и после вы полпепия записаппого вы брасы ваете эту клейкую бумажку в мусорпое ведро.

З а б р а в 6 eiM u

Попробуем создать такую систему с использованием HTML. Н ам потребуется способ сохрапять все эти клейкие замет­ ки, поэтому пам будет нужеп сервер, а также ф айлы cookie... Постойте-ка, вклю чите задпий ход, ведь мы можем сделать все это с помощью API-иптерф ейса HTM L5 Web Storage! S ' A P I -инт ерф ейс Web Storage прост и увлекат елен, работ ат ь с ним - одно удовольствие. Уверяем вас!

нение

из „ , 1лчне|1л <^коЛ -оЗУ *'

Не будем валять дурака, а сразу приступим к использованию локального хранилища. Для этого вам потребуется создать простую HTML-страницу с базовыми элементами: <head>, <body> и <script> (либо ВЫ можете просто воспользоваться файлом no t e t o s e l f . h t m l в примерах кода). Следуйте за нами и наберите в своем элементе <script> приведенный далее код (ввод кода способствует запоминанию материала): На клейкой заметке присутствует лишь текст, который вы напи­ сали, не так ли? Поэтому давайте сначала сохраним эту заметку (sticky) ДЛЯ "Pick up

dry cleaning" ("Забрать

химчистки"):

A P I - ин терф ей с Web Storage будет доступен посредством обьекта localStorage. Вы увидите, что браузер уже определил его за вас. Применяя его, вы используе­ т е основную сист ему локального хранения,

fs"

Метод set Item принима ет две строки в каче­ стве а р гум ент ов, кото рые играю т роль пары «клю ч — значение».

/

^

localStorage. set Item ("sticky_0 ’’

Чтобы сохранить чтот о , мы используем мет од setltem.

П с ‘/ ^

~ 452

глава 9

вещи

\

Вы сможете сохранять только элементы т ипа string. Напрямую сохра­ нять числа или объекты нельзя (однако мы вскоре найдем способ обойти это ограничение).

Pick up dry c l e a n i n g " ) ;

\

‘7 ° Т й

s : i ^

из

Мы начина­ ем с простого, однако прежде, чем вы осознаете это, у нас уЖе будет целое р а ­ ботающее п р и ­ ложение Stickies.

: z z r

Второй строковый аргум ент является значением, которое вы хо т и т е сохранить в л о ­ кальном хранилище.


сохраняем данные локально

О

Предыдущее действие было довольно простым. Давайте добавим второй элемент в локальное хранилище: l o c a l s t o r a g e . s e t I t e m (" sticky_l", "Cancel cable tv, who needs it now?");

Рше один «Люч. К ак м ь I уже говорили, у вас есть Кпъллпжность использовать для ключа любое и м я ,

Значение, которое будет соот вет ст воват ь нашему

^ с к о л ь к у он является ст рока*. сохранять только одно значение на каждый ка

^

4 ^

^

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

Извлекаем значение, ассоциированное с ключом «stickyjD », из локального хранилища... ...и присваиваем его ^ переменной sticky.

^

var sticky = l o c a l S t o r a g e .g e t l t e m (" s t i c k y _ 0 ");

Чтобы все стало еще интереснее, используем ф у , нкцмю alert для вывода на экран значения sticky.

alert (sticky) ;

Время тест-д р айв а! Убедитесь, что вы папечатали весь приведеппы й чуть выше код в своем элемепте < s c r i p t > , H загрузите его в своем браузере. Вот результат пашего тест-драйва: диалоговое J a v a S c r ip t -о к н о Это наше sticky О в качестве alert со значением предупреж даю щ его сообщения.

J a v a S c rip t Pick up dry cleaning

(

)

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

К.

Ладно-ладно, мы согласны, что пример мог бы быть более захватывающим... Однако ост авай­ тесь с нам и, поскольку скоро т ак и будет...

дальше ►

453


как работает ар 'ьинтерфейс localStorage

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

О о

Разумеется. Кратко о том, как обстоят дела: браузер обеспечивает для вас локальное хран и ­ лищ е —область на вашем компью тере, в вашем браузере, — которое страница мож ет исполь­ зовать для сохранения пар «ключ —значение». Вы создаете несколько пар «ключ — значе­ ние», сохраняете их, используя API-интерфейс localStorage, а затем извлекаете одну из них для использования в своем прилож ении. Н е­ смотря на то что это, может, и не самый за­ хваты ваю щ ий прим ер, существует масса и нте­ ресны х вещ ей, которы е вы сможете сделать, используя хранилищ е в браузере каждого из пользователей (и мы уверены, что вы сможете придумать по крайней мере несколько таких ситуаций). А теперь подробпо разберем ся в том, что толь­ ко что произош ло.

Во-первых, помните, что каждый браузер располагает локальным хранилищем, которое вы можете исполь­ зовать для сохранения пар «ключ — значение».

Каждый современный ^ ^ д р а у з е р располагает локальным хранилищ ем «за кулисам и» , г о т о ­ вым к использованию вами для сохранения пар «клю ч — значение». localStorage

Браузер 454

глава 9


сохраняем данные локально

Используя данное локальное хранилище, вы можете взять ключ и значе­ ние (которые будут представлять собой строки) и сохранить их там. localStorage.setltem("sticky_0"

" P i c k u p d r y c l e a n i n g 11)

Т

Используем м ет од setltem для со­ хранения пары «клю ч — значение». К лю чом будет "sticky_Ou, а значе­ нием — "Pick up dry cleaning" ("За­ брать вещи из химчистки").

/ v C|eaning-

Пара «клю ч — з н а ­ чение» , сохраненная посредством вызова метода setltem.

При помещении пары «ключ — значение» в localStorage она сохранится т а м , даже если вы закроете окно браузера, вообще заверш ит е работу браузера или перезагрузите

\ localStorage

компью тер.

Затем мы снова вызвали setltem и сохранили вторую пару «ключ — значение», куда на этот раз входит ключ "sticky i" и значение "Cancel

cable

tv,

на кабельное ТВ,

who

needs

it

n o w ? " ("Отказаться

от

подписки

ведь кому оно теперь нужно?").

l o c a l S t o r a g e . s e t l t e m ( 11s t i c k y _ l 11, " C a n c e l c a b l e tv,

w h o n e e d s i t now?")

Теперь у нас есть два уникальных значения, сохраненных под двумя уникальными ключами^

И когда

вызовем метод getltem, указав при этом ключ вернет значение, имеющееся в соответствующей паре «ключ — значение». МЫ

"sticky o", он

l o c a l S t o r a g e .g e t l t e m (" s t i c k y _ 0 " ); 6 о 3 6

р а ^ е1ЛЛ

“Pick up dry cleaning”

g e tlte m находит э лем ент с ключом ".sticky_0" (при наличии такового) и возвращает его значение.

localStorage

Следует о т м е т и т ь , ч т о , извлекая элем ент , мы не удаляем его из х р а ­ нилища (он по-преж нему ост ается там). Мы лишь извлекаем значение, соот вет ст вую щ ее определенному ключу. дальше ►

455


вопросы о локальном хранилище

Част°

Задаваем ы е Боцрось! «Web Storage» и локальное хранилище — это одно и то же?

ft

0 : Веб-стандарт называется Web Storage, однако большинство людей просто называют его локальным хранилищем (фактически, браузеры как раз и предоставляют данный API-интерфейс посред­ ством объекта localStorage). Web Storage — не самое удачное название для стандарта (поскольку элементы сохраняются в вашем браузере, а не в Интернете). Тем не менее мы придерживаемся его. Вы увидите, что мы будем использовать термин «локальное хранилище» чаще, чем название стандарта Web Storage.

Насколько широко поддерживается API-интерфейс Web Storage? Можно ли рассчитывать на такую поддержку? 0 : Да, можно. На самом деле это один из наиболее поддер­ живаемых API-интерфейсов, даже в версиях вплоть до Internet Explorer 8, причем на текущий момент — в большинстве мобиль­ ных браузеров. Кое-где имеются предостережения, и мы обратим на них ваше внимание. В плане поддержки Web Storage вам, как всегда, следует провести тест, прежде чем пытаться использовать данный API-интерфейс. Вот как можно проверить, поддерживается

Л И localStorage:

0 : В других технологиях, позволяющих сохранять данные в браузере, нет ничего плохого, однако локальное хранилище HTML5 сейчас является стандартом (Google, Apple, Microsoft и прочие компании считают Web Storage стандартным инструментом для сохранения содержимого локально в браузере).

&

Что произойдет, если я вызову setltem в отношении од­ ного и того же ключа несколько раз? Скажем, дважды вызову setltem в отношении «sticky_1». В итоге в локальном хранилище у меня окажутся два ключа «sticky_1»?

0 : Нет. Ключи являются уникальными в localStorage, по­ этому set item будет перезаписывать первое значение вторым. Например, если вы выполните этот код: localStorage.setltem("sticky_l", "Get Milk") localStorage.setltem("sticky_l", "Get Almond Milk") var sticky = localStorage.getltem("sticky_l") значением sticky будет "Get A l m o n d Milk".

Кто сможет сохранять данные в моем локальном хра­ НИЛИ нилище?

f t

0:

Обратите внимание, что при тестировании мы выясняем, имеется ли у глобального объекта w i n d o w свойство localStorage. Если оно присутствует, то мы будем знать, что браузер поддерживает

Управление локальным хранилищем осуществляется в со­ ответствии с источником (вы можете рассматривать источник как свой домен) происхождения данных. Таким образом, к примеру, каждая страница wickedlysmart.com сможет «увидеть» элементы, сохраненные другими страницами на этом сайте, однако код с других сайтов, скажем, с google.com, не будет иметь доступа к данному хранилищу (он сможет получить доступ только к элементам

localStorage.

в своем собственном локальном хранилище).

if (window["localStorage"] ) { // your localStorage code here.

}

5

=В самом начале главы вы упоминали о 5 Мбайтах хранили­

ща eв каждом браузере. Это общий объем, который приходится

В.

Когда я загружаю страницу со своего компьютера, как мы этод это делали в упражнениях, что является моим источником?

на в все приложения?

0 :

Нет, по 5 Мбайт приходится на каждый из доменов.

Т5-

| у * Вы сказали, что участие сервера не требуется, а потом начали вести разговор о доменах.

0 : Все верно, поскольку управление хранилищем полностью осуществляется на стороне клиента. Домен вступает в дело потому, что 5 Мбайт хранилища выделяются всем страницам, исходя­ щим из одного и того же домена. Pet-R-Us.com получает 5 Мбайт, PetEmporium.com — еще 5 Мбайт и т. д., на всех ваших компьютерах.

TJJi *-

А если сравнить данный механизм с Google Gears (или с другой технологией локального хранения данных)?

456

глава 9

0 ::

! Хороший вопрос. В данном случае вашим источником будет Local Files {локал ьн ы е ф айлы ), и он отлично подходит для про­ ведения тестирования. Если у вас будет доступ к серверу, где вы также сможете протестировать свои файлы, то тогда источником будет соответствующий домен.

Локальное хранилище не будет функционировать должным об­ о£-Щор>оЖНь1 , разом, если вы используете file://.

])удыпе

Э т о е щ е один случай , ко гд а н еко т о­ р ы е б р а у зе р ы т р еб ую т , чт обы вы загруж али с во и ст ран и ц ы , и сп о л ьзуя lo ca lh o st:// или о н л а й н -с е р в ер , а н е д е л а л и э т о из ф а й л а . Е сл и ваш и к л ей к и е з а ­ м ет ки н е б удут р а б о т а т ь , п р и б е гн и т е к з а г р у зк е с с е р в е р а или в о с п о л ьзу й т е с ь др уги м б р а узер о м .


сохраняем данные локально Итак, я м о гу сохранять данные в localStorage. А если потре­ буется сохранить числовое значение? Я полагал, что см о гу использовать localS torage для сохранения целочисленны х значений ито го в о го количества элемен­ тов и цен с плавающ ей точкой для такого приложения, как электронная корзина, кото­ рое хочу написать. Та л и это техн о ло ги я, которая мне требуется?

Это именно та технология, которая вам нужна. Верно, в ситуации с localStorage вы сможете использовать только строки в качестве клю чей и значений. Однако здесь все не настолько ограничено, как может показаться. Допустим, вам нужно сохранить целочисленное значение 5. Вы можете вместо этого сохранить строку «5», а затем преобразовать ее об­ ратно в целое число при извлечении из локального хранилищ а. П осмотрим, как это можно сделать в случае с целочисленны ми значениями и значениями с плавающей точкой. Скажем, вам требуется сохранить целочисленное значение с ключом "numitems". Для этого вы написали бы следующее: Разве мы н е говорили, что localStorage . setltem( " n u m i t e m s " , 1 ); сохранять целочисленные значения нельзя? М ожет показаться, что здесь вы сохраняете целочисленное значение, одна­ ко JavaScript знает, что это должна быть строка, поэтому преобразует за вас данное значение в строку. В действительности s e t l t e m увидит строку " 1 ", а не целое число. Однако JavaScript окажется не так умен, когда вы будете из­ влекать значение с помощью getltem: var numitems = l o c a l S t o r a g e .g e t l t e m (" n u m i t e m s ");

ОЭЛЬ

В даппом коде мы присваиваем numitems строку " 1 ", а пе целочислеппое зпа­ чепие, как бы пам хотелось. Ч тобы numitems было числом, потребуется примепить JavaScript-фупкцию p a r s e l n t для п реобразования строки в целое число: Обертываем значение в вызов p arselnt, ^ — что преобразует ст року в целое число. var numitems = p a r s e l n t ( l o c a l S t o r a g e .g e t l t e m ("numitems ")); numitems = numitems + 1;

Mы можем прибавить X к н е м у , поскольку это число.

l o c a l S t o r a g e .s e t l t e m (" n u m i t e m s ", n u m i t e m s )

__ З а т е м МЫ опять сохраняем его, при э т о м Ja v a S c rip t снова обеспечит преобразование.

Если вы будете сохрапять зп ачеп ия с плаваю щ ей точкой, то взамеп вам п отре­ буется использовать фупкцию parse Float при извлечепии элемептов price из localStorage: Здесь все то же самое-, мы сох р ан яе м значение с п л а ва­ ющей т о ч к ой, к о т о р о е пре localStorage .s e t l t e m ("price" , 9.99) ; о б р а з у е т с я в Строку. var price = p a r s e F l o a t ( l o c a l S t o r a g e .g e t l t e m ("pr i c e " ));

И преобразуем э т у ст року обратно в значение с плавающей точкой с помощ ью parseFloat.

--------- >7

дальше ►

457


чем локальное хранилище схоже с массивом

Были ли локальное хранилище и массив разделены при роЖдении? Локалыгое храпилищ е им еет и другую сторону, которой вы еще пе видели. localStorage пе только предусматривает методы получателя и установщ и­ ка (то есть g e t l t e m n setltem), по также позволяет обращ аться с объектом localStorage как с ассоциативпы м массивом. Ч то это озпачает? Вместо того чтобы использовать метод setltem, вы сможете п рисвоить ключу зпачепие в храпилищ е, как показало далее:

массие

localStorage [" s t i c k y _ 0 " ] = "Pick up dry cleaning";

S " Здесь ключ выглядит как индекс для массива хранения. 0 г

\\ А

вот наше значение, р а сп о л а ™ " Р * 6 у " сторону от оператора присваивания.

Используя даппы й подход, мы также можем извлечь зпачепие, сохрапеппое в ключе: 4^ var sticky

= localStorage [ "sticky_0 " ] ;

т

Это работ ает точно т ак же, как ис~ пользование вызова метода qetltem.

f

Присваиваем н а шей переменной sticky...

значение ключа "sticky-О в локальном хранилище,

Н еплохо, правда? Таким образом, вы мож ете прим епять лю бой сиптаксис, поскольку опи оба допусти­ мы. А если вы привы кли использовать ассоциативпы е массивы па JavaScript, то даппы й сиптаксис мо­ ж ет показаться вам более компактпым и удобочитаемым.

ПодоЖдите, это еще не все! API-иптерф ейс localStorage предусматривает еще два иптереспы х ипструмепта: свойство le n g th и ме­ тод key. Свойство le n g th содерж ит количество элемептов в локальпом храпилищ е. А что делает метод key, вы мож ете увидеть чуть пиже: 4 л 1Лл. #_1л ./ Общая ка р т и на : мы используем length Свойство length, позволяет для осуществления итераций по с о О сущ ест вляем ит ерацию у 3натЬ) сколько элемент ов держимому localStorage (как в случае по каждому элементу. содержится в localStoraae с Maccu®0M) и обращаемся к каждому | ключу (например , ”sticky_0") по коду V V процесса. Зат ем мы сможем испольfor (var i = 0; i < l o c a l S t o r a g e .length; i++) { 3овать данный КЛЮЧ для извлечения var key = localStorage.key(i) ; соот вет ст вую щ его значения. = localStorage [key] ; . (val^ue) ;

var value

}

alert

Проведите т е ст и п о с м о т р и т е , выводится ли на экране диалоговое окно alert относительно каждого из элементов? 458

глава 9

^ ЛЯ каж^ого элемент а в localStorage м ет од key дает нам определенный ключ ("sticky О", "Sticky_l" и т. д.). З а т е м с помощ ью имени ключа мы сможем извлечь с о о т в е т ст вую щ ее значение.


сохраняем данные локально

Чаапо Задаваем ы е B olIpoC bX Если я стану осуществлять итерации по localStorage с использованием localStorage.length и localStorage.key, то каким при этом будет порядок элементов? Таким же, каким я записывал их в хра­ нилище?

f t

ч

0

: Вообще-то

порядок элементов не является опре­

деленным. То есть вы сможете увидеть каждую пару «ключ — значение» в хранилище посредством соверше­ ния итераций, однако не следует при этом рассчитывать на какой-то определенный порядок в коде. Фактически разные браузеры могут предусматривать различный порядок для одного и того же кода и элементов.

И г р а в скорлупки

с

Готовы испытать удачу (или, скорее, сноровку)? Данная игра позволит проверить, насколько хорошо вы знаете localStorage, однако вам потребуется проявить решительность, Используйте свои знания об извлечении и сохранении пар «ключ — значение» в localStorage, чтобы уследить за горошиной, когда она будет перемещаться от одной скорлупки к другой. function shellGame()

Можете использовать это прост ранст во для отслеживания сост оя­ ния localStorage.

{

l o c a l S t o r a g e .s e t l t e m (" s h e l l l " , " p e a " ) ; l o c a l S t o r a g e .s e t l t e m (" s h e l l 2 ",

"empty");

l o c a l S t o r a g e .s e t l t e m (" s h e l l 3 ",

"empty");

localStorage["shelll"]

= "empty";

localStorage["shell2"]

= "pea";

localStorage["shell3"]

= "empty";

var value = l o c a l S t o r a g e .g e t I t e m (" s h e l l 2 "); l o c a l S t o r a g e .s e t l t e m (" s h e l l l " , v a l u e ) ; value = l o c a l S t o r a g e .g e t l t e m (" s h e l l 3 "); l o c a l S t o r a g e [" s h e l l 2 "] = value; var key = "shell2"; localStorage[key]

= "pea";

Под какой скорлупкой находится горошина («реа»)? Свой о т в е т напиш ите здесь•

key = "shelll"; localStorage[key]

= "empty";

key = "s h e l l 3"; localStorage[key]

for

= "empty";

(var i = 0; i < localStorage.length;

i++)

{

Клю ч

Значение

var key = l o c a l S t o r a g e .k e y ( i ) ; var value = l o c a l S t o r a g e .g e t l t e m ( k e y ) ;

s h e lll

alert(key + ":

slnellZ

" + value);

she Из н а т ь т1 Т 5ратЬ Эт°' 4Mo6bl пР ° ^ р и т ь свой о т в ет и ч з ~ m*, под какой скорлупкой будет находиться горошина

дальше ►

459


беседа технологий хранения данных

Беседа у камина

У ч а стн и к и сегодняшнего разговора: ф айлы cookie и локальное хранилище Сегодня мы станем свидетелями разговора текущей распространенной технологии хранения данных в браузере, называемой «файлы cookie», и новым кандидатом на лидерство, имя которого «локальное хранилище».

Ф айлы cookie:

Л окальное хранилищ е:

А вот и паш «золотой мальчик» — локальпое храпилищ е. Мы в этом деле уже более десяти лет, и Вы думаете, что мож ете вот так просто добиться успеха? Да у Вас еще молоко па губах пе обсохло! К опечпо, па это можпо и так посмотреть либо сказать, что я создало па оспове опыта, извлечеппого из ваших ошибок. Да Вы хоть имеете представлепие о том, со сколь­ кими страпицами мы используемся? А п а свою статистику Вы когда-пибудь смотрели?

Эй, мы вездесущи, повсеместпы, пас можпо встре­ тить везде! Мы пе думаем, что в пастольпом или мобильпом сегмепте существует браузер (певажпо, пасколько старой оп версии), где пельзя было бы пас пайти.

Это мы еще посмотрим. А что имеппо Вы мож ете предлож ить сверх того, что можем предлож ить мы? Мы прекраспо обеспечиваем храпепие даппых.

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

Я быстро догопяю вас по популярпости. С ре­ ди всех техпологий HTM L5 я являю сь одпой из паиболее хорош о поддерживаемых.

Ч то ж, я пе уверепо, что хочу упомипать об этом па нублике, по у вас проблем ы с объемом.

Мы п опятия пе имеем, о чем Вы здесь говорите. Эй, вы сами это пачали, а пе я. Вам отличпо известпо, что вы ограпичепы 4 Кбайтами храпилищ а, а в моем случае опо более чем в 1 2 0 0 раз больше!

460

глава 9


сохраняем данные локально

Ф айлы cookie: Мы легки, проворпы , можпо даже сказать, гибки.

Да бросьте, мы как откры тая кпига —простое храпилищ е, в которое можпо поместить все, что вам потребуется.

Л окальное хранилищ е: Вот это забавпо. Вы когда-пибудь общались с разработчиками? Вы какие угодпо, по толь­ ко пе гибкие. У вас, если вы так лю бите ста­ тистику, есть даппы е о количестве часов, ко­ торы е разработчики п отеряли из-за глупых ош ибок и заблуждепий при использовапии файлов cookie?

Н а самом деле у вас, по сути, отсутствуют какие-либо ф орм аты даппых, из-за чего разра­ ботчикам приходится запово изобретать схе­ му сохрапепия ипф орм ации в файлах cookie.

А разве пары «ключ — зпачепие» являю тся каким-то большим повшеством? Нужды в каких-либо больших повш ествах в храп еп и и даппы х пет; пары «ключ — зпаче­ пие» прекраспо работают, опи просты и под­ ходят для мпогих вы числительны х прилож е­ ний. <Хихикапье> Ах, да, Вы же сохрапяете все в виде строки! О тличпая работа! </Х и хи капье>. И з строк можпо извлечь мпого пользы, а если вам потребуется что-то более сложпое, то для этого есть соответствующ ие нути. Да, да, позовите мепя через десять лет, и мы посмотрим, выдерж али ли Вы проверку времепем. О, будьте уверепы. П осм отрите правде в гла­ за: вы с самого пачала были обречепы . Кто захочет пазвать своих детей в вашу честь? Вы увидите, как еще будете в слезах звать мепя, когда Вам скажут: «Ха-ха, пять мега­ байт —и это все, что у Вас есть?». дальше ►

461


приложение для работы с клейкими заметками

Серьезно о клейких зам етках Итак, вы пемпого поиграли с Web Storage, а теперь продолжим пашу реализацию . Мы создадим прилож епие N ote to Self для работы с электроппы м и клейкими заметками, чтобы вы смогли увидеть свои заметки и добавить к пим повые. П осмотрим, что мы собираемся сделать, п ре­ жде чем приступим к работе.

Нам нужен способ добавления новых клейких заметок. Поэтому мы создадим форму с полем ввода

Наше приложение Note to Self будет отображать клей­ кие заметки, сохраненные g localStorage, а также позволит нам добавлять новые заметки,

икнопкой.

Я ^ Г> Note to Self I *• ►| + J0hr.p/jIcq.iosiv-Bcih/Hcad -irsi HTVLSKhasiersrnoiEicso'i’it/nl

При щелчке на кнопке Add Sticky Note to Self (Доба­ вить клей­ кую замет­ ку для себя) в localStorage будет до­ бавляться заметка.

Мы также уви­ дим появление новых клейких заметок на экране, что будет происхо­ дить благодаря добавлению но­ вого элемента в объектную модель доку­ мента (РОМ) для каждой за­ метки. 462

глава 9

localStorage

Если у нас в хранилище уже будут заметки, то мы хо­ тим, чтобы они отобража­ лись на экране после загрузки страницы. Как, например, эти две заметки, которые уже у нас есть.

__ J

(Add Sticky No:c то Self j

Pick up dry

Cancel cable tv, who needs it now?

cleaning

Как вы помните, ключами для этих двух заметок являются sticky_0 и "stickyЛ ". Мы будем придерживаться нашего соглашения и создадим ключи для заметок, используя целые числа с воз­ растанием: sticky_Z, sticky т. д.

"

"

м

Дляотобра­

жения заме­ ток мы будем совершать итерации по всем заметкам в localStorage и добавлять их в объектную модель докумен­ та (РОМ).

Мы стилизуем электронные клейкие заметки с использова­ нием CSS, чтобы они были по­ хожи на настоящие листочки!


сохраняем данные локально

Создание интерфейса Для пачала пам пеобходимо пайти способ вводить текст клей­ ких заметок. И было бы здорово, если бы мы могли видеть их па страпице, поэтому пам потребуется элемепт, в котором будут содерж аться все заметки, отображ аемы е па страпице. Н апиш ем соответствующ ий код, пачав с HTM L-разметки. О т­ кройте свой HTM L-файл и добавьте элем епт <form>, элем епт <ul> и CSS-ссылку п а пего, как показало пиже:

Вот наш основной HTML-ф айл

/

< ! doctype html> <html> <head> <title>Note to Self</title>

Mw добавили небольшое количество CSSj чтобы наши электронные з а ­ м е т к и выглядели более похожими на настоящие листочки. Эта книга не посвящена C SS, но вы можете з а ­ глянут ь для справки в данный файл!

Cmeta c h a r s e t = " u t f -8"> <link r e l = ffstylesheet" href = " n o t e t o s e l f .c s s "> <script s r c = " n o t e t o s e l f .js"></script>

. Поместим весь наш Ja vaS crip t-код в файл notetoself.js.

</head> <body> <f orm>

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

< input type="text" i d = " n o t e _ t e x t "> < input t y p e = " b u t t o n " id="add_button" v a l u e="Add S ticky Note to Self"> </form>

<ul i d = " s t i c k i e s "> < /ul> </body> </html>

^4 Благодаря CSS каждый э лем ент списка будет выглядеть более похожим на записку -напоминание.

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

дальше ►

463


написание javascript-кода для заметок

Теперь добавим JavaScript У пас уже есть все пеобходимое па страпице, а также п ара клейких заметок в localStorage, ожидающих своего отображ епия. Д авайте сделаем так, чтобы опи появились па страпице, для чего спачала считаем их из localStorage, а затем поместим в пеупорядочеппы й список (элемепт <ul>), которы й мы только что создали: ...которая счит ает осе с у щ е­ Когда страница загрузит ся, ст вую щ ие клейкие зам ет ки мы вызовем функцию (n i t .. из localStorage и добавит их в <ul> посредством РОМ. wi n d o w . o n l o a d = init;

function i n i t () for

Д ля этого мы будем осущ ест влят ь итерации по всем элем ент а м в хранилище.

Г

{

(var i = 0; i < l o c a l S t o r a g e .length;

i++

var key = l o c a l S t o r a g e .k e y (i ) ; if

(key.s u b s t r i n g (0,

6) == "sticky")

{

var value = l o c a l S t o r a g e .getltem(key) addStickyToDOM(value);

}

' V Если это клейкая за м е т к а , то мы извлекаем ее значение и добавляем на нашу страницу (посредством РОМ).

И так, теперь пам пеобходимо паписать фупкцию которая будет вставлять заметки в элемепт <ul>:

function addStickyToDOM(value)

Извлекаем каждый ключ. А за т е м убеждаемся, что данный элем ент является за м е т к о й , п у т е м проверки, начинается ли его ключ со "sticky". Зачем мы это делаем? Что Ж, в localStorage м о г у т находиться и другие э л ем е н ­ ты помим о наших клейких зам ет о к (подробнее об эт о м мы поговорим позже).

addStickyToDOM,

Нам передается т е кс т заметки. Необ­ ходимо создать элем ент неупорядочен­ ного списка, а за т е м вст авит ь его.

{

var stickies = d o c u m e n t .getElementByld (" s t i c k i e s "); ^-var sticky = d o c u m e n t .c r e a t e E l e m e n t (" l i " ); var span = d o c u m e n t .c r e a t e E l e m e n t (" s p a n " ); span.setAttribute("class",

"sticky") ,

span.innerHTML = value; s t i c k y .a p p e n d C h i l d ( s p a n ) ; s t i c k i e s .a p p e n d C h i l d ( s t i c k y ) ;

464

глава 9

Извлечем элем ент <ul> с id в виде "stickies". Создаем элем ент списка и присваиваем ем у имя класса sticky" (чтобы его можно было стилизовать).

Задаем содержимое span, где находится т е кс т заметки. И добавляем span в элем ент списка "sticky"j который, в свою очередь, добав­ ляем в элем ент <ul> с id в виде "stickies".


сохраняем данные локально

Время еще одного mecm-gpauBa! Н аберите приведеппы й выше код в своем элемепте < s c r ip t> и загрузите его в браузере. Вот что получилось у пас, когда мы загрузили страпицу в браузере: Мои 10 Self

О ГЛ О [А *1 +

г;юа.м<ш/-eeth/Hcad -1гл HTVLS/ctooiciS'noincce'nuTil

d ip

('лад sackv noic 10 srtfj

Cancel cable tv, who needs it now?

Pick up dry cleaning

Завершаем создание интерфейса пользователя О сталось лиш ь активировать форму, чтобы у пас появился способ добавлять повы е заметки. Д ля этого пеобходимо добавить обработчик, которы й будет вы зы ваться п ри щ елчке па кпопке A dd Sticky N ote to Self (Добавить клейкую заметку для себя), а также паписать код для создапия повой заметки. Вот паш код для добавлепия обработчика: Извлечем ссылку на к н о п ­ ку A d d Sticky Note to Self Добавьте э т о т новый код (Добавить клейкую з а ­ в свою функцию init: м е т к у для себя). f u n c tio n i n i t () { у/ var button = document.getElementByld("add_buttonn) button, onclick = creates ticky;

^___________

/ / f o r lo o p goes h e re Остальная часть кода в init будет такой же, как раньш е, мы просто экономим м ест о, не п р и ­ водя ее здесь повторно.

И добавим обра­ ботчик., который будет вызываться при ее нажатии. Д а нном у об­ работчику мы присвоим имя createSticky. дальше ►

465


создание заметок с помощью кода

А вот код для создапия п овой клейкой заметки: _______ Данный обработчик ^ будет вызываться при function createsticky о { щелчке кнопкой мыши.

Сначала происходит изв лечение т е к с т а , введенного в поле ввода формы.

var value = document.getElementByld("note_text") .value; var key = ,,sticky_11 + localStorage.length; localStorage.setltem(key, v a l u e ) ;

addstickyToDOM (value);

% И наконец, добавляем новый т екст в объект ную модель документа для пр едст авле­ ния клейкой заметки.

U еще один те ст-д р а й в !

Д а лее мы добавля­ ем новую за м е т к у в localStorage с использо­ ванием нашего ключа.

З а т е м нам нужно создать уникальный ключ для заметки. Воспользуемся "s tic k y j', к о н­ катенированным со значением length всего локального х р а н и ­ лища; оно продолжит ув е л и ч и ­ ват ьсяj не т ак ли?

Теперь вы можете от правлят ься в п ут еш ест вие на фиджи, а когда

Обязательно попробуйте закрыть окно браузера, а за т е м сова о т кр ы т ь его. Ну как, вы по-преж нему видите свои замет ки? 466

глава 9


сохраняем данные локально

4acm°

^адаВ аеМ ы е B o llp o C b l

Т5 JJ *-

Зачем нам проводить проверку для того, чтобы узнать, начинается ли ключ каждого из элементов со строки "sticky"?

Т5y j • Я всего лишь перезагрузил страницу, и теперь мои заметки располагаются в другом порядке!

0 : Как вы помните, все страницы из одного домена (например,

0 : Когда вы добавляете новую заметку, ее элемент добавляется

apple.com) смогут «увидеть» любой элемент, сохраненный другими

путем внедрения его в список заметок, поэтому такой листок всегда

страницами в этом домене. Это означает, что если мы не будем

будет оказываться в конце списка. Когда вы перезагружаете стра­

внимательно подходить к присваиванию имен нашим ключам, то

ницу, заметки добавляются в том порядке, в котором они обнару­

можем вступить в конфликт с другой страницей, которая использует

живаются в l o calStorage (а как вы помните, определенный

аналогичные ключи иным путем. Таким образом, это наш способ

порядок расположения элементов здесь не гарантируется). Вы

убедиться в том, что элемент является заметкой (а не, к примеру,

могли бы подумать, что порядок будет таким же, в каком элементы

порядковым номером или игровым уровнем), прежде чем мы ис­

добавлялись в хранилище, либо они окажутся в каком-то другом

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

обоснованном порядке, однако рассчитывать на это нельзя. По­ чему? Причина заключается в том, что соответствующая специ­

Т5 JJ *-

А что, если в localStorage окажется большое количество элементов, включая те, которые не являются клейкими замет­ ками? Разве будет эффективным осуществление итераций по всему этому набору элементов?

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

0 : Что ж, если речь не идет об очень большом количестве эле­

может упорядочивать ваши элементы по-другому.

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

T i-

Меня удивило использование значения localStorage.length в качестве номера заметки в ключе, например:

Т5 J; •-

Я часто использую форму for in цикла for. А здесь он сработает?

О

! Сработает. Все будет выглядеть следующим образом:

for

(var key in localStorage) { var value = l o c a l S t o r a g e [ k e y ] ;

nsticky_n + localStorage.length

Зачем мы так поступили?

в

Можно ли удалять клейкие заметки?

0 : Нам необходим способ создания новых, уникальных ключей. Мы могли бы использовать что-то вроде значения времени или

0 : Да, удалять элементы из localStorage можно с помощью

генерировать целое число, которое увеличивалось бы с каждым

метода localStorage.remove Item Вы также можете делать

разом. Либо, как отмечалось ранее, можно использовать значение

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

length локального хранилища (которое увеличивается каждый

продемонстрируем оба этих способа.

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

Т5 Jу -•

Я создал набор заметок в браузере Safari, а затем пере­ шел на Chrome, но не смог увидеть их в этом браузере. В чем причина?

f l -•

Каждый браузер поддерживает свое собственное локальное

хранилище. Так что если вы создадите клейкие заметки в Safari, то сможете увидеть их только в этом браузере.

ШТУРМ Учитывая способ реализации клейких за­ меток, с нашей схемой присваивания имен возникнет проблема, если пользователь бу­ дет иметь возможность удалять заметки по своему усмотрению. Как вы думаете, в чем именно будет заключаться эта проблема? дальше ►

467


диагностика браузерного хранилища

Прервемся для небольшого запланированного мероприятия Было бы здорово, если бы существовал ипструмепт для про­ см отра элемептов в вашем localStorage папрямую? Л ибо ипструмепт для удалепия элемептов или даже для полпой очистки храпилищ а, чтобы пачать все запово, когда вы будете запиматься отладкой? Все осповпы е браузеры располагаю т встроеппы м ипструмептарием разработчика, позволяю щ им папрямую исследовать содерж имое вашего локальпого храпилищ а. Д аппы й ипструм ептарий разпится от браузера к браузеру, поэтому вместо его полпого исследовапия мы укажем вам правильпое паправлепие, после чего вы сможете сами покопаться и узпать, какова специф ика вашего собствеппого браузера. В качестве прим ера взгляпем па то, что предлагает браузер Safari:

[

▼j у L « jI Si игдд* l o c a l h o '« I

►ЩSession _? Cpokiev

►Ш A pfktauS an Cache

Старомодные файлы cookie на случай, если они вам потребуются.

Key Ot Hbrty j IslitIr.o

VjJje

Q\mr ftuydMfelr Apple gaNSig^Tl

■Пара « к а н о и — з на чение» для каждого own t ыж? элемента в хранилище находимся здесь. Щелкнув правой кнопкой Щелкнув здесь, вы увидите мыши на одном из элемен­ хранилище! ассоциированное тов хранилища , вы сможе­ с данным источником. те отредактировать или I Од этом мы пого­ удалить этот элемент ворим позже. прямо в данном окне.

С

X

Источник хранилища. Здесь мы и споль­ зуе м локальные файлы , загружаемые из http ://lo c a lh o st, однако это может быть и доменное и м я, если вы проводи­ т е тестирование на онлайн-сервере.

глава 9

i

Nmeiirst Frcfles Auzls. Cwrata

Network Scipts

►| | Uatasues

468

И нст рум ент а рий р а з р а ­ ботчика в браузере Safari

Web Inspector —httpi/ZlDcalbDst^Beth/HTMLS^crealStarage/no-tetobJeirhtml {>s a im

и СПСМ5.

очистка localStorage вашего браузера

Не говоря уже о новых версиях браузеров, к о т о ­ рые появляются быстрее, чем мы пиш ем страницы!

Mw щелкнули на вкладке Resources (Ресурсы), чтобы п р о ­ инспект ироват ь localStorage. n o n

Сегодняшнее спецпредложение

В браузере Safari мы можем использовать данные инструменты для перезагрузки пред­ ставления Storage (Хранилище) и удаления выбранного элемента.

Для активации или доступа к ипструмептарию раз­ работчика, как мы уже говорили, в разпы х браузерах п ридется поступать по-разпому. П осетите страпицу h ttp :/ /w ickedlysm art.com /h fh tm l5 / devtools.htm l, что­ бы узпать, как это сделать имеппо в вашем браузере.


сохраняем данные локально

По 99ер)кка типа «сделай сам» Существует еще о д и п способ очистки храпилищ а от ваших элемептов (а также, как мы вскоре увидим, способ удалепия их поодипочке), которы й потребует от вас самостоятельного обеспечепия пеболы иой поддержки, прямо из JavaScript. API-иптерф ейс localStorage вклю чает удобпый метод clear, которы й удаляет все элементы из вашего локальпого храпилищ а (по крайп ей мере, элементы из вашего домепа). П осмотрим , как можпо использовать вызов даппого метода па JavaScript, создав повы й ф айл maintenance.html. Сделав это, добавьте туда приведеппы й пиж е код, и мы пош агово разберем, как оп работает. Это Хороший и н с т р ум е н т для вашего набора

< ! doctype html> <html> <head> <title>Mainten a n c e < / t i t l e > <meta c h a r s e t = " u t f - 8 "> <script> w i n d o w . o n l o a d = f u n c t i o n ()

{

var clearButton = d o c u m e n t .g e t E l e m e n t B y l d ("clear_button" ; c l e a rButton.onclick = clearStorage;

Mw добавили одну кнопку на ст р аниц у, а э т о т ^ код добавит для данной кнопки обработчик собы­ т и й л инициируемых при ее нажатии.

} function c l e a r S t o r a g e ()

При щелчке на кнопке будет происхо­ дить вызов функции clearStorage.

{

l o c a l S t o r a g e .c l e a r () ;

Данная функция лишь вызывает м ет од localStorage. clear. Используйт е ее осторожно, поскольку она уд а ­ л и т все элем ент ы , ассоциированные с источником данной страницы Maintenance!

} </script> </head> <body> <form> <input type= "button" </form> </body> </html>

id="clear_button" v a lue="Clear storage"

/>

Г

А вот наша кнопка. Используйт е файл m aintenance.htm l всякий р а з, когда вам понадобится ст ерет ь все содержимое localStorage (хо р о ­ шо подходит для тестирования).

Н абрав даппы й код, загрузите его в своем браузере. Теперь у вас есть возмож пость безопаспо (в случае с паш им прилож ением для работы с электроппы м и за­ метками N ote to Self) очистить localStorage, поэто­ му попробуйте это сделать! Н о спачала убедитесь в том, что вы разобрались в своем ипструмептарии раз­ работчика, чтобы увидеть измепепия.

|Аыпе оаг*ороЖ

Н

Ь 1

Данный код уда­ лит все элемен­ ты в вашем до­ мене!

Если у вас имеется сверхценное локальное хранилище °гЛ 3аИТ е ° другим проектом в том же самом домене, то выпишитесь всех своих элементов, если выполните данный код. просто имейте это в виду...

дальше ►

469


проблема с приложением note to self

У меня возникла проблема. Выполняя упражнения в книге, я воспользовался своим и знаниями для создания новой электрон­ ной корзины для нашей ком пании. М ое приложение N ote to S e lf перестало работать. Заглянув в localStorage с пом ощ ью инструментария разработчика в браузере S a fa ri, я увидел, что нумерация всех м о и х заметок стала беспо­ рядочной: "sticky_ 0 ", "s tic k y _ l" / "sticky_ 4 ", "sticky_ 8 ", "sticky_15", "sticky_16", s ticky_ 2 3 ", "sticky_ 4 2 ". У меня такое чувство, что причина в том, что я создаю в localStorage и другие элементы одновременно с заметками. Что же происходит?!

Вы столкнулись с основным недостатком проектирования. Ладно, приш ло время сказать все начистоту: ранее мы создали отлич­ ное небольш ое прилож ение, которое должно безупречно работать довольно долгое время, пока вы не начнете вставлять какие-либо дру­ гие элементы в localStorage (как поступил Джоэль в случае со своей электронной корзиной). Как только вы сделаете это, вся наша схема отслеж ивания клейких зам еток перестанет работать или, по крайней мере, больше не будет нормально работать. h с этиМ> Если бы еду П ричина в следующем. Прежде всего наши клей кие заметки нумеруются от нуля до числа, которое обозначает общее и х количество (минус один):

ооооо

Ms tic k y _ 0 "

"s tic k y _ 1 "

"s tic k y _ 2 "

"s tic k y _ 3 "

"s tic k y _ 4 "

Пять за м ет о к с м е т ка м и от О до 4. Чтобы добавить новую заметку, м ы подсчиты ваем количество элементов в локальном хранилищ е и создаем новый кл ю ч исходя из получивш егося количества: var key = "sticky " + localStorage.lengt "s tic k y _ 5 "

А чтобы отобразить все клейкие заметки, м ы осуществляем итерацию от нуля до значения length л о кал ьного хранилищ а (м инус один):

^

^

"s tic k y _ 0 "

ч

"s tic k y _ 1 "

*

^ ,,s tic k y _ 2 "

^

^

"sticky_Z" ,,s tic k y _ 4 ”

4

^ " s tic k y .S ”

2

Значением length на данный м о м е н т является поэт ом у мы осуществляем ит ерацию от О до 5, отображая зам ет ки от "sticky_0" до "sticky_S". 470

глава 9


сохраняем данные локально

Вот элем ент ы , которые Джоэле? использует в коде своей электронной корзины.

Теперь добавим элементы из электронной корзины Джоэля в localStorage!

ь/

'sticky_0" "sticky_1" "sticky_2" "sticky_3" "sticky_4" "sticky_5" "элемент 1 "элемент 2 "элемент 3 _____________________________________________________________ электроннойэлектроннойэлектронной — - - ________ корзины" корзины" корзины"

Теперь у нас в localst„rae , в су м м е имеете* d e t , m элементов.

-

var key = "sticky_n + localStorage.length;

о

'

"sticky_9”

При создании новой за м ет ки значением length локального хранилища будет <?, поэт ом у мы создаем за м е т к у с именем sticky_я". Х м , не похоже, что это будет правильным. Когда нам потребуется совершить итерацию по заметкам для того, чтобы отобразить их, у нас возникнет проблема:

QQ Q Q Q Q

"sticky_0” "sticky_1" "sticky_2" 4

”sticky_3"

”sticky_4"

“sticky_5”

Я

Теперь значением length является НО (мы только что добавили новую за м е т к у ), поэт ом у итерация будет осуществляться от О до Я с отображением каждой зам ет ки от "sticky_0" до "sticky_4".

— ’ ------- ^

3

J

'— v— '

Q

“sticky_9”

Ч -Л

\■ # T О >" s t ic k y ^ , s ic у_ WAU "st'C^yS У нас Иет'

Возьми в руку карандаш Отметьте флажками, какие проблемы может вызывать наша текущая реализация: [

|

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

j

[

Клейкая заметка может быть перезаписана методом setltem, если объем localStorage уменьшится, несмотря на то что другое приложение удалит все свои элементы. Сложно быстро сказать, сколько имеется клейких заметок; вам придется осуществлять итерацию по каждому элементу в localStorage, чтобы извлечь все заметки.

Используйте файлы cookie, поскольку такой подход должен оказаться проще!

дальше ►

471


сохранение массивов

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

472

глава 9


сохраняем данные локально

У нас есть технология... Мы пе обмапывали вас, когда отмечали, что вы сможете сохрапять только строки в качестве зп ачепий элемептов localStorage. Одпако это пе вся правда, поскольку у вас всегда будет возможпость преоб­ разовать массив (или объект) в строку, прежде чем сохрапять его. Похоже паж ульпичество, одпако это абсолю тпо легитим пы й способ сохрапепия в localStorage типов даппых, которы е пе являю тся string. Мы зпаем, что вам ужаспо хочется п ерей ти к рассм отрению п одробностей сохрапепия массивов, по прежде, чем мы это сделаем, взгляпем п а то, как массив сможет реш ить паши (и Джоэля) проблемы.

Вернемся немного назад и представим, что у нас имеется шесть клейких за­ меток В localStorage:

"sticky_0" "sticky_1" "sticky_2"

"sticky_3"

"sticky_4"

"sticky_5”

И зам ет ки , и массив "stickiesArray" располагаются localStorage.

Шесть клейких зам ет ок с м е т к а м и от О до 5

И, допустим, у нас в localStorage есть массив "stickiesArray":

Каждый элем ент массива "stickiesArray" является ключом для зам ет ки в localStorage.

"sticky_0" "sticky_1" "sticky_2" "sticky_3" "sticky_4" "sticky_5" "stickiesArray"

Теперь добавим новую клейкую заметку. Назовем ее "sticky_815". Почему такое большое число? А потому, что нас больше не будет волновать, как она называется, пока ее ключ является уникальным. Таким образом, чтобы доба­ вить заметку, мы просто вносим "sticky_815" в массив, а затем сохраняем элемент для данной заметки точно так же, как делали раньше. Например:

У нас появилась еще одна зам ет ка в localStorage.

"sticky_0" "sticky_1" "sticky_2"

"sticky_3"

,,sticky_4"

"sticky_5"

"sticky_815"

Семь клейких заметок: их ключи дольше неважны, они просто должны быть уникальными. sticky_0" "sticky_1" ,,sticky_2" "sticky_3" ,,sticky_4" "sticky_5" "sticky_815

Мы также р а с ­ ширили массив "stickiesArray" на одно значение.

"stickiesArray"

дальше ►

473


переписываем приложение с использованием массива

Дорабаты ваем наше приложение с использованием массива Итак, мы приблизительно зпаем, как собираем ся отслеж ивать паш и заметки с помощью массива. Одпа­ ко пойдем пемпого дальше и убедимся, что мы сможем осуществлять и терац и и и отображ ать все клей­ кие заметки. В текущем коде мы отображ аем все заметки в фупкции init. А мож по ли переписать ее с использованием массива? Спачала взгляпем па имею щ ийся код, а затем посмотрим, как оп изм епится (падеемся, в лучшую сторону) п ри использовании массива. П ока пе печатайте даппы й код; мы сосредо­ точим ся па измепепиях, которы е пам пеобходимо впести сейчас, а пе па том, чтобы сделать этот код «нулепепробиваемым». Таким мы его сделаем чуть позже.

Д о... function init ()

// b u t t o n code here. . . for

Вот наш старый код, который полагается на т о > Что У зам е т о к будут специфические ЫШНа: ^ у . О , S t k k y . l и т. д.

{ ^

(var i = 0; i < localStorage.length;

(key.substr (0 ,

{

^

var key = localStorage.key(i) ; if

i++)

6) == "sticky")

{

^

^

е с л и

^ |Д0

HeaKKypamH0,

вдуматься.

var value = l o c a l S t o r a g e .g e t I t e m ( k e y ) ; addstickyToDOM(value);

л ^

} } }

Новый

Ц улучшенный

function i n i t ()

К ак мы т еперь знаем, здесь возможны бреши поскольку нельзя рассчит ывать на то, что все зам ет ки обязательно будут при сут ст воват ь т а м , если присваивать им имена исходя из одщего количества элемент ов в localStorage.

Начинаем с извлечения stickiesArray

{

// but t o n code here...

4

из localStorage.

Нам необходимо удостовериться в т о м j что в localStorage есть ______________ массив- Если его т а м не будет , т0 у\ды создадим пустой массив.

var stickiesArray = localStorage["stickiesArray"]; if (!stickiesArray)

{

stickiesArray = [] ;

localStorage.setItem("stickiesArray" ,

stickiesArray);

Совершаем

)

ПРИМЕЧАНИЕ: fa все

рации, по м а с с в у .— V Г ^ for (var i

= 0; i < stickiesArray.length; i+ + ) {

var key = stickiesArray[i] ; var value = localStorage [key] ; addstickyToDOM (value) ;

^ } . „ Добавляем со от вет ст у ю щ е е з в объектную модель документа (Р ОМ) точно так Же, как делали это раньше. 474

глава 9

^

"*) Каждый элем ент массива яв л яется ключом клейкой за м ет к и, п оэт ом у мы используем его для извлечения соот вет ст вую щ его элеМента мз locaisto ra g e.

1Щ‘ He З н а е т е , как с°~ хранят ь и извлекать м а с с и в ы , содержащ ееся

в localStorage, п о эт о м у р а с с ма тр и в а й те эт о как псе&докод, пока Мы вам все не покажем. Нам пот ребует ся вн ест и совсем небольшое дополнение, чтобы он р а6отал.


сохраняем данные локально

ПрЗЖНСШС

Нам по-прежнему нужно выяснить, как ф актически осущ ествляется со хр ан ени е м ассива в lo c alS to ra g e. Вы уже могли догадаться, что у нас есть возможность использовать JSON для создания строкового представления массива. И если так и было, то вы правы. Располагая таким пред­ ставлением, ВЫ сможете сохранить его В localStorage. Как вы помните, в API-интерфейсе JSON имеются только два метода: s tringify и parse. Задействуем данные методы и завершим функцию ini t (посмотрите решение данного упражнения в конце главы, прежде чем двинетесь дальше):

function i n i t ()

{

// but t o n code here... var sticki e s A r r a y = l o c a l S t o r a g e [" s t i c k i e s A r r a y " ]; if

(!stickiesArray) sticki e s A r r a y =

{ [];

l o c a l S t o r a g e .s e t l t e m (" s t i c k i e s A r r a y " , __________ } else

{

s ticki e s A r r a y = ____________ (stickiesArray) ;

} for

,(stickiesArray)) ;

(var i = 0; i < s t i c k i e s A r r a y .length; var key = s t i c k i e s A r r a y [ i ] ; var value = l o c a l S t o r a g e [ k e y ] ;

i++)

{

Me?/ добавили данное предложе­ ние else, поскольку вам п о т р е ­ буется кое-чт о п редпринят ь, если вы извлечете массив из localStorage (поскольку это будет строка, а не массив).

addStickyToDOM(value);

}

Внесение изменений в createSticky с целью использования массива Мы п о ч т и п о л п о с т ь ю рассм отрели паше прилож епие. Осталось лишь доработать метод createSticky, которы й, как вы помпите, извлекает текст для клейкой заметки из формы , сохрапяет его локальпо, а за­ тем отображает. Взгляпем па текущую реализацию , преж де чем впесем в пее измепепия: Вместо использования значеfunction c r e a t e S t i c k y () { ния length локального хр а н и ­ var value = d o c u m e n t .g e t E l e m e n t B y l d (" n o t e _ t e x t " ).v a l u e ; лища для генерирования ключа (что, как мы уже видели, var key = "sticky_" + localStorage.length; может ст а т ь причиной п р о ­ ' <l o c a l S t o r a g e .setltem(key, value) блем) нам пот ребует ся соз­ дать более уникальный клю ч. addStickyToDOM(value);

)

Нам также нужно dot... stickiesArray и сохранить э т о т массиЬ дальше ►

475


Часто

добавление уникального идентификатора

ЧаДаВаеМые В опросы

Ч то именно необходимо изменить? f t

Есть две вещи, которы е пеобходимо изм епить в createSticky.

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

Существует масса способов создапия упикальпых клю­ чей. Мы могли бы использовать зп ачеп ия даты и времепи, либо геперировать причудливые случайпые 64-битпые числа, либо задействовать в сочетапии с пашим п рилож епием API-иптерфейс, связаппы й с атомпы ми часами. И спользование зп ачеп ий даты и врем епи пред­ ставляется хорош им и легким реш епием. JavaScript под­ держ ивает объект Date, которы й возвращ ает зпачепие в виде количества миллисекупд, прош едш их с 1970 года; даппое зпачепие должпо оказаться достаточпо упикальпым (если только вы пе собираетесь создавать свои за­ метки с очень высокой скоростью): — Создаем объект P a te, а за т е м извлекаем ^ значение текущего времени в миллисекундах. var currentDate = new Date() ;

„ ^. .

„ , ^.

var key = "sticky_" + time;

^

л w

это

за значение в виде количества

О:'

Вы, возможно, уже знаете, что миллисекун­

да представляет собой тысячную долю секунды, а метод getTime возвращает значение, ко­ торое является общим количеством миллисе­ кунд, прошедших с 1970 года. Почему именно с

Создание уникального ключа для клейкой заметки.

var time = currentDate .getTime () ;

Что

миллисекунд, прошедших с 1970 года? мил;

_

1970 года? Данное поведение унаследовано от операционной системы Unix, которая определя­ ла время таким способом. Несмотря на то что такой подход неидеален (например, значения времени до 1970 года представляются в виде отрицательны х чисел), он окажется кстати, когда вам потребуется уникальное число или возникнет необходимость отслеживать время в JavaScript-коде.

Разве применение методов parse и stringify в случае с JSON-типами не явля­ ется довольно неэффективным с точки зрения производительности? А если мой массив сильно разрастется, то не окажется ли так, что и сохранение будет осущест­ вляться неэффективно?

Наш новый код для > генерирования уни 0 J\ кального клю ча.

: Теоретически, да,

по обоим упомянутым

вами пунктам. Однако в случае с типичными за­

А за т е м генерируем ключ п у т е м добавления получен­ ного значения в миллисекундах в ст року " stickyj1.

дачами программирования веб-страниц обычно это не является проблемой. Вместе с тем, если вы занимаетесь реализацией серьезного при­

ф

Сохранение новой заметки в массиве.

ложения с высокими требованиями относитель­

но сохранения данных, то можете столкнуться Теперь, когда у пас имеется способ геп ери ровап ия упис проблемами, используя JSON для преобразо­ кальпого ключа, пам пеобходимо сохрапить текст заметки вания элементов в строки и обратно. с этим клю чом и добавить даппы й ключ в stickiesArray. П осмотрим , как это можпо сделать, а потом объедипим Вместо того чтобы повт орят ь весь код весь код. для извлечения и проверки stickiesArray, Сначала извлечем массив stickiesArray. как мы это делали в функции init (на п р е ­ дыдущей странице), мы создадим новую var stickiesArray = getStickiesArray(); функцию. Д о этого мы дойдем позже.

localStorage.setltem(key,

value)

stickiesArray.push(key); localStorage.set l t e m ("stickiesArray"

З а т е м сохраняем ключ с его значением, как делали раньше (только речь здесь идет о нашем новом ключе).

JSON.stringify(stickiesArray)

IT И сохраняем массив обратно в localStorage, предвари­ тельно преобразовав его с помощ ью метода stringify. 476

глава 9

-Д алее используем мет од push, который добавляет ключ в конец массива stickiesArray.


сохраняем данные локально

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

Соединяем все воедино П ора и птегрировать весь новы й код на основе массива, вклю­ чая фупкции init и createSticky. Д ля этого мы сначала абстра­ гируем небольш ой ф рагм ент кода, которы й необходим в обе­ их фупкциях, — это код, извлекаю щ ий массив stickiesArray из localStorage. Вы видели его в функции init, и он снова пам понадобится в createSticky. П оместим данны й код в метод get Stickies Array — on уже долж еп быть вам зпаком, если исхо­ дить из того кода, которы й мы с вами уже рассмотрели: Сначала мы и з ­ влекаем э лем е нт "stickiesArray" из localStorage. function getStickiesArray() {

Г

var stickiesArray = localStorage.ge t l t e m ("stickiesArray" if

(!stickiesArray) stickiesArray = []

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

localStorage.set l t e m ("stickiesArray"

И если все-т аки массив будет о т с у т с т в о в а т ь , то мы создадим пустой массивj а за т е м сохраним его в localStorage.

JSON.stringify(stickiesArray)

} else { stickiesArray = JSON.parse(stickiesArray);.

return stickiesArray;

3 любом случае в итоге у нас 6ydev массив, который мы возвратим.

Не забудьте сперва п р е ­ образовать его с п о м о ­ щью метода stringify! 3 прот ивном случае мы все же находим в localStorage массив, в отношении которого нам п о ­ т ребует ся прим ени т ь мет од parse, чтобы преобразовать его в JavaScript-Maccu6.

дальше ►

477


интеграция всего кода

Соединяем все воедино (продолжение...) Написав getStickiesArray, взгляпем паупрощ еппы е, ф ипальпы е версии фупкций init и createSticky. Н аберите приведеппы й далее код: . Как вы поллните, мы т а к function init о { у' же задали здесь, в методе init обработчик событий, var button = document. getElementByld (" add_button") ; к а с а И ) 1 ц и Х С Я button. button.onclick = createSticky;

Д алее мы извлекаем массив с ключами зам ет ок, которые var stickiesArray = getStickiesArray () ; ^ ----- — б нем содержатся. Теперь мы будем о сущ ест влять итерацию по м а е f o r (var i = 0; i < stickiesArray.length; i++) { cug stickiesArray (не no var key = stickiesArray [i] ;

--------

var value = localStorage [key] ; addstickyToDOM (value) ;

т а к же извлечем его значение из localStorage.

ч }

^ э л е м е н т а м localStorage!). Каждый элем ент в массиве является клю чом для заметки. Извлечем их.

И добавим в объектную модель документа (РОМ) точно т ак же, как делали раньше.

Закопчив с init, пам остается лиш ь разобраться с createSticky:

function createSticky ()

Начинаем с извлечения массива stickiesArray.

{

с о з д а д и м уникальныи к л ю ч для нашей новой заметки.

var stickiesArray = getStickiesArray () ;

Л а л е е

-X var currentDate = new Date() ; var key = "sticky_" + currentDate . getTime () ;

— _ Добавляем пару

)

var value = document.getElementByld ("note_text"). v a lue;

«КЛЮЧ

значение»

/ зам ет ки в localStorage. ^ ----

localStorage.setltem(key, value); stickiesArray .push (key) ; ч

И добавляем новый ключ в массив stickiesArray...

localStorage.setltem("stickiesArray" , JSON.stringify(stickiesArray) ) ; addstickyToDOM(value);

j Наконец, обновляем страницу с использованием новой за м ет ки п у т е м ее добавления в РОМ.

478

глава 9

с

А за т е м применяем м ет од stringify для преобразования массива и записываем его обратно в localStorage.


сохраняем данны е локально

Тест-драйв! (Aaatdcfcyncaiataf-, Н а б е р и т е весь и р и в е д е и п ы й в ы ш е к о д , о ч и с т и т е у себя l o c a l S t o r a g e , ч т о б ы п а ч а т ь с ч и с т о г о л и ста . З а гр у з и т е д а п п ы й ко д , в резул ьта те ч е го в ы д о л ж п ы у в и д е ть т о ч п о т а к о е ж е п о в е д е п и е , к а к и в п р о ­ ш л ы й раз. Д ж о эль, т ы у в и д и ш ь , ч т о т е п е р ь т в о й к о д р а б о та е т д о л ж п ы м о б р а зо м !

Pick up dry cleaning

Cancel

сable tv, who needs

it now?

Buy another

Apple gadget

J

Часш °

^адаВ аеМ ы е B o llp o C b l

Tj J5*- Мы используем

"sticky_" как префикс для имен наших элементов localStorage. А существует ли согла­ шение относительно схем присваи­ вания имен элементам localStorage?

вить план относительно того, какие име­ на вы будете присваивать элементам. 1Если у меня будет много клейких заметок, то мой массив stickiesArray станет очень длинным. Это будет про­ блемой?

! Соглашения, касающегося присваи­ вания имен элементам l o c a l S t o r a g e , не существует. Если ваше приложение располагается на небольшом сайте в домене, который находится под вашим контролем, то с присваиванием имен не должно возникнуть проблем, поскольку вы будете осведомлены обо всех именах, которые используются разными страни­ цами на данном сайте. Мы считаем, что хорошей идеей будет использовать имя, которое является индикатором страницы или веб-приложения, полагающегося на элемент с данным именем. Таким

! Если только вы не создадите тыся­ чи заметок. В противном случае это не должно превратиться в проблему (а если вы все же создадите тысячи заметок, то нам хотелось бы узнать, как вам уда­ лось оказаться столько продуктивным!). В наши дни JavaScript работает довольно быстро.

&

Просто чтобы прояснить ситу­

ацию: мы сможем сохранить любой объект в localStorage, всего лишь

образом, " s t i c k y _ " помогает нам запомнить, что такие элементы связаны

предварительно преобразовав его с помощью метода stringify A P I-

с приложением Note to Self для работы с электронными заметками.

интерфейса JSON?

&

Если мое приложение Note to Self является лишь одним из многих приложений в домене, то мне нужно беспокоиться о потенциальных кон­

фликтах?

0

: Все верно.

JSON-строки пред­

ставляют собой упрощенные версии JavaScript-объектов, а наиболее простые JavaScript-объекты могут быть преоб­ разованы в строки с помощью JSON и сохранены в l o c a l S t o r a g e . Сюда относятся массивы (в чем вы убедились

0 : Да. Вам (или тому, кто управляет веб-сайтами в соответствующем домене) в данном случае будет полезно соста­

Выбирайте схему присваивания имеи для своих элементов localStorage, которая ие приведет к конфликтам с другими приложениями в том же самом домеие.

ранее), а также объекты, содержащие имена свойств и значения, как вы вскоре увидите.

Если вам потребуется сохранить массивы и м объекты в localStorage, используйте JSON. stringify для создания значения, которое можно буцет сохранить, и задействуйте JSON.parse иосле того, как извлечете его. дальш е ►

479


еще одна т ребуемая ф ункция: удаление

—'

Трудно разобраться во всех \ своих делах, если после того, как и х сделаешь, нельзя избавить­ ся от листочков, на которы х они были записаны. Нельзя л и снабдить и х ф ункцией удаления? >

Buy another

Apple

Pick UP dTY cleaning

Go grocery

gadget

Learn tWW

db -clutter

shopping

Order

Tweetshirt t-slni*

Drink more coffee

< vi d e o >

my d e ^

works

Find my mobile phone

Get rid of some of

Learn how to meditate

these sticky

Б удьт е осторожны с ост рыми предмет ами!

Удаление клейких заметок Она нрава: дан ное н рнлож енне не будет иметь большого уснеха, если он о н е но зв о лит удалять заметки. Мы уже уноминали метод l o c a l S t o r a g e . re m o v eltem , однако не беседовали о нем. М етод remove I t e m нриним ает ключ элемента и удаляет данны й элемент и з lo c a lS to r a g e : lo c a l S t o r a g e . re m o v eltem (k ey );

Д а н н ы й м е т о д у д а л я е т с о дер­ жащийся в localStorage э л е ­ м е н т с о пр еделен ны м к л ю ч о м .

r e m o v e l t e m и м е е т один

п а р а м е т р : кл ю ч э л е м е н т а , подлежащего у д а л е н и ю ,

Все это кажется довольно нросты м, не так ли? Н о если задуматься, то удаление клейкой заметки не ограничивается лишь вы зовом м етода r e m o v e lt e m —нам также нотребуется разобраться со s t i c k i e s A r r a y . . . 480

глава 9


сохраняем данны е локально

^Возьми в руку карандаш Давайте удалим клейкую заметку! Ниже приведено сод ерж им ое l o c a l S t o r a g e . У вас имеется весь необходи­ мый JavaScript-код наряду с методом rem oveltem . Набросайте карандаш ом на бумаге то, что нуж н о сделать, чтобы удалить s t ic k y _ 1 3 0 4 2 2 00 0 6342 из

l o c a l S t o r a g e . Сделав это, напиш ите внизу псевдокод, чтобы показать, ка к вы собираетесь писать свой настоящ ий код.

"sticky_1304294652202" "sticky_1304220006342" "sticky_1304221683892" "sticky_1304221742310" "элемент 1 "элемент 2 электронной электронной корзины" корзины"

"sticky_1304294652202" "sticky_1304220006342"

"sticky_1304221742310"

"sticky_1304221683892"

"stickiesArray"

Свой псевдокод н а п и ш и т е здесь.

дальш е ►

481


реш ение упражнения

Возьми в руку карандаш Решение

Давайте удалим клейкую заметку! Ниже приведено сод ерж им ое l o c a l S t o r a g e . У вас имеется весь необходи­ мый JavaScript-код наряду с методом rem oveltem . Набросайте карандаш ом на бумаге то, что нуж н о сделать, чтобы удалить s t ic k y _ 1 3 0 4 2 2 0 00 6342 из

l o c a l S t o r a g e . Сделав это, напиш ите внизу псевдокод, чтобы показать, ка к вы собираетесь писать свой настоящ ий код. Вот наше реш ение этого упр аж н е н ия.

l o c a l S t o r a g e r e m o v e i t e m C s > t i c k y ^ 0 4 Z Z 0 0 0 ^ 3 4 Z ),

I'lAXOQiieCOOnO" "s tic k y /l304220^)6342” ",,sticky_1304221683892" c tin l/u п а м А и т 41 ’Ч п о и о м т 2 "sticky_1304294652202" "sticky_1304221742310" 'Ч "элемент "элемент / электронной электронной корзины" корзины"

sticky_1304294652202" "s

[006342" "sticky_1304221742310" "sticky_1304221683892 "stickiesArray"

1). Удалить клейкую зам ет ку с ключом "stickyjL304ZZ000<b34-Z" из localStorage с помощью метода localStorage.removeltem. 2). Извлечь stickiesArray. 3). Удалить элемент с ключом- 'sticky jL304-ZZ000<b34-Z" из stickiesArray. 4).

Записать stickiesArray обратно в localStorage (предварительно преобразовав его с помощью метода stringify).

5). Найти "sticky_1304ZZ000<Z>34Z" в объектной модели документа (РОМ) и удалить ее.

482

глава 9


сохраняем данны е локально

Функция deleteSticky В ы с о с та в и л и п л а н т о г о , к а к будет о с у щ е с тв л я ть с я удаление к л е й к и х за м е т о к, н о э т о м у да в а й те в згл я н е м н а ф у н к ц и ю d e l e t e S t i c k y :

Сначала мы у д а ля е м з а м е т к у из localStorage с п о м о щ ь ю м е т о д а r e m o v e lte m , передав е м у кл ю ч за м е т к и , подлежащей удалению . fu n ctio n d e le te S tic k y (k e y )

{

И спользуем функцию ts tic k ie s A r r a y для из лечения stickiesA rray из localStorage. Убеждаемся в т о м , чт о у нас и м е е т с я stickiesA rray (на всякий слу ч а й ), а з а ­ т е м со вер ш аем и т е р а ц и ю по м а ссиву в поисках клю ча, к от ор ы й х о т и м уд а ли т ь .

£

lo c a l S t o r a g e . rem o v eltem (k ey ); g e t S t i c k i e s A r r a y ();

var s tic k ie s A r r a y if

(stick iesA r ra y ) for

{

(var i = 0; i < s t i c k i e s A r r a y . l e n g t h ; if

(key == s t i c k i e s A r r a y [ i ] ) { s t ic k ie s A r r a y . s p l i c e ( i , 1);

} }

i+ +b) )

{

^Отыскав требуемый ключ, удаляем его из массива с помощью splice.

-

sPllce удаляет элементы из массива, начиная с пози ции, обусловленной первым аргументом (Г), при этом количество удаляемых элементов окажется таким, как указано во втором аргументе (г).

lo c a l S t o r a g e . s e t lt e m ( " s t ic k ie s A r r a y " , J S O N .s t r in g if y ( s tic k ie s A r r a y ) );

Наконец, сохраняем stickiesArray (при этом соответствующий ключ из него уже удален) обратно в localStorage.

Я разобралась в коде, однако не м о гу понять, как м ы извлекаем кл ю ч для передачи d e le te S tic k y . Если вду­ маться, то как пользователь вообще см о­ жет выбрать заметку для удаления?

дальш е ►

483


в ы бо р замет ок с п ом ощ ью h tm l и ja va s c rip t

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

Pick up dry cleaning

л и в ы м п у те м и д о б а в и т ь н о н е б о л ь ш о й н и к т о гр а м м е уда­ л е н и я для к а ж д о й з а м е т к и , о д н а ко в н а ш е м н р и л о ж е н и и N o te to S e lf м ы н о с т у н и м н а м н о го н р о щ е : будем н р о с т о уда­

Cancel cable tv, who needs it now?

Buy another Apple gadget

л я ть о н р е д е л е н п у ю зам етку, е сли п о л ь зо в а те л ь щ е л к н е т н а н е й . Э то , в о з м о ж н о , н е самая л уч ш а я р е а л и за ц и я с т о ч к и з р е н и я уд об ства н о л ь з о в а н и я , о д н а ко н р о с т а я .

Когда мы щ е л к н е м на к л е й ­ кой з а м е т к е с п о м о щ ь ю м ы ш и , она б удет удалена.

Д л я р е а л и з а ц и и э т о го н а м сначала п о т р е б у е т с я в н е с т и и з м е н е н и я в н а ш и к л е й к и е за м е т ки , ч т о б ы м ы с м о гл и в ы ­ я в л я ть , когда п о л ьзо в а те л ь щ е л ка е т н а за м е тке , н о сл е ч е го не р е д а д и м ее ф у н к ц и и d e l e t e S t i c k y . М н о г о е и з э т о го д о л ж н о н р о и с х о д и т ь в ф у н к ц и и addStickyToDOM:

т е , пр замет ку.

^ ^

в и з ° ве ° т

п р о м

-

и f u n c t i o n addStickyToDOM(key, v a l u e )

{

v a r s t i c k i e s = docum ent. g e tE le m e n tB y ld (" s t i c k i e s r v a r s t i c k y = docum ent. c r e a t e E le m e n t (" l i sticky.setAttribute ("id" , key) ; v a r sp an = d o c u m e n t . c r e a t e E l e m e n t ( "span s p a n .s e t A t t r i b u t e (" c la s s " , " s t ic k y " ) ; span.innerHTML = s t i c k y O b j . v a l u e ; s t i c k y . ap p e n d C h ild (sp a n );

Д о б а в л я е м уни ка льны й и д е н т и ф и к а т о р в случае с э л е м е н т о м <li>> ко т о р ы й п р е д с т а в л я е т к л е й к у ю з а м е т к у в РОМ. М ы д ела ем э т о для т о го , чтобы ф у н к ­ ция d e le te S tic k y зн а ла , на какой з а м е т к е вы щ елкн ули. Поскольку на м уже и з ве с т но , ч т о клю ч з а м е т к и у никал е н, будем п р о с т о и с п о ль з о ва т ь его как идент ификат ор.

s t i c k i e s . a p p e n d C h ild ( s t i c k y ) ; sticky.onclick = deleteSticky;

*^ т пражненке аЖ н

Мы также добавляем обработчик клейкой з а м е т к и При щ елчке на з а м е т к е б у ­ дет п р ои с хо д и т ь вызов deleteS ticky.

событий click для каждой

Ваша задача — обновить весь код таким образом, чтобы везде, где мы будем вызывать addStickyToDOM, мы передавали ключ, а также значение. Вам не должно составить тру­ да найти эти места. Выполнив данное задание, посмотрите его решение в конце главы, чтобы проверить свои результаты.

Не п р о п у с к а й т е э т о у п р а ж н е ние, иначе п р е д с т о я щ и й т е с т драйв окажется неудачным!

484

глава 9


сохраняем данны е локально

Как извлечь заметку зля удаления, используя объект event Для каждой заметки у нас на данны й момент имеется обработчик собы тий, ведущий нрослушивание со­ бы тий c l i c k . Когда вы щелкнете на заметке, н р ои зой дет вызов функции d e l e t e S t i c k y , к оторой будет нередан объект e v e n t с и нф орм ацией о соответствую щ ем собы тии, нанрим ер на каком элем енте щелкпул пользователь. Мы мож ем обратиться к e v e n t . t a r g e t , чтобы сказать, на какой заметке нроизош ел щелчок. Давайте бол ее нристально носм отрим , что нроизойдет, когда вы щ елкнете на заметке. Если вы щелкнете на Если вы щелкне­ желтой части заметки, те на тексте, то event.target будет эле­ то event.target мент <(/>. Это именно то, будет <span> < Cancef Buy another саЫс tv, Apple что нам нужно, поскольку внутри <//’>, who needs it now? <(i> теперь имеет иден­ а это не то, тификатор в виде ключа что нам нужно. клейкой заметки.

I < l i i d = " s t i c k y _ 1 3 0 4 2 70008375"> < sp an c l a s s = " s t i c k y " > P i c k up d r y c l e a n i n g < / s p a n > < /li>

Так или иначе , о б ъ е к т e ven t, сгенерированный в а ш и м щ е л ч ­ к о м > п ер едает ся d eleteSticky. f u n c t i o n d e l e t e S t i c k y (е)

ta r g e t — э т о э л е м е н т , на к о т о р о м вы щ е л к н у л и и кот о ры й с генерировал о б ъ е к т event. Мы м ож ем и з ­ влечь и д е н т и ф и к а т о р данного э л е м е н т а из свойст ва target. Если t a r g e t я вля е т ся <(/>, т о все в порядке.

{

Если ta r g e t окажется <span>, т о нам п о т р е б у е т с я извлечь идент ификат ор родит ель­ ского э л е м е н т а , т о е с т ь <(/*> (<Ч> — э т о э л е м е н т с и д е н т и ­ ф и к а т о р о м , ко т о р ы й я вля ет ся необходимым на м клю чом).

v a r k ey = e . t a r g e t . i d ; if

( e . t a r g e t . tagN am e. t o L o w e r C a s e () == "span")

{'

k ey = e . t a r g e t . p a r e n t N o d e . i d ; }

lo c a lS t o r a g e . rem o v eltem (k ey ); var s t ic k ie s A r r a y = g e t S t i c k i e s A r r a y (); if

(stick iesA r ra y ) for

{

(var i = 0; i < s t i c k i e s A r r a y . l e n g t h ; if

Э т о HTML для зам ет ки, к о т о ­ р у ю м ы создаем в addStickyToD O M .

(k e y == s t i c k i e s A r r a y [ i ] ) { s t i c k i e s A r r a y . s p l i c e ( i , 1);

i+ +)

{

Теперь мы м ож ем в о с ­ п о ль зо ва т ь с я к л ю ч о м для удаления э л е м е н т а из localStorage , а также из stickiesArray.

} }

lo c a l S t o r a g e . s e t I t e m (" s tic k ie s A r r a y " , J S O N .s tr in g ify (s tic k ie s A r r a y ) removeStickyFromDOM (key) ; }

^ __

Нам также п о т р е б у е т с я у д а л и т ь <li>, с о д е р ­ жащий к л е й к у ю з а м е т к у , из с т р а н и ц ы , чтобы данная з а м е т к а исчезла, когда вы на ней щ е л ­ кнет е. Э т и м м ы и з а й м е м с я далее... дальш е ►

485


удаление замет ок из dom

Удаление заметки такЖе из DOM Ч т о б ы з а в е р ш и ть удаление, н а м н о н а д о б и т с я р е а л и зо в а ть ф у н к ц и ю remove S t ickyFromDOM. Ранее м ы о б н о в и л и ф у н к ц и ю addstickyToDOM с ц е л ью д о б а в л е н и я к л ю ч а к л е й к о й з а м е т к и в ка ч е с т в е и д е н т и ­ ф и к а т о р а эл е м е н та < l i > , к о т о р ы й с о д е р ж и т зам етку, п р и с у т с т в у ю щ у ю в о б ъ е к т н о й м о д е л и д о ку м е н та . П о э т о м у м ы с м о ж е м в о с п о л ь з о в а ть с я d o c u m e n t . g e t E l e m e n t B y ld для н о и с к а к л е й к о й з а м е т к и в D O M . М ы и з в л е ч е м p a r e n tN o d e з а м е т к и и н р и м е н и м м е то д re m o v e C h ild для ее удал ения:

Передаем ключ (также яв л яю щийся идент иф икат ором) клей - ~ X кой за м ет ки, кот орую ищ е м . f u n c t i o n г emoveStickyFromDOM(key)

{

у

Извлекаем элем ент <Н> ^ --- ^ из РОМ... ...и удаляем , для чего сначала извлекаем его p arentN od e ,

v a r s t i c k y = d o c u m e n t . g e t E l e m e n t B y l d (key) ; s t i c k y .p a r e n tN o d e . r e m o v e C h ild ( s t i c k y ) ; ^

}

<(i>

^<ul> удалит^Ъчерний узел \ l i >

а 3at/vxe,M применяем removeChild. -V

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

Отличная работа! А не X м о гл и бы вы теперь сделать так, чтобы я см огла раскрашивать свои заметки? Ну там, знаете, ж ел­ ты м цветом те, на которы х записаны срочные дела, синим — на которы х помечены идеи, розовым — заметки I со второстепенны ми делами. В таком духе?

I

t-ihirt

г.

Теперь мы можем удалять заметки!

Конечно моЖно! У ч и т ы в а я ваш о н ы т в э т о м деле, м ы с м о ж е м с п р а в и т ь с я с д а н н о й зад ачей. К а к и м е н н о м ы э то сделаем? Ч т о ж , м ы созд адим о б ъ е к т для р а зм е щ е н и я т е к с т а за­ м е т к и и ее ц в е та , а за те м с о х р а н и м е го к а к з н а ч е н и е эл е м е н та за м е т ки , п р е д в а р и ­ т е л ь н о зад ействов а в JSON. s t r i n g i f y для п р е о б р а з о в а н и я е го в стр о ку .

486

глава 9

у


сохраняем данны е локально

Обновление интерфейса пользователя для выбора цвета заметок Н а д а н н ы й м о м е н т все н а ш и з а м е т к и и м е ю т ж е л т ы й цвет. А н е будет л и л у ч ш е , е сли н а м с т а н е т д о с т у н е н для в ы б о р а ц е л ы й д и а н а з о н ц ветов? Sx* ЮI;If

л;tijttmi

1+ Cotof: I у»ИвшЯ

Мы м о г л и бы добавить сюда м е н ю выбора, чтобы вы с м о гли вы бират ь для своей з а м е т к и лю бой цвет.

Pick up dry cleaning

C ancel cable tv , who needs it now?

Buy a n o th e r Apple gadget

t- F

Л Так луч ш е, не правда ли?

С начал а н р и м е м с я за л е гк у ю ча с ть: о б н о в и м H T M L , ч т о б ы у нас н о я в и л о с ь м е н ю в ы б о р а ц в е то в , и з к о т о р о г о п о л ь зо в а те л ь с м о ж е т в ы б р а т ь п у ж н ы й цвет. О т р е д а к т и р у й т е ф айл n o t e t o s e l f . h tm l и о б н о в и т е с в о ю ф о р м у с ц е л ью д о б а в л е н и я ц в е то в , к а к н о к а з а н о далее:

Мы вносим изм енения т о л ь к о в ф о р м у , а все ос т а ль н о е о с т а н е т с я прежним.

О б р а т и т е вним ание на и д е н т и ф и к а м о р <select>j он н а м п о т р е б у е т с я для извлечения значения выбранного <form> п а р а м е т р а на Java Scrip t. M w добавили ч е т ы р е Добавим < ia b e l fo r = " n o te c o lo r " > C o lo r : < / la b e l> у а лЛ ъля для зз аа М м ^е ттОо Кк ,,g ме^кудля ~ _ ц ве т а оля которых м о ж н о ду< _______ s e le c t _ i d_= " n o t e c o l o r " .> текста uw замет. выбрать нужный ки чтобы < o p t i o n v a lu e = " L ig h tG o ld e r iR o d Y e llo w n> Y e l l o w < / o p t i o n > Otm г < h tm l>

пользова-

< o p tio n

C o- p tio n v a lu e = " L ig- h t P i r i k " > p i n k < / o p t io n > для чего ю еднаыа, реоназна < o p t io n v a lu e = " L ig h t B lu e n> b lu e < / o p t io n > чено данное поле. < /se le c t>

^

^

Каждое значение я в л я -

v a l u e = nP a le G r e e n n> g r e e n < / o p t i o n >

'

е т с я и м е н е м ц в е т а , ко т о р о е мы мож ем в с т а п,,, . А п о и т ь п р я м о в с т и л ь для наш их за м е т о к .

< l a b e l f o r = " n o t e _ t e x t n> T e x t : < / l a b e l > <i n p u t t y p e = " t e x t " i d = " n o t e _ t e x t "> < i n p u t t y p e = " b u t t o n " id = " a d d _ b u t to n " valu e= "A d d S t i c k y N o te t o S e l f " > < /fo r m >

jk

•О с т а л ь н а я ч а ст ь ф о р м ы о с т а н е т с я прежней. < /h t m l> М ы и с н о л ь з о в а л и CSS для о н р е д е л е н и я ц в е та н о у м о л ч а н и ю . Т е н е р ь н е о б х о д и м о с о х р а н и т ь ц в е т вм есте с са м о й з а м е т ко й . В о з н и к а е т в о н р о с : к а к м ы будем с о х р а н я т ь ц в е т для з а м е т к и в l o c a l S t o r a g e ?

дальш е ►

487


использование js o n для сохранения цвета

Метод JSON.stringify — не только для массивов Для сохранения цвета заметки вместе с ее текстом у нас есть возмож ность нрибегпуть к той ж е м етодике, которую мы иснользовали со s t i c k i e s A r r a y : м ож но сохранить объект, содерж ащ ий текст и цвет, как значение для заметки в lo c a lS to r a g e . Color:

[pink

Text: [Cancel cable tv, who needs it now?

~]

(Add sticky Note to S eif) |

t И мы с охра ни м его в localStorage с и с ­ поль зо ва ни е м клю ча клейкой з а м е т к и .

Мы будем д р а т ь введенные п о л ь з о в а т е ­ л е м значения для ц ве т а и т е к с т а з а м е т к и и « у п а к о в ы в а т ь » их в п р о с т о и объект . Точно т а к же, как и в случае со stickiesA rray, н а м п р и д е т с я вы зва т ь JSO N .strin gify в о т н о - ‘ илении значения з а м е т к и , прежде чем м ы вызовем loc a lStorage.setltem для с о ­ хранения данного значения.

localStorage

var stick yO b j = { " v a lu e " : "C an cel c a b l e t v , who n e e d s i t now?", " c o l o r " : " L ig h tP in k " };

П е р е н и ш е м ф у н к ц и ю c re a te S tic k y для с о х р а н е н и я ц в е та вм е сте с т е к с т о м к л е й к о й за м е т к и . Д л я н р е д с та в л е н и я т е к с т а и ц в е та будем и с н о л ь з о в а т ь н а ш у д о б н ы й о б ъ е кт:

f u n c t i o n c r e a t e S t i c k y ()

{

var s t ic k ie s A r r a y = g e t S t i c k i e s A r r a y (); v a r c u r r e n t D a t e = new D a t e ( ) ; var colorSelectObj = document.getElementByld("note_color") var index = colorSelectObj.selectedlndex;

Мы делаем т о , чт о обычно п р и н я т о для извлечения значения выбранного цвета.

var color = colorSelectObj[index].value; v a r k ey = " s t i c k y _ " + c u r r e n t D a t e . g e t T i m e ( ) ; var v a lu e = docum ent. g e t E l e m e n tB y ld (" n o t e _ t e x t " ) . v a l u e ;

ния S t i c k y O b j -

объект а.

содержащего два с в о й с т в а ,

var stickyObj = {

т ек ст зам ет ки и цвет , вы бранный п о л ь з о в а т е л е м .

"value11: value, "color": color

П реобразуем stickyO bj

};

localStorage.set Item (key, JSON.stringify (stickyObj )) ; s t i c k i e s A r r a y . p u s h (key) ;

З а т е м и с п о л ь з у е м данное значение ц в е т а для соъда

у с пом ощ ью мет ода JSON

Stringify прежде чем

м е с т и м его в localStorage.

l o c a l S t o r a g e . s e t lt e m ( " s t ic k ie s A r r a y " , J S O N .s t r i n g if y ( s t i c k ie s A r r a y ) ); addStickyToDOM (key, stickyObj); / Передаем о б ъ е кт в м е с т о т е к с т о в о й с т р о к и ф ун кц и и

addStickyToD O M . А э т о означает , ч т о ва м также п о ­ т р е б у е т с я обновит ь a d d S tic k y T o D O M , не т а к ли ? 488

глава 9


сохраняем данны е локально

использование нового объекта stickyObj Когда мы нередаем stickyObj функции addstickyToDOM , нам необходим о обновить эту функцию, чтобы иснользовать объект вместо строки, которую мы нередавали нреж де, а также чтобы задать цвет ф она для заметки. Эти изм енения довольно легко внести: НуЖН0 w3MeHumt, здесь п а р а м е т р , чтобы и м был stic k y O b j, а не т е к ­ ст овое значение з а м е т к и . f u n c t i o n addstickyToD O M (key,

stick y O b j)

{

v a r s t i c k i e s = d o c u m e n t . g e t E l e m e n t B y l d ("s t i c k i e s

И звл е ка е м ц в е т из о б ъект а stickyObj, ко т о р ы й передаем addstickyToD O M .

var s t i c k y = docum ent. c r e a t e E le m e n t (" l i " );

Объекты элементов HTML обладают свой стволл style, которое вы можете ис­ пользовать Эля доступа к стилю соответ ствующего элемента. }

s t i c k y . s e t A t t r i b u t e (" id " , k e y );

s t i c k y . sty le.b a ck g ro u n d C o lo r

stic k y O b j.c o lo r ;

( v a r sp an = d o c u m e n t . c r e a t e E l e m e n t ( " sp a n " ) s p a n . s e t A t t r i b u t e ( " c l a s s ",

" stic k y " );

span.innerHTML = s t i c k y O b j . v a l u e ; £ s t i c k y . a p p e n d C h ild (sp a n );

О б р а т и т е внимание: к о г ­ да м ы указы вае м с во й с т во , ■связанное с ц в е т о м фона, на J a v a S c r ip t, мы оп ре д е ля е м его как backgroundColor, а НЕ b a c k g ro u n d -c o lo r, как на CSS. З а т е м нужно извлечь т е к с т о в о е значение, ко т о р о е м ы со б и р а ­ емся и с п о ль з о ва т ь для з а м е т к и , из объекта.

s t i c k i e s . a p p e n d C h ild (stick y ); s t i c k y . o n clic k = d e le te S tic k y ;

Есть ещ е одно м есто, где нам н еобходи м о обновить код. И находится оно в функции i n i t , где мы извлекаем заметки и з l o c a l S t o r a g e и нередаем их addstickyToDOM, когда

в нервый раз загружаем страницу. f u n c t i o n i n i t ()

{

v a r b u t t o n = d o c u m e n t . g e t E l e m e n t B y l d ( " a d d _ b u tt o n " ) b u tto n . o n click = crea teS tick y ;

var s t ic k ie s A r a y = g e t S t i c k i e s A r r a y ();

for

(v a r i = 0; i < s t i c k i e s A r r a y . l e n g t h ;

i+ +)

v a r k ey = s t i c k i e s A r r a y [ i ] ;

{

Теперь, когда мы будем и з ­ влекат ь значение за м ет к и из localStorage, нам по т реб ует ся преобразоват ь его с помощ ью JSO N .parse, поскольку эт о больше не строка а объект.

var v a lu e = J S O N .p a r se (lo c a lS to r a g e [k e y ]) addstickyToD O M (key, v a l u e ) ;

}

4 ------------------

И м ы передадим данный о б ъ е кт ф ункци и a d d stick y T o D O M в м е с т о с т р о к и (код вы глядит т а к же, одна­ ко п ередаем м ы уже ч т о - т о другое). дальш е ►

489


т ест ирование цвет ны х замет ок

Тест-драйв цвета заметок П реж де чем снова вынолнять нрнлож енне N ote to Self, вам нотребуется очистить l o c a l S t o r a g e , носкольку нредыдущие версии наших клейких за­ меток не имели никакого цвета, и сейчас мы иснользуем другой ф ормат для значений наш их заметок. Ранее мы иснользовали строки, а тенерь — объекты. П оэтом у очистите у себя l o c a l S t o r a g e , перезагрузите страницу и добавьте несколько заметок, выбрав нри этом разны й цвет для каждой из них. Вот как выглядят наши заметки (кроме того, мы заглянем в наше локальное хранилищ е).

Вы можете восполь­ зоваться файлом maintenance'ktml для очистки своего localStorage либо об­ ратиться к консоли.

Мы выдрали желтый, розовый и синий цвет для заметок.

j

Wrccic S:11 Ч-и 1-~У1гЧ-.1тг:у|па1:к1й‘ '-г,а

j | + I*

Г ; ГоГ.

wllttft 7

»Т«М.

С | '<Хг G z c j i f A s f e l кч- tun* IK W )

Ca ncef cable tv, who needs it now

Pick up dry cleaning

Buy another Apple gadget 1

1 <s>инч-а- ^ wit n

’ •.r

|*-п-*нч n | ;*-«***■ Г" b

■ >/ I'

'llfl

AI^J U.I№MI.2 U.tU J*i tj; u.Sl»*«.+

- ___ _

J

Cl"j 11чМуг. >A'i U.1J 4dll|l||i' JW j> W. .1 J'r I UMlft *>, i tJJ*Hl4Aa I ЫЛ& W I u; l »V*‘ '»U'’JV,4'* i

* -j : "iintv

*■.. Vui'lm *■ _•ЕнММ *■^ Л1**

m *5________

Значение каждой заметки теперь является объектом (преобразованным с помощью метода JSON.stnngify), который содержит текстовое значение и цвет соответствующей заметки.

490

глава 9


/

Я д ум а л ; раз м ы м ожем сохра- \ нять объекты и массивы, то почему q . бы просто не сохранить все заметки в \ самом массиве, зачем нам нужны все эти I остальные элементы? П о хо ж е , все только усложняется, хотя м ы м о гл и бы просто / у вложить и х в один элемент / в localStorage.

У

В некоторых ситуациях так поступать весьма разумно. И с н о л ь з у я с в о и з н а н и я , м ы , н е с о м н е н н о , см о гл и б ы р а з­ р а б о та ть к л е й к и е з а м е т к и т а к и м о б р а зо м , ч т о б ы о н и п р е д ­ с та в л я л и с о б о й о б ъ е кт ы , в л о ж е н н ы е в м ассив. В д а л ьн е й ш е м в ы м о гл и б ы и м е н н о т а к и п о с т у п и т ь . Э то т а к ж е им е л о б ы см ы сл в случае с э л е к т р о н н о й к о р з и н о й . Е д и н с т в е н н ы й н е ­ д о с т а т о к за кл ю ч а е тс я в то м , ч т о м е то д а м JSON. s t r i n g i f y и JS O N .p arse н р и х о д и т с я п р о д е л ы в а т ь массу д о п о л н и т е л ь н о й р а б о т ы в с я к и й раз, к о гд а в ы в н о с и т е и з м е н е н и я : н а п р и м е р , ч т о б ы д о б а в и т ь зам етку, на м п р и д е т с я п р е о б р а з о в а ть с п о ­ м о щ ь ю JS O N .p arse ц е л ы й н а б о р за м е т о к, п о т о м д о б а в и т ь зам етку, а за те м с н о в а п р е о б р а з о в а ть все з а м е т к и у ж е с п о ­ м о щ ь ю JSON. s t r i n g i f y , п р е ж д е че м за п и с ы в а т ь и х о б р а т н о в х р а н и л и щ е . У ч и т ы в а я к о л и ч е с т в о д а н н ы х в н а ш е м случае, э то н е д о л ж н о ста ть п р о б л е м о й (о д н а к о зад ум айтесь о м о ­ б ил ьны х устр о й ств а х с не очень м о щ н ы м и пр о це ссо р а м и и о в л и я н и и и с п о л ь з о в а н и я р е с у р с о в н р о ц е с с о р а н а у р о в е н ь за­ ря д а а кк у м у л я т о р а ). Т а к и м о б р а зо м , р е ш е н и е о т о м , «унаковать» вам все в о д и н о б ъ е к т и л и ж е в м а сси в в l o c a l S t o r a g e , будет за в и с е ть о т к о ­ л и ч е с т в а э л е м е н то в д а н н ы х , к о т о р о е вам н о т р е б у е т с я с о х р а ­ н и т ь , а т а к ж е о т т о г о , н а с к о л ь к о б о л ь ш и м я в л я е тс я к а ж д ы й и з н и х и о б р а б о т к у к а к о г о р о д а в ы с о б и р а е те с ь о с у щ е с тв л я ть в о т н о ш е н и и э т и х эл е м е н то в . Н е с м о т р я н а т о ч т о н а ш а р е а л и за ц и я м о ж е т б ы т ь с л е гка гр о м о з д к о й для о г р а н и ч е н н о г о к о л и ч е с т в а за м е т о к, м ы н а ­ деем ся, ч т о о н а о т л и ч н о н о м о гл а вам н о н я т ь , ч т о т а к о е A P Iи н т е р ф е й с l o c a l S t o r a g e и к а к о б р а щ а ть с я с и м е ю щ и м и с я в н е м э л е м е н та м и .


Ш ПЫТАЙТЕСЬ СДЕЛАТЬ ЭТО ДОМА (И ЛИ КАК РАЗИКСТИ В ПУХ II ПРАХ ВАШ И 5 МБАЙТ) Как мы уж е говорил и, в сумме у вас будет 5 М байт хранилищ а для браузера ка ж д ого из пользователей. Несмотря на то что такой объем может показаться больш им, все ваши данные сохраняю тся в виде стро к, а не в байтовом формате. Возьмите, к прим еру, размер госуд арственного долга: если вы разить его в виде значения с плавающей то чко й , то для его размещ ения в хранилищ е потребуется не м н ого места, од н ако если вы разить его в виде стр о ко в о го значения, то для его сохранения потребуется гораздо больш ий объ ­ ем. Таким образом , хранилищ е разм ером 5 М байт спо соб н о вместить не так м ного, ка к могло показаться. Так что же произойдет, когда вы исчерпаете 5 Мбайт? К сож алению , это од но из поведений, которы е не определяю тся специф икацией HTML5, и браузеры м о гут поступать по-разном у, когда вы превы сите свой лимит. Браузер может спр оси ть у вас, хотите ли вы увеличь объем хранилищ а, либо сген ер и рует и скл ю че­ ние QUOTA_EXCEEDED_ERR, которое м ож но перехватить следую щ им образом :

' try

t ru/catck

пере

_

и с к д к н е н и я , ге н е р и ­

руемое 6 блоке tryЭ т о о бласт ь J a v a S c rip t, к о т о р у ю мы не з а т р а ­ ги в а л и , и вы м ож ет е з а х о т е т ь исследоват ь э т о т вопрос подробнее.

{ f l o c a l S t o r a g e . s e t l t e m (шуКеу, myValue) c a t c h (е) { i f (e == QUOTA_EXCEEDED_ERR) { a lert(" O u t o f sto ra g e !" ) }

П р о ве р я е м , ошибка ли э т о квот ы х р а н и л и щ а (а не к а к о й - т о другой т и п и склю ч ен ия ). Если т а к оно и е с т ь j м ы выведем для п о л ь з о в а т е л я диа л о го ­ вое окно ale rt с с о о т в е т с т в у ю щ и м сообщением. Вы, скорее всего, з а х о т и т е с д е ла т ь ч т о - т о более зн а ч и т е л ь н о е , чем п р о с т о вывод окна alert.

настоящий м о ­ Не все браузеры м е н т г е н е р и р у ю т исклю чение QUOTA_ EXCEEDED_ERR. Однако они все же с г е н е р и р у ю т исклю чен ие, когда вы п р е вы с и т е свой л и м и т , п о э т о м у н е ­ л и ш н и м б удет р азоб ра т ь с я с общ им с лу ч а е м исклю чения п ри сохранении т ого или иного э л е м е н т а в х р а н и л и щ е

492

глава 9

Вызов s e t l t e m в с е р е д и ­ не блока t r y ; если ч т о нибудь п о й д е т не т а к и s e t l t e m с ге н е р и р у е т и ск л ю ч е н и е , т о будет задейст вован блок catch.


сохраняем данные локально

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

ОПАСНО Взрывное задание

<html>

Начнем с односимвольной с т р о к и с к л ю ч о м "fuse".

<head> < scrip t>

lo c a lS to r a g e . se tlte m ( "fuse", w h ile(tr u e )

И п р о с т о будем , не ост а н а вл и ваясь, у в е л и ч и в а т ь ее размер...

;

{

..п у т е м удваивания э т о й с т р о к и (п о с р е д с т в о м к о н к а ­ т ена ции ее с сам ой собой).

v a r f u s e = l o c a l S t o r a g e . g e t l t e m ("f u s e try

{ l o c a l S t o r a g e . s e t l t e m ( " fu se " , f u s e + f u s e ) ; ^

} catch (e)

З а т е м попытаемся записат ь ее обратно в localStorage.

{

a l e r t ( " Y o u r b r o w s e r b l e w up a t" + f u s e . l e n g t h + " w i t h e x c e p t i o n : break; }

l o c a l S t o r a g e . r e m o v e I t e m ( "f u s e ” < /sc rip t> < /h e a d >

He будем о с т а в ­ л я т ь беспорядок и у д а л и м да н ­ ный э л е м е н т С' • из localStorage.

<body> < /b o d y > < /h t m l>

Ес-ли у вас х в а т ит духу во ОЛЬзобат ься э ^ и м кодом, ^ о опи здесь свои Р езу л ь т а т ы .

Наберите этот код, «зажгите фитиль», загрузи в его, и поразвлекайтесь! Испытайте его в разны х браузерах.

" + e);

Если браузер аварийно заверш ит работ у — дело сделано! В ы в е ­ дем для п о л ь з о в а т е л я диалоговое окно ale rt с соот вет ст вую щ им сообщ ением и выйдем из данного цикла.

ь

буд ьте о С Г О о |> о Ж Н ь х

Вы и спол ь зу­ ете этот код на свой страх и риск!

Данный код способен вызвать серьез­ ный сбой браузера, из-за чего операци­ онная система «очень расстроится», что может привести к потере резуль­ татов вашей работы. Используйте его на свой страх и риск!

дальш е ►

493


инф орм ация о sessionstorage

Я провожу бета-тестирование своей электронной корзины. П ользователи не хотят, чтобы содержимое и х корзины оставалось в браузере. Как м ож но удалить все элементы электронной корзины , когда пользователь закрывает браузер? Я вы­ брал не ту те хн о л о ги ю ?

Нет, Люк, есть еще один Скайуокер. О ка з ы в а е тс я , у l o c a l S t o r a g e и м е е тс я «сестра» п о и м е н и s e s s i o n S t o r a g e . Е сли в ы п о д с та в и те гл о б а л ьн ую п е р е м е н н у ю s e s s i o n s t o r a g e везде, где и с п о л ь зо в а л и l o c a l S t o r a g e , то ва ш и эле­ м е н т ы будут с о х р а н я т ь с я т о л ь к о в т е ч е н и е сеан­ са браузера. Т а к и м о б р а зо м , к а к т о л ь к о д а н н ы й сеанс з а к о н ч и т с я (д р у ги м и сл о в а м и , п о л ь зо в а ­ тел ь з а к р о е т о к н о б р а узе р а ), с о х р а н е н н ы е эле­ м е н т ы будут удалены . О б ъ е к т s e s s i o n s t o r a g e п о д д е р ж и в а е т т о ч н о та ­ к о й ж е A P I-и н т е р ф е й с , ч т о и l o c a l S t o r a g e , ноэ то м у вам у ж е и з в е с т н о о н е м все н е о б х о д и м о е . В о с п о л ь зу й те с ь и м !

494

глава 9


сохраняем данны е локально +

На данный момент вы полностью изучили API-интерфейс l o c a l S t o r a g e . Чуть ниже приведены главные действующие лица данного API-интерфейса, скрытые под масками. Посмотрите, сможете ли вы разобраться, кто из них для чего используется. В качестве примера мы соотнесли одно из описаний с нужной позицией.

dear

feffionStorage

key

И с п о л ь з у й т е м е п я для с о х р а п е п и я э л е м е п то в п а д л и т е л ь п ы й с р о к .

Я п р и п и м а ю к л ю ч и и з п а ч е п и я , к о т о р ы е за те м з а п и с ы в а ю в l o c a l S t o r a g e . И м е й т е в виду, ч т о е сли в l o c a l S t o r a g e у ж е и м е ­ е тся т а к о й к л ю ч , я п е буду п р е д у п р е ж д а ть вас об э то м , а п р о с т о п е р е з а п и ш у е го , п о э т о м у вам следует п о п и м а т ь , о ч е м в ы п р о с и т е .

Е сл и в ы с та п е те з л о у п о т р е б л я т ь г о с т е п р и и м с т в о м в l o c a l S t o r a g e и и с п о л ь зо в а ть с л и ш к о м м п о го п р о с т р а н с т в а , то будет с ге п е р и р о в а п о и с к л ю ч е н и е и в ы п о л у ч и т е о т м е п я и з в е с ти е .

setltem Н у ж п о уд а л ить элем епт? Я а к к у р а т п о в ы п о л п ю э ту работу.

removeltem

length

getltem

localStorage

QUOTAJXCEEDEDJRR

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

Я — р а з п о в и д п о с т ь х р а п и л и щ а п а к о р о т к и й с р о к : буду с о х р а п я т ь в а ш и д а п п ы е , п о к а о т к р ы т о о к п о браузера. З а к р о й т е о к п о браузе­ р а и — бац! — все в а ш и д а п п ы е и с ч е зл и . К о гд а все э л е м е п ты в l o c a l S t o r a g e б о льш е вам п е н у ж п ы , я пав о ж у п о р я д о к и в ы б р а с ы в а ю и х , о ста в л яя вам ч и с т о е и н у с т о е л о ­ ка л ь н о е х р а п и л и щ е (и м е й т е в виду, ч т о я м о гу п а в о д и т ь п о р я д о к т о л ь к о в св о е м с о б с т в е п п о м и с т о ч п и к е ).

Н у ж п о у зп а ть к о л и ч е с т в о эл е м е п то в в ваш ем l o c a l S t o r a g e ? Я п о ­ м о гу вам с э ти м .

Д а й т е м п е и п д е к с , и я п р е д о с та в л ю вам к л ю ч о т п е го в l o c a l S t o r a g e .

дальш е ►

495


вариант ы использования web storage

Теперь, когда Вы изучили localStorage, как Вы собираетесь использоВать его? С ущ еств уе т масса с п о с о б о в и с п о л ь з о в а н и я l o c a l S t o r a g e . В п р и л о ж е п и и N o te to S e lf для р а б о ­ т ы с э л е к т р о п п ы м и за м е т ка м и м ы и с п о л ь з о в а л и е го т а к и м о б р а зо м , ч т о п а м п е п о тр е б о в а л с я се р в е р , п о даж е п р и п а л и ч и и се р в е р а l o c a l S t o r a g e м о ж е т п р и п е с т и д о в о л ь п о м п о го п о л ь з ы . Н и ж е пр иве д е п ряд д р у ги х вариа пто в, к о т о р ы м и пользую тся р а зр а б о тч и ки :

0 /*

В своем новом Твиттер-клиенте я буду кэшировать с помощ ью localStorage поисковы е результаты Твиттера для повышения производительности. Когда м ои пользователи будут выполнять поиск, я сначала проверю локальны е результаты. Все это по-настоящ ему поможет м оим м обильны м пользователям.

Я буду сохранять п л е йл исты с мета­ данны ми для своих пользователей. Они см огут сохранить свои л ю б и м ы е кл и п ы вместе с временным кодом, указы ваю ­ щим, где они прервали просмотр.

Я испо льзую sessionStorage для своей новой электронной корзи­ ны в ком мерческой интернет-библио­ теке. Если пользователь закрывает окно браузера, необходим о, чтобы со ­ держимое его корзины удалялось.

496

глава 9


сохраняем данны е локально

У меня есть действительно класс­ ная игра, которая работает в двух разных окнах браузера, и я использую localStorage для син­ хронизации состояния.

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

Я испо льзую новый способ сохранения состо­ яния пользователей. Зачастую мне требовалось своего рода сеансовое хранилищ е на стороне сервера. Теперь я м о гу просто сохранять состоя­ ние м о и х пользователей локально и задейство­ вать код на стороне сервера, только когда мне приходится это делать.

дальш е ►

497


обзор web storage

КЛЮЧЕВЫЕ -------------------------- МОМЕНТЫ ■

Web Storage — это хранилище в вашем браузере и APIинтерфейс, который вы можете использовать для сохранения и извлечения элементов из хранилища.

Большинство браузеров обеспечивают по крайней мере по 5 Мбайт хранилища на каждый источник.

Web Storage состоит из

l o c a l S t o r a g e

пункт Delete (Удалить) (данный подход работает не во всех браузерах). ■

Вы можете удалять элементы из l o c a l S t o r a g e в коде, используя методы r e m o v e l t e m ( к л ю ч - ) и c l e a r . Следует отметить, что метод c l e a r удаляет все элементы в l o c a l S t o r a g e в том источнике, где вы проводите очистку.

Ключи для всех элементов l o c a l S t o r a g e должны быть уникальными. Если вы примените тот же ключ, который уже имеется у существующего элемента, то перезапишете значение данного элемента.

Сгенерировать уникальный ключ можно с использова­ нием значения текущего времени в миллисекундах, про­ шедших с 1970 года, прибегнув к методу g e t T i m e ( ) объекта D a t e .

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

Web Storage в текущий момент поддерживает сохране­ ние строк как значений для ключей.

Вы можете преобразовывать числовые значения, со­ храненные в l o c a l S t o r a g e как строки, в числовые значения, используя p a r s e l n t или p a r s e F l o a t .

Если вам потребуется сохранить комплексные данные, можете воспользоваться JavaScript-объектами и пре­ образовать их в строки перед сохранением, прибегнув к j s o n . s t r i n g i f y , а после извлечения преобра­ зовать их снова в объекты с помощью J S O N . p a r s e .

Локальное хранилище может оказаться особенно по­ лезным на мобильных устройствах для снижения тре­ бований к пропускной способности канала.

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

и

s e s s io n s to ra g e .

Локальное хранилище сохраняет данные на постоянной основе, даже если вы закроете окно браузера или во­ обще завершите его работу.

Элементы в s e s s i o n S t o r a g e будут удалены, если вы закроете окно браузера или завершите его работу. s e s s i o n S t o r a g e хорошо подходит для временных элементов, но не годится как хранилище для данных на более длительный срок.

И lo c a lS to ra g e , и s e s s io n S зуют один и тот же API-интерфейс.

исполь-

Web Storage предусматривает организацию по источни­ ку (считайте — домену). Источник — это местоположе­ ние документа в Интернете (например, wickedlysmart. com или headfirstlabs.com).

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

to ra g e

Используйте l o c a l S t o r a g e . s e t l t для добавления значения в хранилище.

e m

Используйте l o c a l S t o r a g e . g e t l t для извлечения значения из хранилища.

e m (

Вы можете использовать тот же синтаксис, который при­ меняется в случае с ассоциативными массивами, для со­ хранения элементов в хранилище и извлечения их отту­ да. Используйте для этого l o c a l S t o r a g e [ клю ч] .

■ ■

Используйте метод l o c a перечисления ключей в l o

lS t o r a g e

(ключ-)

. k ey

ключ)

() для

c a lS to ra g e .

— это количество эле­ в определенном источнике.

l o c a l S t o r a g e . le n g th

ментов в l o

c a lS to ra g e

Используйте консоль в своем браузере для просмотра и удаления элементов в l o c a l S t o r a g e .

Вы мож ете у д а л я ть элем енты напрям ую из l o c a l S t o r a g e , щелкнув правой кнопкой мыши на том или ином элементе и выбрав в появившемся меню

498

глава 9


сохраняем данны е локально

U I M L 5 - K f ° CCB ° r A Ц ^ Ф

V tTA Trи TTте T»^ п ТТ^Т^/ЛТ’ Уд ел е к о т оПГЧ/ЛА р о е кТ/П о лТТиТТчТТА е с/'Т т’ вЮ/Л о врем епи тестир о ва ­ н и ю с в о е го с о б с т в е п п о го л о к а л ь п о го х р а п и л и щ а .

а г г

■ ■

п

м ■ ■ ■ ■

По горизонтали

По вертикали

4.Имя сестры Люка Скайуокера.

1. Мы создаем___________ для размещения текста заметки и ее

5.Когда мы использовали значение____________ l o c a l S t o r a g e для генерирования имен ключей, то столкнулись с проблемой — в последовательности имен наших клейких заметок оказались бреши.

2. У файлов c o o k i e имеется проблема с _____________ . 3. Мы использовали_____________ для размещения ключей всех наших клейких заметок, благодаря чему отыскать их

7. l o c a l S t o r a g e позволяет сохранять только____________. 9. Мы можем выяснить, на какой заметке щелкнул пользователь, обратившись к e v e n t . _____________. 10. Нам необходимо преобразовать объект с помощью метода _____________ , прежде чем сохранять его в l o c a l S t o r a g e . 11. Большинство браузеров предлагает_____________ мегабайт хранилища на каждый источник. 12. Данный метод используется для сохранения элементов в

lo c a lS to r a g e. 14. Мы полагали, что можно лишь мечтать о возможности сохра­

цвета в одном элементе l o c a l S t o r a g e .

в l o c a l S t o r a g e не составит труда. Сеансовое хранилище подобно локальному хранилищу за ис­ ключением того, что элементы, которые в него помещены, не сохраняются там н а _____________ основе и удаляются, если вы закрываете окно браузера. 8. Используйте____________для преобразования строки в цело­ численное значение. 13. Если вы сохраните что-то в своем браузере и полетите на , то оно по-прежнему будет там, когда вы вер­ нетесь. 6.

нить ______________ в l o c a l S t o r a g e , но, как оказалось, она существует, и дает ее JSON. 15. Используйте t r y / ________ для выявления ошибок, возника­ ющих из-за превышения квоты хранилища, в l o c a l S t o r a g e .

дальш е ►

499


реш ение упражнения

Ц гР а В

ско р л упки, ^е ^е н и е

________________________________________

£

Готовы испытать удачу (или, скорее, сноровку)? Данная игра позволит проверить, насколько хорошо вы знаете l o c a l S t o r a g e , однако вам потребуется проявить решительность. Используйте свои знания об извлечении и сохранении пар «КЛЮЧ — значение» В l o c a l S t o r a g e , чтобы уследить за горошиной, когда она будет перемещаться от одной скорлупки к другой. Вот наше решение этого задания.

f u n c t i o n s h e ll G a m e ( ) { l o c a l S t o r a g e . s e t l t e m ( " s h e l l l " , "p ea" ); l o c a l S t o r a g e . s e t l t e m ( " s h e l l 2 ", " e m p t y " ) ; l o c a l S t o r a g e . s e t l t e m ( " s h e l l 3 " , "em pty"); l o c a l S t o r a g e [ " s h e l l l " ] = "empty"; l o c a l S t o r a g e [ " s h e l l 2 "] = "pea"; l o c a l S t o r a g e [ " s h e l l 3 " ] = "empty"; v a r v a l u e = l o c a l S t o r a g e . g e t l t e m ( " s h e l l 2 " ); lo c a lS to r a g e . s e tlt e m ( " s h e lll" , v a lu e ); v a lu e = l o c a l S t o r a g e . g e t l t e m ( " s h e l l 3 " ); l o c a l S t o r a g e [ " s h e l l 2 "] = v a l u e ; v a r k ey = " s h e l l 2 " ; l o c a l S t o r a g e [ k e y ] = "pea"; k ey = " s h e l l l " ; l o c a l S t o r a g e [ k e y ] = "empty"; k ey = "s h e l l 3 "; l o c a l S t o r a g e [ k e y ] = "empty"; for

(v a r i = 0; i < l o c a l S t o r a g e . l e n g t h ; i+ + ) v a r k ey = l o c a l S t o r a g e . k e y (i ) ; var v a lu e = lo c a l S t o r a g e . g etltem (k e y ) ; a l e r t ( k e y + ": " + v a l u e ) ;

Под какой с к ор луп к о й н а х о ­ дит ся горош ина ("реа")?

К люй

З н а ч ен и е

sb e //X

e m p ty

s h d lZ

реа

$1ле11з

e m p ty

Горошина ("реа") находится под скорлупкой Z ("skellZ").. {

}

пражнение решение

Ваша задача заключалась в том, чтобы обновить весь код таким образом, чтобы везде, где мы стали бы вызывать addStickyToDOM, мы передавали ключ, а также значение. Вам следовало обновить все вызовы addStickyToDom в i n i t и c r e a t e S t i c k y , чтобы они выглядели следующим образом: addStickyToDOM(key, v a l u e ) ;

500

глава 9


сохраняем данные локально

Зозьми в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Решение Отметьте флажками, какие проблемы может вызывать наша текущая реализация: Отображение клейких заметок будет происходить неэффективно, если в l o c a l S t o r a g e присутствует большое количество элементов, которые не являются заметками.

0

Клейкая заметка может быть перезаписана методом s e t l t e m , если объем l o c a l S t o r a g e уменьшится, несмотря на то что другое приложение удалит все свои элементы.

х

Сложно быстро сказать, сколько имеется клейких заметок; вам придется осуществлять итерацию по каждому элементу в l o c a l S t o r a g e , чтобы извлечь все заметки. □

Используйте файлы cookie, поскольку такой подход должен оказаться проще!

пражненне решение

Нам по-преж нем у нуж но вы яснить, как ф акти чески осущ ествл яется со хр ан ени е м ассива в lo c alS to ra g e Вы уже могли догадаться, что у нас есть возможность использовать JSON для создания строкового представления массива. И если так и было, то вы правы. Располагая таким представлением, вы сможете сохранить его в l o c a l S t o r a g e . Как вы помните, в API-интерфейсе JSON имеются только два метода: s t r i n g i f у и p a r se . Задействуем данные методы и завершим функцию i n i t :

Извлекаем массив из localStoraae. ]

Если в localStorage не окажемся массива, то мы создадим пустой массив I*и присвоим его переменной stickiesArray. пусто сд телики 8 данный момент переменная stickiesArray будет строкой

'

I

\ f u n c t i o n i n i t () //

{

з д е с ь б у д е т код,

касающийся b u t t o n . .*

var s t ic k ie s A r r a y = lo c a lS to r a g e [" s tic k ie sA r r a y " ] ; if

(! s t i c k i e s A r r a ) I y s tic k ie s A r r a y = [];

/

у

l o c a l S t o r a g e . s e t l t e m ( " s t i c k i e s A r r a y " , JSON. s } else

{

stick ie sA rr a y

tr in g ify

_ = J S O N .p a rse ( s t i c k i e s A r r a y ) ;

} for

(var i

=

0; i

<

s t ic k ie s A r r a y . len g th ;

i+ + )

{ ^\

v a r k ey = s t i c k i e s A r r a y [ i ] ; v a r v a l u e = l o c a l S t o r a g e [key] ; addStickyToDOM ( v a lu e ) ; }

I

/

ЕГ/> л и нам и л а лпридется i/o#i А о мл />сг создать /'л з И л м Если массив, то мы воспользуемся JSON.stringifу для генерupования строкового представления массива, а затем сохраним его...

(stick iesA r ra y ) ) ;

Если массив stickiesArray уже будет сохранен в localStorage (в виде строки), нам потребуется преоб­ разовать егоj используя метод parse A P I -интерфейса JSON. После этого в нашем распоряжении окажется массив ключей, присвоенный переменной stickiesArray.

Чтобы вам все было ясно: мы берем строку, на которук, указывает stickiesArray, преобразовываем ее в массив с помощью метода parse а затем снова присваиваем этот массив переменной stickiesArray. '

дальш е ►

501


реш ение упражнения

Ш ПЫТАЙТЕСЬ СДЕЛАТЬ ЭТО ДОМА (И ЛИ КАК РАЗНЕСТИ В ПУХ II 1IPAX ВАШ И 5 МБАЙТ) Как мы уже говорили, в сумме у вас будет 5 Мбайт хранилища для браузера каждого из пользователей. Несмотря на то что такой объем может показаться большим, все ваши данные сохраняются в виде строк, а не в байтовом формате. Возьмите, к примеру, размер государственного долга: если выразить его в виде значения с плавающей точкой, то для его размещения в хранилище потребуется не много места, однако если выразить его в виде строкового значения, то для его сохранения потребуется гораздо больший объ­ ем. Таким образом, хранилище размером 5 Мбайт способно вместить не так много, как могло показаться. Так что же произойдет, когда вы исчерпаете 5 Мбайт? К сожалению, это одно из поведений, которые не определяются спецификацией HTML5, и браузеры могут поступать по-разному, когда вы превысите свой лимит. Браузер может спросить у вас, хотите ли вы увеличь объем хранилища, либо сгенерирует исключе­ ние QUOTA_EXCEEDED_ERR, которое можно перехватить следующим образом:

try W c a t c k пере-

catch(e)

x6aw t>i6aew АУС ии скл ю ч е н и я , г Р

руелльл 6 блоке

{ l o c a l S t o r a g e . s e t lt e m ( m y K e y , m y V a lu e ) ;

if

9

{

(e == QUOTA_EXCEEDED_ERR) a lert(" O u t o f sto ra g e

}

J

Г )У

П р о ве р я е м , ошибка ли э т о квот ы х р а н и л и щ а (а не к а к о й - т о другой т и п исключения). Если т а к оно и е с т ь , м ы выведем для п о л ь з о в а т е л я диалоговое окно a le rt с с о о т в е т с т в у ю щ и м сообщением. В ы , скорее всего; з а х о т и т е сд е ла т ь ч т о - т о более з н а ч и т е л ь ­ ное, чем п р о с т о вывод окна alert.

Не все браузеры в н а ст о я щ и й м о ­ м е н т г е н е р и р у ю т исклю чение QUOTA_ EXCEEPEP_ERR. Однако они все же с г е н е р и р у ю т и с к л ю ч ен и е , когда вы п р е в ы с и т е свой л и м и т , п о э т о м у н е ­ л и ш н и м будет р азоб р ат ь ся с общ им с лу ч а е м исклю чения при сохранении т о го или иного э л е м е н т а в храни лищ е.

502

глава 9

{

В о т вызов s e t l t e m в с е ­ редине блока t r y ; если ч т о -н и б у д ь п о й д е т не т ак и setltem сгенери­ р у е т исключение, т о будет задейст вован блок catch.


сохраняем данны е локально

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

<html> <head>

Начнем с односимвольной строки с клю чом "fuse".

< scr ip t>

l o c a l S t o r a g e . s e t l t e m ( " f u s e ", w h ile(tr u e )

И просто будем, не останавливаясь, увеличивать ее размер...

;

{

...путем удваивания этой с т р о ­ ки (посредством конкатенации ее с самой собой)..

v a r f u s e = l o c a l S t o r a g e . g e t l t e m ("f u s e " ) try

{ lo c a lS to r a g e . se tlte m (" fu se " , fuse + fu se );

} catch(e)

{

З а т е м попытаемся записат ь ее обратно в localStorage.

a l e r t ( " Y o u r b r o w s e r b l e w up a t" + f u s e . l e n g t h + " w i t h e x c e p t i o n :

" + e);

break; }

Не будем ост авлять беспорядок и уда ­ л и м данный элем ент из localStorage.

}

l o c a l S t o r a g e .r e m o v e l t e m ( " fu s e " ); < /sc rip t> < /h e a d >

- Если браузер аварийно з а ­ верш ит работ у — дело сделано! Выведем для пользователя диалоговое окно alert с с о о т в е т с т в у ­ ю щ им сообщением и вы й­ дем из данного цикла.

<body> < /b o d y > < /h t m l> Наберите этот код, «зажгите фитиль», загрузив его, и поразвлекайтесь! Испытайте его в разных браузерах.

Результат ы, получившиеся у нас при использовании брау­ зеров Safari и Chrome.

h ttp './/lo c a lh o s t

The page at focathost says:

Y o u r brow ser blew up a t 2 0 9 7 1 5 2 w ith excep tio n : Error: QUOTA_EXCEEDED_ERR: D O M Exception 2 2

Your browser blew up at 2 0 9 7 1 5 2 with exception: Error: QUОТA_EXCEEDED_ERR: DOM Exception 22

(

ok

)

(

o*

)

дальш е ►

503


решение упражнения

--------------------------------------------------------------------------------------------------

+

К

Т

9

И

РЕШЕНИЕ На данный момент вы полностью изучили API-интерфейс l o c a l S t o r a g e . Чуть ниже приведены глав­ ные действующие лица данного API-интерфейса, скрытые под масками. Посмотрите, сможете ли вы разобраться, кто из них для чего используется. В качестве примера мы соотнесли одно из описаний с нужной позицией.

И с п о л ь з у й т е м е п я для с о х р а п е п и я э л е м е п то в п а д л и т е л ь п ы й с р о к .

ieiiion$tora?e

Я п р и п и м а ю к л ю ч и и з п а ч е п и я , к о т о р ы е за те м з а п и с ы в а ю в l o c a l S t o r a g e . И м е й т е в виду, ч т о е сли в l o c a l S t o r a g e у ж е и м е ­ ется т а к о й к л ю ч , я п е буду п р е д у п р е ж д а ть вас об э то м , а п р о с т о п е р е з а п и ш у е го , п о э т о м у вам следует п о п и м а т ь , о ч е м в ы п р о с и т е .

Е сли в ы с та п е те з л о у п о т р е б л я т ь г о с т е п р и и м с т в о м в l o c a l S t o r a g e и и с п о л ь з о в а т ь с л и ш к о м м п о го п р о с т р а н с т в а , т о будет с ге п е р и р о в а п о и с к л ю ч е н и е и в ы п о л у ч и т е о т м е п я и з в е с ти е .

Н у ж п о уд а л ить элем епт? Я а к к у р а т п о в ы п о л п ю э ту работу.

removeltem

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

Я — р а з п о в и д п о с т ь х р а п и л и щ а п а к о р о т к и й с р о к : буду с о х р а п я т ь в а ш и д а п п ы е , п о к а о т к р ы т о о к п о браузера. З а к р о й т е о к п о браузе­ р а и — бац! — все в а ш и д а п п ы е и с ч е зл и .

getltem

localStorage

QUOTA EXCEEDED ERR

504

глава 9

К о гд а все э л е м е п ты в l o c a l S t o r a g e бо льш е вам п е н у ж п ы , я пав о ж у п о р я д о к и в ы б р а с ы в а ю и х , о с та в л я я вам ч и с т о е и н у с т о е л о ­ ка л ь н о е х р а п и л и щ е (и м е й т е в виду, ч т о я м о гу п а в о д и т ь п о р я д о к т о л ь к о в св о е м с о б с т в е п п о м и с т о ч п и к е ).

Н у ж п о у зп а ть к о л и ч е с т в о эл е м е п то в в ваш ем l o c a l S t o r a g e ? Я п о ­ м о гу вам с э ти м .

Д а й т е м п е и п д е к с , и я п р е д о с та в л ю вам к л ю ч о т п е го в l o c a l S t o r a g e .


сохраняем данные локально

Ш

1

П Ш

- 1Т восВТ А - Г « т ен и е

дальш е ►

505



10 гриМеняеМ JavaScript на ДеЛе

#

API-интерфейс Web Workers + Да, я не см о гу справиться здесь со ВСЕМ мне потребуется неболь­

Я м о гу помочь тебе разобраться с этой шахтой лифта.

шая помощь.

Медленный сценарий — хотите продолжить его выполнение? Если вам доводилось тесно работать с JavaScript или путешествовать по Интернету, то вы, вероятно, сталкивались с диалоговым окном Slow Script (Медленный сценарий). Но как же сейчас, когда в компьютерах устанавливаются многоядерные процессоры, сценарии могут выполняться слишком медленно? Все потому, что JavaScript поддерживает выполнение только одного действия за раз. Однако с появлением HTML5 и Web Workers все изменилось. Теперь у вас есть возможность создавать собственные множественные JavaScript-объекты

w o rk e r

для одновременного выполнения

нескольких действий. Независимо оттого, пытаетесь вы создать более отзывчивое приложение либо просто хотите по максимуму использовать возможности центрального процессора — API-интерфейс Web Workers придется кстати. Итак, надевайте шляпу директора предприятия под названием JavaScript и заставьте своих подчиненных

w o rk e r

попотеть!


ja v a s c rip t-пот оки

Устрашающее диалоговое окно Slow Script (Медленный сценарий) О д п о й и з п р и м е ч а т е л ь п ы х о с о б е п п о с т е й J a v a S c rip t я в л я ­ е тся т о , ч т о о п п о д д е р ж и в а е т в ы п о л п е п и е т о л ь к о о д п о го д е й с т в и я за р аз — м ы о б ы ч п о п а зы в а е м э то о д п о п о т о ч п о с т ь ю . П о ч е м у д а п п а я о с о б е п п о с т ь п р и м е ч а те л ь п а ? А п о то м у, ч т о о п а делает п р о ц е с с п р о гр а м м и р о в а н и я п р о с т ы м . К о гд а у вас и м е е т с я м п о ж е с т в о п о т о к о в , п р о ­ т е к а ю щ и х о д п о в р е м е п п о , п а п и с а п и е к о р р е к т п о р а б о та ­ ю щ е й п р о гр а м м ы м о ж е т п р е в р а т и т ь с я в с л о ж н у ю задачу.

Н е д о с т а т о к о д п о п о т о ч п о с т и з а кл ю ч а е тс я в т о м , ч т о е сли в зв а л и ть н а Ja va S crip t-n p o rp a M M y с л и ш к о м м п о г о р а б о т ы , о п а м о ж е т п е ус п е в а ть с п е й с п р а в л я ть с я , и в и т о г е п а э к р а п е м ы у в и д и м о к п а Slow S c rip t (М е д л е п п ы й с ц е п а р и й ). Д р у го е п о с л е д с т в и е о д п о п о т о ч п о с т и с о с т о и т в т о м , ч т о е сли у вас и м е е т с я J a v a S c rip t-код , к о т о р о м у п р и х о д и т с я и п т е п с и в п о р а б о та ть , т о будет о ста в а ть с я п е о ч е п ь м п о го в ы ч и с ­ л и т е л ь н ы х р е с ур с о в для и н т е р ф е й с а п о л ь з о в а те л я и л и в з а и м о д е й с т в и й п о л ь з о в а те л е й , и ваш е п р и л о ­ ж е н и е м о ж е т п о ка з а т ь с я м е д л е п п о р а б о т а ю щ и м и л и п е о т з ы в ч и в ы м .

Как JavaScript проводит сбое Время Д а в а й те п о с м о т р и м , ч т о э то все о зп а ча е т, в згл я н у в , к а к J a v a S c rip t о б р а б а т ы в а е т за д а чи , ка с а ю щ и е с я т и п и ч п о й в е б -с тр а п и ц ы :

JavaScript-nom ok

Г сI С

В о т ч т о мы и м е е м в виду под о д н о п о т о ч носты-о. J a v a S c r ip t пошагово вы п о л н яе т всеj ч т о е м у нужно с д е л а т ь , одно за д р у ­ ^ гим. Никакого п а р а л ­ лельного выполнения ^ здесь нет.

Я здесь только один, но взгляните, сколько всего я делаю , обрабатывая по одной задаче за раз.

В ы пол нение ф ункц ии in it

11

ИТ

Обработка события clic k Значение времени таймера исте кло

j

Обработка собы тия subm it

'

Обработка массива данны х \ Обработка с л е д ую щ е го собы тия c lic k

|

|

О бновление объектной

С

\ м одел и документа (D O M ) Выборка данны х ф ормы

I 508

глава 10

П роверка введенных пользователем данны х

*

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


применяем ja v a s c rip t на деле

Когда однопоточность — это ПЛОХО Д е й с т в и т е л ь н о , во м п о г и х с и т у а ц и я х д а п п ы й о д п о п о т о ч п ы й р е ж и м в ы ч и с л е п и й с и с п о л ь з о в а н и е м J a v a S c rip t о т л и ч п о р а б о та е т и , к а к м ы у ж е о тм е ч а л и , делает п р о ц е с с п р о гр а м м и р о в а н и я п р о с т ы м . О д п а к о если в ы п а п и ш и т е ко д , к о т о р ы й будет тр е б о в а ть п а с т о л ь к о б о л ь ш о го о б ъ ем а в ы ч и с л е п и й , ч т о э то п а ч п е т о т р и ц а т е л ь н о с ка зы в а т ь с я п а с п о с о б н о с т я х J a v a S c rip t, о д п о п о т о ч п а я м одель с т а п е т ра зва л и ва ть ся.

JavaScript-nom ok

В ы полнение ф ункции in it Обработка собы тия clic k

г I ..

Значение времени таймера истекло

I

<

Обработка события subm it

I

ж -ж -ж

Все б удет з а м е ч а ­ тельно работ ат ь до т е х п о р , пока ч а с т ь J a v a S c r i p t -кода не н а ч ­ н е т т р е б о в а т ь много врем ени на о б р а б о т к у , к о т о р о е будет з а ­ бират ься у работ ы J a v a S c r ip t по в з а и м о ­ д е й с т ви ю с п о л ь з о в а ­ т елем и инт ерфейсом.

О й, обработ ка большого м ассива з а н и м а е т м ного врем ени!

Обработка массива данны х

Ж-Ж-Ж

Кто это прибрал к ру­ кам все время на обра­

ж -ж - ж

ботку? Обработка сл е д ую щ е го __ л ^ собы ти я c lic k

Что у вас там наверху происходит? Задачи не выполняю тся!

Обновление объектной 1 ^ о д е л и докум ента ( D O M ) ^ Выборка данны х ф ормы > Г

- --------------------------------- Н Проверка введенных пользователем данны х

0 Q

П ользователи уходят! Интерфейс не обновляется!

4

О Все, м ы сдаемся, выво­ дите диалоговое окно Slow S c rip t (М едленны й сценарий).

дальш е ►

509


api-инт ерф ейс ja v a s c rip t web w orkers

Добавление еще одного потока управления в качестве помощника Д о п о я в л е п и я H T M L 5 м ы п р и д е р ж и в а л и с ь п о д х о д а п а о с п о в е о д п о го п о т о к а у п р а в л е п и я для с в о и х с т р а п и ц и п р и л о ж е п и й , о д п а ко б л а го д а р я W eb W o rk e rs у п а с п о я в и л с я с п о с о б созд ать еще о д и п п о т о к у п р а в л е п и я для о к а з а п и я п о м о щ и гл а в п о м у п о то к у . Т а к и м о б р а зо м , е сли ваш к о д будет о т п и м а т ь м п о го в р е м е п и п а о б р а б о тку , в ы с м о ж е те созд ать ф о п о в ы й в е б -с ц е п а р и й w o r k e r (б л о к J a v a S c rip t-кода, в ы п о л ­ н я ю щ и й с я в ф о п о в о м р е ж и м е ), к о т о р ы й за й м е тс я о б р а б о т к о й за д а чи , п о к а гл а в п ы й J a v a S c rip t-п о т о к у п р а в л е п и я будет з а б о т и т ь с я о т о м , ч т о ка с а е тс я бр а узе р а и п о л ьзо в а те л я .

В м е с т о т ого чтобы замедлять? вы полнение з а ­ дач и з - з а большого объем а вычислений J a v a S c rip t, мы м ож ем создат ь веб -сц ен а ри й w o r k e r , к о т ор ы й будет вы п о л нят ь с я в о т д е л ь н о м п о т о к е и з а н и ­ м а т ь с я всей тяжелой работой. i f

JavaScript-nom ok

П о то к Веб-сценария worker

i В ы пол нение ф ункции in it Обработка собы тия c lic k

На э т о т ра з все и д е т ( гладко, в е б сценарии w o r k e r забо т ит ся о вы­ числениях:, за н и м а ю щ и х продолж и­ т е л ь н о е вре _ ^ мя...

(

1

начение времени таймера истекло

Worker ^Обработка события onsubm ilj

Ребята, делайте все необходимое, чтобы пользователь был доволен, а я займусь этой задачей;

Создание веб-сценария w o rk e r _____■ Обработка с л е д ую щ е го со

41JX

Обновление объектной J м одели документа (Р О М ) 7 Обработка массива данны х

С

Выборка данны х ф ормы i фоверка введенных пользователем данны х ^И спользование массива Выборка данны х ф ормы

С

j П роверка введенны х^

А когда задача б удет вы полнена, веб -сц ен а ри й

|

w o r k e r даже см ож ет п р и с л а т ь нам данные, над к о т о р ы м и он р а б о т а л , а м ы сможем в к л ю ­ ч и т ь их в наше прилож ение .

пользователем данны х

М ы о со б о п о д ч е р к и в а л и в а ж п о с т ь т о г о ф а кта , ч т о о д и п п о т о к у п р а в л е п и я о б е с п е ч и в а е т п р о с т о т у и л е г­ к о с т ь п р о ц е с с а п р о гр а м м и р о в а н и я , и э то правда. К а к в ы ещ е у в и д и т е , A P I-и п т е р ф е й с W e b W o rk e rs б ы л тщ а те л ь п о п р о р а б о т а л , ч т о б ы все о с та в а л о сь п р о с т ы м и п а д е ж п ы м для п р о гр а м м и с т а . Ч у т ь п о з ж е м ы узп а е м п а с к о л ь к о .

510

глава 10


применяем ja v a s c rip t на деле

J A V A S C R IP T

(С Й 0 1 3 А )

Интервью недели: Где JavaScript проводит свое время? Head First: С в о зв р а щ е н и е м , J a v a S c rip t, п р и я т п о Вас в и д е ть. JavaScript: Рад б ы ть здесь, п о да ва й те п р и д е р ж и в а т ь с я м о е го гр а ф и к а , а т о у м е п я еще о ч е п ь м п о го дел. Head First: И м е п п о п а э то м , к а к я по л а га л , м ы и м о гл и б ы с о с р е д о т о ч и т ь с я во в р е м я с е го д п я ш п е го ра з­ го в о р а . В ы ста л и с в е р х у с п е ш п ы м п а р п е м , у Вас т а к м п о го в с е го п р о и с х о д и т — к а к В ам удается со всем справляться? JavaScript: Ч т о ж , у м е п я есть ф ило со ф ия: я делаю что -то од п о за раз, п о делаю это п о -п а сто ящ е м у х о р о ш о . Head First: К а к э то В ы делаете т о л ь к о ч т о -т о о д п о за раз? К а к п а м к а ж е т с я , в ы и з в л е ка е те д а п п ы е , о т о ­ б р а ж а е те с т р а п и ц ы , в за и м о д е й ств у е те с п о л ьзо в а те л е м , уп р а в л я е те та й м е р а м и и д и а л о го в ы м и о к п а м и a l e r t , п е о ста н а в л и в а я сь... JavaScript: Д а , я все э то делаю , п о в о п р е д е л е п п ы й м о м е п т в р е м е п и то л ь к о ч т о -т о о д п о . Т а к и м об р а зо м , если я в за и м о д е й с т в у ю с п о л ьзо в а те л е м , то э т и м все и будет о гр а н и ч и в а т ь с я до т е х п о р , п о к а я п е р а з­ берусь с д а п п о й задачей.

Head First: Н е у ж е л и э то правда? А если з п а ч е п и е в р е м е п и та й м е р а и с т е ч е т, л и б о п о с е ти п о с т у п я т д а п ­ п ы е , л и б о п р о и з о й д е т ч т о -т о д р у го е — ра зве В ы п е о с т а н о в и т е с ь и п е за й м е те сь этим ? JavaScript: П р и п а с т у п л е п и и с о б ы т и я вр о д е т е х , о к о т о р ы х в ы у п о м я н у л и , о п и будут д о б а в л е п ы в о ч е ­ редь. Я даж е п е в згл я н у п а п и х , п о к а п е з а к о п ч у т о , пад ч е м р а б о та ю . И с п о л ь з у я т а к о й п о д х о д , я делаю все п р а в и л ь п о , п а д е ж п о и э ф ф е к т и в н о .

Head First: А сл уча л о сь л и ко гд а -п и б у д ь т а к , ч т о В ы с о п о з д а п и е м д о б и р а л и с ь до о д п о й и з т е х зад ач в очере д и?

JavaScript: О , т а к бы вает. К сч а с т ь ю , я я в л я ю с ь т е х п о л о г и е й , с то я щ е й за б р а у зе р п ы м и в е б -с тр а п и ц а м и , п о э т о м у ч т о у ж т а к о г о п л о х о го в т о м , е сли я буду п е м п о г о запазды вать? В ам луч ш е п о г о в о р и т ь с п а р п я м и , к о т о р ы м п р и х о д и т с я в ы п о л п я т ь ко д , у п р а в л я ю щ и й р а б о т о й д в и га т е л е й к о с м и ч е с к и х к о р а б л е й и к о п т р о л л е р о в а т о м п ы х э л е к т р о с т а п ц и й ... Э т и р е б я та в ы н у ж д е п ы ж и т ь п о д р у ги м п р а в и л а м — в о т п о ч е м у о п и м п о г о за р а б а ты в а ю т.

Head First: М п е в се гд а б ы л о и п т е р е с п о у з п а т ь , ч т о п р о и с х о д и т , к о гд а у м е п я в б р а узе р е п о я в л я е т с я д и а л о го в о е о к п о с с о о б щ е п и е м о м е д л е п п о м с ц е п а р и и и в о п р о с о м о т о м , х о ч у л и я п р о д о л ж и т ь е го вы п о л п е п и е . Э то из-за т о г о , ч т о В ы б е р е те п е р е р ы в ? JavaScript: Б е р у п е р е р ы в ! Х а ! Т а к бы вает, к о гд а к т о -т о п е гр а м о т п о с т р у к т у р и р о в а л с в о ю стр а п и ц у , — т а к и м о б р а зо м и п а м е п я в зв а л и в а е тся с т о л ь к о р а б о т ы , ч т о я п е м о гу с п е й с п р а в и т ь с я ! Е сл и в ы п а п и ш е те п е б о л ы н о й б л о к J a v a S c rip t-код а, к о т о р ы й будет о т п и м а т ь все м ое в р е м я , т о ваш е в з а и м о д е й с т в и е с п о л ь зо в а те л е м п о стр а д а е т. Я м о гу в ы п о л п я т ь т о л ь к о ч т о -т о о д п о за раз.

Head First: П о х о ж е , В ам тр е б у е тс я п о м о щ ь . JavaScript: Э та п о м о щ ь м п е о ка зы в а е т с я б л а го д а р я H T M L 5 , п о с к о л ь к у и м е п п о здесь в дело в с ту п а е т A P I-и п т е р ф е й с W eb W o rk e rs . Е сли вам н у ж п о п а п и с а т ь ко д , т р е б у ю щ и й б о л ь ш о го объем а в ы ч и с л е п и й , — и с п о л ь зу й т е W eb W o rk e rs , ч т о б ы с п я т ь с м е п я ч а с ть р а б о ты . Б л а го д а р я э то м у я с м о гу с о с р е д о т о ч и т ь с я п а с в о и х задачах, а ве б -сц е па р и и w o rk e r сделаю т за м е п я п е к о т о р у ю тя ж е л у ю ра б о ту (п е меш ая п р и э то м м п е ).

Head First: Э то и п т е р е с п о , м ы иссл едуем д а п п ы й а с п е кт. А т е п е р ь с л е д у ю щ и й в о п р о с ... П о с т о й т е -к а , о п и с ч е з. П о х о ж е , уш ел за п и м а т ь с я с в о е й сл е д ую щ е й зад ачей. С е р ь е з п ы й о п п а р е п ь , п е п р а в д а ли? дальше ►

511


как работ аю т веб-сценарии w orker

Как работают веб-сценарии worker Д а в а й те в згл я п е м п а о д и п д е п ь и з ж и з п и в е б -сц е п а р и е в w o rk e r: к а к о п и со зд а ю тс я , о тку д а о п и зп а ю т, ч т о дел ать, и к а к о п и в о зв р а щ а ю т р е зу л ь та ты ваш ем у о с п о в п о м у б р а у зе р п о м у коду.

Для их использования браузеру сначала потребуется создать один веб-сценарий worker (или более), который станет помощником в решении задач. Каждый worker определяется посред­ ством своего собственного JavaScript-файла, содержащего весь код (или ссылки на код), необ­ ходимый ему для выполнения своей работы. _ . Каждый вео -сц енар ии w o rk e r определяет ся посредст вом о т д е л ь ного Jav a S c rip t -файла.

Я действительно м о г N бы воспользоваться по) мощью... создав один w o rke r,

\

Браузер Все веб-сценарии worker живут в очень ограниченном мире; у них нет доступа к множеству объ­ ектов времени выполнения, который имеется у вашего основного браузерного кода, например к объектной модели документа (DOM) или любым переменным либо функциям в коде.

Н ичего себе! Я не м о гу получить доступ к DOM или чем у-либо другом у в основном браузерном коде.

Так будет намно­ го безопаснее — тебе не

Браузер

512

глава 10

нужно изменять объектную модель документа, это моя работа.

0

3


применяем ja v a s c rip t на деле

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

У меня есть для тебя работа.

200 х 200 пикселов. Я м о гу сделать это для тебя.

сообще­ ние

Worker Браузер

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

Вот работа, которую ты просил сделать.

Браузер

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

дальш е ►

513


дост уп к dom

П очем у бы не разре­ шить веб-сценариям w o rke r доступ к объектной модели документа? П о х о ­ же, отправка сообщ ений туда-сю да доста­ вит массу х л о п о т, если все веб-сценарии w o rke r будут выполняться в одном и том же браузере.

Отсутствие у них доступа к DOM объ ясня­ ется стремлением обеспечить эф ф ектив­ ность. П р и ч и н а , п о к о т о р о й о б ъ е ктн а я модель д о к у ­ м е н та и Ja v a S c rip t я в л я ю тс я с то л ь у с п е ш н ы м и , за кл ю ч а е тс я в то м , ч т о м ы м о ж е м з н а ч и т е л ь н о о п ти м и зи р о ва ть операци и с D O M , поскол ьку у нас и м е е тс я т о л ь к о о д и н п о т о к с д о с т у п о м к D O M . Е сли м ы п о з в о л и м сразу н е с к о л ь к и м вы числительны м потокам одноврем енно вно­ с и т ь и з м е н е н и я в D O M , э то с е р ье зн о у д а р и т п о у р о в н ю п р о и з в о д и т е л ь н о с т и (а р а зр а б о т­ ч и к а м б р а узе р о в п р и ш л о с ь б ы п р и л а га т ь б о л ь­ ш и е у с и л и я , ч т о б ы уб е д и ть с я в б е з о п а с н о с т и в н е с е н и я и з м е н е н и й в о б ъ е к т н у ю м одель д о к у ­ м е н т а ). Ч е с т н о го в о р я , если р а з р е ш и т ь о д н о ­ врем енное внесение ку ч и и зм е н е н и й в D O M , э то м о ж е т п р и в е с т и к с и т у а ц и я м , ко гд а D O M о к а ж е т с я в н е с о гл а с о в а н н о м с о с т о я н и и , а э то плохо. О чень плохо.

Т о >чего мы к о т и м избежать!

514

глава 10


применяем ja v a s c rip t на деле

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

□ □ □ □

□ □ □ □

Кэширование данных для исполь­ зования в ваших страницах.

Проверка орфографии при вводе пользователем текста на странице.

Обработка большого количества данных в массивах или объемных JSON-ответов, поступающих от веб­ служб.

Опрос веб-служб и предупрежде­ ние основной страницы, когда чтото случается.

□ □

Обработка изображений в ca n v a s.

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

Управление странице.

Управление подключениями к ба­ зам данных наряду с добавлением и удалением записей на основной странице. Автоматизированный агент для ста­ вок на ипподроме. Анализ видео.

Подсветка синтаксиса иного текста.

рекламой

кода

на

или

вашей

□ □

□ Свои идеи н а п и ш и т е здесь!

( - г - \ м п о ш о эн v f r ig o o g ‘ a w i i a g w i w o w

' v w o d p o v i v m v h rtyig vwio a w i v v v p

v

‘m h n w d w o п о г о н ю i q m g o w ts v g w o ^ R o o vmhfiv <oh>kowso9 'рэиэх&умниэ n ппф»Жоф - do fadzgodu -.awmdouoovi oh>kow э ж xmh ем nodvu о ow hqo ‘л щ л о г л gvndvHZh^psg HYiH?H?wndu iciwiHvndvg vnmodox nogoo wicHXvgvwiogvdu iqwivqwio ■smiag эмнн ?vJYih?d?Ll

дальш е ►

515


будьт е вним ат ельны с браузерной поддержкой

Браузер Google Chrome предусматривает дополнительные ограничения (для обе|^ у Д Ы 1 1 6 I спечения безопасности), которые не поо с гц о Р оЖ Н ы ! зволят вам запускать веб-сценарии worker напрямую из файла. Если вы попытаетесь это сделать, станица не будет работать и вы не получите никаких уведомлений о причинах такого поведения (в том числе никаких сообщений об ошибках, где будет сказано, в чем дело!). л

Вы такж е м ож ет е в о с ­ п о ль з о ва т ь ся п е р е к л ю ч а ­ т е л е м врем ени вы полнения C h ro m e - - a llo w -file -a c c e ssfr o m - file s , однако м ы р е к о ­ м е н д у е м в а м и с п о ль з о ва т ь данный п а р а м е т р т о л ь к о при т е с т и р о в а н и и кода.

Поэтому для приведенных здесь примеров рекомендуем вам ис­ пользовать другой браузер или свой собственный сервер и за­ пускать их с http://localhost. Либо можете загрузить их на онлайнсервер, если у вас имеется к нему доступ.

а ]) у д ь щ е o c r n o p o ^ H b i!

Почти все современные браузеры поддерживают API-интерфейс Web Workers, но есть одно исключение — Internet Explorer 9. Хоро­ шая новость заключается в том, что в версии 10 (и выше) этого вебобозревателя вы можете рассчитывать на Web Workers, однако для Internet Explorer 9 и всех предшествующих версий вам придется ис­ кать альтернативное решение.

Вы можете легко проверить и узнать, поддерживает ли тот или иной браузер API-интерфейс Web Workers: Если API - и н т е р ф е й с W eb W o rkers под держ ивается, т о с войст во W o rk e r б у д е м определено в глобальном о б ь е к т е w in do w , ^

if

(window["W orker"])

^ если свойст во W o r k e r не определено, т о т а к а я у поддержка в браузере 5 у дет от сут ст воват ь.

{

v a r s t a t u s = d o c u m e n t . g e t E l e m e n t B y l d ( " s t a t u s ") ; s t a t u s . innerHTML = "Bummer, no Web Workers";

8 подобной с и т у а ц и и ва м п р и д е т с я п о с т у п и т ь т а к , как б удет нужно для вашего прилож ения. Здесь м ы п р о с т о у в е д о м л я е м п о л ь з о в а т е л я п у т е м р а зм е щ е н и я сообщения в э л е м е н т е с id="status".

516

глава 10


применяем ja v a s c rip t на деле

Ваш первый веб-сценарий worker... Д а в а й те созд ад им w ork er. Д л я э т о го п а м п о т р е б у е т с я с т р а п и ц а , в к о т о р о й все будет р а зм е щ а ть ся. М ы п а п и ш е м сам ую п р о с т у ю Н Т М Ь б -р а з м е тку , к о т о р о й с м о ж е м о б о й т и с ь в д а п п о м случае; в п е с и т е в p in g p o n g .h t m l т о , ч т о п о к а з а п о далее:

< ! d o c t y p e h tm l> <htm l la n g= " en " > <head> < title > P in g P o n g < /title > <meta c h a r s e t = " u t f - 8 "> < s c r i p t s r c = " m a n a g e r .j s " > < / s c r i p t >

\ ___^ Д а н н ы й J a v a S c r i p t -код создаст все веб -сцен а ри и w o r k e r и б удет осущ ест влят ь управление и м и .

< /h e a d > <body> <p i d = " o u t p u t " > < /p > < /b o d y >

Г е н ери ру е м ы й в е б -с ц е н а р и ем w o r k e r вывод мы будем р а з м е щ а т ь здесь.

< /h t m l>

Как создать Веб-сценарий worker П е р е д п а ч а л о м р е а л и з а ц и и m a n a g e r . j s в згл я п е м п а т о , к а к ф а к т и ч е с к и со зд ается в е б -с ц е п а р и й worker: Д л я создания нового w o r k e r м ы г е н е р и р у е м

новый о б ъ е к т Worker.

) v a r w ork er = new W o r k e r ( " w o r k e r . j s " );

П рисваиваем новый W o rk e r J a v a S c r i p t п е р е м е н н о й worker.

В еб-сц ена ри й w orker

...Ja v a S c rip t- ф а й л worker.js будет содержать код для w orker,

В о т к а к созд ается о д и п w o rk er. О д п а к о вам п е о б я за т е л ь п о п а э т о м о с та н а в л и в а т ь с я — м о ж е т е созд ать с т о л ь к о w o rk er , с к о л ь к о н у ж п о :

v a r w ork er2 = new Worker ( " w o r k e r . j s ") ; v a r w o r k e r 3 = new W o rk er( " w o r k e r . j s " );

д д ^ ^ е м легко с о з ­

дат ь два д о п олнит ель ны х w o r k e r , ко т о р ы е б удут и с п о ль з о ва т ь т о т же код , ч т о и наш первы й worker.

v a r a n o t h e r _ w o r k e r = new W o r k e r ( " a n o t h e r _ w o r k e r . j s " );

Либо мы м ож ем создат ь д о п олнит е ль ны е w o r k e r , основанные на др у го м J a v a S c r i p t -ф айле.

Ч у т ь позже м ы п о ­ с м о т р и м j как и с п о л ь ­ зо в а т ь в м е с т е сразу несколько worker...

дальше ►

517


написание кода для управления w orker

Написание manager.js Т е п е р ь , к о гд а в ы зп а е те , к а к созд ать w o rk er (и п а с к о л ь к о л е гк о э то д е л а е тся ), п о р а б о т а е м пад к о д о м m a n a g e r . j s. О п будет п р о с т ы м , и се й ч а с м ы с ф о р м и р у е м т о л ь к о о д и п w ork er. С о зд а й те ф айл с и м е п е м m a n a g e r . j s и доб авьте в п е го с л е д у ю щ и й ко д :

Мы дождемся полной w in d o w .o n lo a d = f u n c t i o n ()

загрузки страницы.

{

v a r w o rk er = new Worker ( " w o r k e r . j s

;

J

4—

}

л

^ ^

А з а т е м создадим новый worker.

Э то о т л и ч п ы й ста р т, о д п а ко т е п е р ь п а м п е о б х о д и м о сделать т а к, ч т о б ы w o rk er за п я л ся р а б о т о й . К а к у ж е о тм е ч а л о с ь р а п е е , ч т о б ы за с т а в и ть w o rk er ч т о -т о сделать, н у ж п о о т п р а в и т ь ему со о б щ е п и е . Д л я э т о го м ы во сп о л ьзу е м с я м е то д о м p o s t M e s s a g e о б ъ е кта w ork er. В о т к а к о п п р и м е п я е т с я :

w in d o w .o n lo a d = f u n c t i o n ()

{

v a r w o rk er = new W o rk er( " w o r k e r . j s ")

w o r k e r . p o s t M e s s a g e ( " p in g " ) ;

Используем м ет од postMessage объекта worker для отправки ему сообщения. Н аш е" сообщение п р едст ав­ ляет собой про ст ую ст року "ping".

^

т Метод postMessage определен для вас в API -инт ерф ейсе Web Workers.

/>

Хот ит е от прав­ л ят ь более сложные сообщения? Бот как это делается...

под увеличительным сшекл°м

В ы с м о ж е те о т п р а в л я т ь п е ч т о б о льш ее, ч е м п р о с т о с т р о к и , и с п о л ь зу я p o s t M e s s a g e . Д а в а й те в згл я п е м , ч т о м о ж п о о т п р а в л я т ь в с о о б щ е п и и :

Вы можете о т пра влят ь с т р о ку... w o r k e r . p o s t M e s s a g e ( " p in g " ) ; w o rk er . p o s t M e s s a g e ( [ 1 ,

2, 3 , 5, 1 1 ] ) ;

w o r k e r . p o s t M e s s a g e ( { " m e s s a g e " : " p in g " ,

...массив... " cou n t" :

5});

..или даже JSON -объект. О т п р а в л я т ь ф у п к ц и и нельзя:

w o r k e r . p o s t M e s s a g e (updateTheDOM) ;

О т п р а в л я т ь т у или иную ф ункцию нельзя — она МоЖет содержать ссылку на объ ект н ую

модель докум ент а, позволяя w orker вносить изменения в РОМ!

518

глава 10


применяем ja v a s c rip t на деле

Получение сообщений о т веб-сценария worker М ы п о к а п е совсе м д о в о л ь п ы к о д о м m anager, j s — п а м ещ е н у ж п а в о з м о ж п о с т ь п о л у ч а т ь с о о б щ е п п я о т w ork er , если м ы с о б и р а е м с я всецело и с п о л ь з о в а т ь е го т я ж е л ы й труд. Ч т о б ы п о л у ч и т ь с о о б щ е п и е о т w ork er, п о т р е б у е т с я о п р е д е л и ть о б р а б о т ч и к для с в о й с т в а w o rk er с и м е п е м on m e ssa ge, ч т о б ы к а ж д ы й ра з п р и п о с т у п л е п и и с о о б щ е п и я о т w o rk er п р о и с х о д и л в ы зо в п а ш е го о б р а б о т ч и к а (и п е р е д а ч а ему соо б щ е п и я ). В о т ч т о м ы сделаем:

w in d o w .o n lo a d = f u n c t i o n ()

О предел яем ф у н к ц и ю , кот орая будет вы ­ зыват ься всякий раз при получении с о ­ общения от данного w o rk e r. Сообщение от w o rk e r будет обернут о в объект e v e n t

{

v a r w ork er = new W o r k e r ( " w o r k e r . j s f

w o r k e r .p o stM e s sa g e (" p in g " );

w o r k e r . o n m essage = f u n c t i o n

(event)

{

v a r m e s s a g e = "Worker s a y s " + e v e n t . d a t a ; d o c u m e n t . g e t E l e m e n t B y l d ( " o u t p u t " ) . innerHTML = m e s s a g e ;

При получении сообщения от w o rk e r м ы п о м ест и м его в э л е ­ м ен т <р> в H T M L -ст ранице.

/>

О б ъ е кт ev en t, п е р е ­ даваемый наш ем у обработ чику , облада­ ет свойст вом d a ta , содерж ащ им данные сообщения (нуж ны е нам ), кот оры е о т ­ правил w o rk er.

oum e^age под ув е л и ч и те л ь н ы м с т е кл а м

К р а т к о р а с с м о т р и м с о о б щ е п и е , к о т о р о е п а ш о б р а б о т ч и к on m e ssa ge п о л у ч а е т о т w ork er. К а к м ы у ж е г о в о р и л и , д а п п о е с о о б щ е п и е будет о б е р н у т о в о б ъ е к т e v e n t , к о т о р ы й обладает двум я и п т е р е с у ю щ и м и пас с в о й с т в а м и : d a t a и t a r g e t :

Эт о о б ъ е кт , кот оры й w o rk e r посы лает коду в вашей ст ранице при от правке сообщения.

w o r k e r . o n m e ssage = f u n c t i o n

(event

var m essage = e v e n t .d a t a ;

«

--------------------

Свойст во d ata содерж ит сообщ ение , кот орое от правил w o rk e r ( н а п р и м ер , с т р о к у вроде "pong").

v a r w o rk er = e v e n t . t a r g e t ;

ta rg e t - эт о ссылка на w o rk e r, кот оры й от правил сообщение. Д анное свойст во при дет ся к ст а т и , когда вам п о т р еб у ет ся у з ­ нат ь , о т какого w o rk e r исходит сообщение М ы дудем использоват ь его далее в главе

дальш е ►

519


ваш первы й w orker

А теперь напишем worker П р и с т у п а я к п а п и с а п и ю w o rk e r, п е р в ы м д ел ом п а м п е о б х о д и м о п о з а б о т и т ь с я о т о м , ч т о б ы п а ш

w o rk er с м о г п р и п и м а т ь с о о б щ е п и я , к о т о р ы е п о с т у п а ю т о т m a n a g e r . j s , — т а к w o rk e r будет п о л у ч а т ь за д а п и я п о р а б о те . Д л я э т о го п а м т а к ж е п о т р е б у е т с я за д е й с тв о в а ть о б р а б о т ч и к on m e ssa ge, к о т о р ы й будет в сам ом w ork er. К а ж д ы й w o rk er го т о в к п р и е м у с о о б щ е п и й , вам н у ж п о л и ш ь д ать ему о б р а б о т­ ч и к для и х о б р а б о т к и . С о зд а й те ф айл w o r k e r . j s n д обавьте в п е го п р и в е д е п п ы й далее ко д :

on m e ssa ge = p in g P o n g ;

Присваиваем свойст во o n m e ssa g e ^ w orker ф ункци и pingPong.

Мы собираемся н а п и с а т ь ф у н к ц и ю pingP ong для обработки всех п о с т у ­ п а ю щ и х сообщений.

Написание обработчика сообщений для worker Н а п и ш е м о б р а б о т ч и к с о о б щ е п и й p in g P o n g для w ork er. П о п а ч а л у все будет п р о с т о . В о т ч т о будет п р о и с х о д и т ь (в ы у ж е м о гл и об э т о м д о га д а ть ся, в згл я н у в п а и м я p in g P o n g ): w o rk er будет п р о в е р я т ь л ю б о е п о л уча е м о е и м с о о б щ е п и е , ч т о б ы у б е д и ть с я в т о м , ч т о о п о с о д е р ж и т с р о к у "p in g", и если э та с р о к а п р и с у тс т в у е т, т о м ы о т п р а в и м пазад с о о б щ е п и е со с т р о к о й "pong". Т а к и м о б р а зо м , р а б о ­ т а w o rk er в д е й с т в и т е л ь н о с т и будет за кл ю ч а т ь с я л и ш ь в п р и е м е "ping" и о т п р а в к е о тв е т а в вид е "pong" — м ы п е со б и р а е м с я п р о и з в о д и т ь ка ки е -л и б о и п т е п с и в п ы е в ы ч и с л е п и я , а п р о с т о у б е д и м ся в т о м , ч т о m a n a g e r . j s и w o rk er о б щ а ю т с я д р у г с д р у го м . Е сл и ж е с о о б щ е п и е п е будет с о д е р ж а т ь с т р о к у "pin g", м ы п р о с т о п р о и г п о р и р у е м е го . Т а к и м о б р а зо м , ф у п к ц и я p in g P o n g будет п р и п и м а т ь с о о б щ е п и е и о т в е ч а т ь п а п е го "pong". Д о б а в ь те п р и в е д е п п ы й далее к о д B w o r k e r . j s :

Когда w o r k e r п о л у ч и т сообщение о т основного кода, п р о и зо й д е т вызов ф ун кц и и p in g P o n g , к о т о р о й б удет передано данное сообщение. o n m essa ge = p in g P o n g ; f u n c t io n p in g P o n g (e v en t) if

EL. {

( e v e n t . d a t a == "ping")

{

Если сообщение будет содержать с т р о к у "p in g ", м ы о т п р а в и м назад с о ­ общение со с т р о ко й "pong". О т в е т н о е

p o s t M e s s a g e ( "pong") ;

О б р а т и т е вн им ан и е, ч т о w o r k e r тоже и с п о л ь з у е т postM essage для о т п р а в к и сообщений.

520

глава 10


применяем ja v a s c rip t на деле

Проведение тест-драйба У б е д и те сь в т о м , ч т о в ы п а б р а л и и с о х р а п и л и весь н е о б х о д и м ы й к о д в p i n g p o n g . h t m l , m a n a g e r . j s и w o r k e r . j s. Т е п е р ь д е р ж и т е э т и ф а й л ы о т к р ы т ы м и , ч т о б ы м о ж п о б ы л о за гл я д ы в а ть в п и х , и да­ в а й те задумаемся пад те м , к а к все р а б о та е т. С па ча л а m a n a g e r . j s ООП

геперирует повый w ork er, присваивает ему обработчик сообщ еПИЙ, а Затем ОТПраВЛЯеТ ЭТОМу w o rk er Сообщепие СО СТрОКОЙ "ping". В св о ю о че р е д ь, w o rk er уб е ж д а е тся в т о м , ч т о фупкция p in g P o n g задапа в ка ч е с т в е е го о б р а б о т ч и к а с о о б щ е п и й , после ч е го п а ч и п а е т ж д а ть . В к а к о й -т о м о м е п т w o rk er п о л у ч а е т со о б ­

S j p !^ ^ h tt ^ oca(hpSt/^Be~ ^ Worker says pong

щ е п и е о т m anager, j s и п р о в е р я е т е го п а п р е д м е т с о д е р ж а п и я с т р о к и "ping", к о т о р а я и будет в п е м п р и с у т с т в о в а т ь . З а те м w o rk e r в ы п о л п я е т м ассу со все м п е м п о г о т я ж е л о й р а б о т ы и о т ­ п р а в л я е т в о т в е т с о о б щ е п и е со с т р о к о й "pong". В э то т м о м е п т о с п о в п о й б раузерпы й код получает сообщ епие о т

w ork er, к о т о р о е п е р е д а е т о б р а б о т ч и к у с о о б щ е п и й . О б р а б о т ч и к за те м п р о с т о д о б а в л я е т "Worker s a y s " п е р е д э т и м с о о б щ е п и е м и в ы в о д и т е го п а э к р а п . И т а к , п р о в о д и м ы е п а м и в ы ч и с л е п и я г о в о р я т о т о м , ч т о п а с тр а ­ п и ц е д о л ж п а п о я в и т ь с я ф раза "Worker s a y s pong"... Л а д п о , л а д по , м ы п о п и м а е м , ч т о в ы б о льш е п е м о ж е т е в ы п о с и т ь п а п р я ж е п п о г о о ж и д а п и я . З а гр у з и т е ж е , п а к о п е ц , э ту с т р а н и ц у !

П остойте-ка, просто думая на­ перед... Если нам когда-либо придется создать более одного w orker, лю бящ его играть в такой « п и н г-п о н г» , то мне действительно придется попотеть.

дальш е ►

521


СТАНЬбраумром ------------------ДрхШдо Бремя п ри твориться £раузер°М, «ДениБа1°ЩиМ

JavaScript-Код. |J оп роси те се^я в р°Ли браузера для КаЖДоГо &л°Ка К«Да, приведенного ниже, и н а пиШише Генерируемый UM ВыВод на стр о ­ ках справа. ]У[ожете с ч и т а т ь , Чцю дан­ ный код использует т ° т же ^ а й л woikerjg, Кот°рый Мы т°ЛьКо Чщо написали. w in d o w .o n lo a d = f u n c t i o n ()

{

v a r w o rk er = new Worker ( " w o r k e r . j s " ); w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) { a l e r t ( "Worker s a y s

" + ev e n t.d a ta );

(v a r i = 0; i < 5;

i++ )

}

for

{

w o rk er .p o stM essa g e(" p in g " ) ; }

w in d o w .o n lo a d = f u n c t i o n ()

{

v a r w o rk er = new W o r k e r ( " w o r k e r . j s " ); w o r k e r . ommessage = f u n c t i o n ( e v e n t ) { a l e r t ( "Worker s a y s

" + ev e n t.d a ta );

}

f o r ( v a r i = 5; i > 0; i - - )

{

w o r k e r .p o stM e ssa g e (" p o n g " ); }

522

глава 10

^ — Свои о т в е т ы вы

см ож ет е п р о в е р и т ь в р еш ении к э т о м у заданию в конце главы .


применяем ja v a s c rip t на деле

w in d o w .o n lo a d = f u n c t i o n ()

{

v a r w o rk er = new W o r k e r ( " w o r k e r . j s " ); w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) { a l e r t ( "Worker s a y s " + e v e n t . d a t a ) ; w o r k e r . p o s t M e s s a g e ( " p in g " ) ; }

w ork er. p o stM essa g e(" p in g " );

a w in d o w .o n lo a d = f u n c t i o n ()

Б у д е т е осторожны с э т и м и блокам и кода. Возможно , в а м п р и д е т с я п р и н у ­ д и т ель н о з а в е р ш и т ь р а б о т у б р а узе р а , чтобы п р е к р а т и т ь их вы полнение ...

{

v a r w o rk er = new W o r k e r ( " w o r k e r . j s " ); w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) { a l e r t ( "Worker s a y s " + e v e n t . d a t a ) ; }

se tln te r v a l(p in g e r ,

fu n c tio n p in g e r()

1000);

{

w o r k e r . p o s t M e s s a g e ( " p in g " ) ;

дальш е ►

523


упражнение на использование компакт ного w orker

-Возьми в руку карандаш Несмотря на то что обычно веб-сценарии w o rk er получают рабочие задания посред­ ством сообщений, такой подход вовсе не обязателен. Взгляните на данный отличный и компактный способ сделать необходимую работу с помощью веб-сценариев w ork er и HTML. Когда вы разберетесь в том, что делает данный код, опишите это внизу. Свой ответ вы сможете проверить в решении к этому упражнению в конце главы. < ! d o c t y p e htm l> <htm l la n g = " en " >

q u o te .h tm l

^

<head> < title > Q u o te < /title > <meta c h a r s e t = " u t f - 8 "> < /h e a d > <body> <p i d = "q u ot e ">< / p> < scr ip t> v a r w o rk er = new W o rk er( " q u o t e . j s " ); w o r k e r . on m e ssage = f u n c t i o n ( e v e n t ) { d o c u m e n t . g e t E l e m e n t B y l d ( " q u o t e " ) . innerHTML = e v e n t . d a t a ; }

< /sc rip t> < /b o d y > < /h t m l>

qwote.js

iv a r q u o te s = ["I hope l i f e i s n ' t a j o k e , b e c a u se I d o n ' t g e t i t . " , "There i s a l i g h t a t t h e end o f e v e r y t u n n e l . . . j u s t p ray i t ' s n o t a t r a i n ! " , "Do you b e l i e v e i n l o v e a t f i r s t s i g h t or s h o u ld I walk by a g a in ? " ] ; v a r in d e x = M a th .flo o r (M a th .r a n d o m () * q u o t e s . l e n g t h ) ; p o s t M e s s a g e ( q u o t e s [ i n d e x ] );

П опробуйт е ввест и Свое описание п р и в е д и т е здесь:

524

глава 10

вы п о л н и т ь данный код!


применяем ja v a s c rip t на деле

Г ф З Ж Н бН И б

Давайте добавим несколько worker в нашу игру p ingP on g. Ваша задача заключается в том, чтобы устранить имеющиеся пробелы и завершить приведенный внизу код, чтобы в результате происходила отправка трех сообщений со строкой "ping" веб-сценариям worker, а в ответ от них поступали три сообщения со строкой "pong".

w in d o w .o n lo a d = f u n c t i o n ()

{

М и создаем т р и w o r k e r и со

v a r numWorkers = 3;

хр а н я е м wx

в м ассиве workers.

var w orkers = []; for

У с т р а н и т е пробелы, за п олнив их с о о т ­ в е т с т в у ю щ и м кодом .

(var i = 0; i <

; i++ )

v a r w o rk er = new

( " w o r k e r . j s ")

w orker.

= fu n ctio n (ev en t)

{

{

a l e r t ( e v e n t . ta r g e t + " says " + even t. };

w o rk ers. p ush (w orker);

Здесь м ы добавляем новый w o r k e r в м а с с и в w o r ke r s

}

for

(var i = 0; i <

i+ + )

{

("p ing" )

w o rk ers[i]. }

Ч а ст° ^адаВ аеМ ы е B o llp o C b l

! / • Можно ли просто передать функцию вместо JavaScriptфайла при создании worker? Наверняка так было бы проще и это лучше соответствовало бы стандартному поведению JavaScript. 0 : Нет, нельзя. И вот почему: как вы знаете, одно из требо­ ваний, касающихся веб-сценариев w ork er, заключается в том, что они не должны иметь доступа к объектной модели документа (или к любому состоянию главного браузерного потока). Если бы можно было передать конструктору Worker функцию и при этом оказалось бы, что ваша функция содержит ссылку на DOM или другие части основного JavaScript-кодэ, это нарушило бы данное требование. Таким образом, разработчики API-интерфейса Web Workers предпочти сделать так, чтобы вы передавали URL-адрес JavaScript-файла во избежание данной проблемы.

Если отправить веб-сценарию worker объект в сообщении, станет ли он объектом, совместно используемым основной страницей и этим worker? 0 : Нет, когда вы отправляете объект веб-сценарию w o rk er , он получает его копию. Любые изменения, который вносит worker, не затронут объект в вашей основной странице, w o rk er выпол­ няется в среде, отличной от вашей основной страницы, поэтому у вас не будет доступа к находящимся там объектам. Аналогичным образом дело обстоит и с объектами, которые w orker отправляет вам: вы будете получать их копии.

либо возможность совершать запросы с использованием XMLHttpRequest?

О

Да, у веб-сценариев w o rk er имеется доступ к l o c a l S t o r a g e и возможность совершать запросы с ис­ пользованием XMLHttpReguest.

дальш е ►

525


вклю чение ja va scrip t-кода в w orker

пражнение решение

Давайте добавим несколько w o rk er в нашу игру p ingP on g. Ваша задача заключает­ ся в том, чтобы устранить имеющиеся пробелы и завершить приведенный внизу код, чтобы в результате происходила отправка трех сообщений со строкой "ping" веб­ сценариям w orker, а В ответ ОТ НИХ поступали три сообщения СО строкой "pong". Вот наше решение этого упражнения. М ы и с п о л ь з у е м n u m W o r k e r s для т р е х к р а т н о г о соверш ения и т е р а ц и и и создания т р е х w o r k e r (вы м ож ет е свободно и з м е ­ н и т ь значение данной п е р е м е н н о й , чтобы их было больше!).

w in d o w .o n lo a d = f u n c t i o n ()

М ы задали о б р а б о т ­ чик сообщений в коде нашей основной ст раницы , исполь­ зуя свойст во w o r k e r с и м е н е м onmessage.

{

v a r numWorkers = 3; var workers = []; fo r

(var i = 0; i < numWorkers; i+ + )

{

v a r w o rk er = new Worker ( " w o r k e r . j s w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) {

a l e r t ( e v e n t . ta r g e t + " says " + ev e n t.d a ta ); };

И с п о л ь з у е м свойст во d a ta для извлечения содержимого сообщения.

w o r k e r s .p u s h ( w o r k e r )

} for

(var i = 0; i < w o r k e r s . l e n g t h ;

i+ + )

{

w o r k e r s [ i ] . p o s t M e s s a g e ( " p i n g " ) /r \ }

Вы также м ож ет е и с п о л ь ­ зо ва т ь здесь n u m V J o r k e r s , если за х о т и т е .

t

О т п р а в л я е м веб -сц е н а р и ю w o r k e r сообщение со с т р о ­ кой « p i n g » с п о м о щ ь ю postMessage.

г

С ледует о т м е т и т ь , ч т о ^ ^ ^ ^ Т р а д о с т ь ю

независимо т

Д а н н о е диалоговое

окно alert п оя вит ся ( на экране трижды.

526

глава 10


применяем ja v a s c rip t на деле

Интересно, как вклю чить ^ дополнител ьны е J a v a S c rip t-ф айлы в м ой w orker? У меня имеется несколько связанных с финансами библиотек, которые я хотел бы ис­ пользовать, однако в результате и х копирования и вставки в w o rke r получится огром ны й файл, которы й не очень удобен в сопровождении.

Вам стоит взглянуть на im portScripts. A P I-и н т е р ф е й с W eb W o rk e rs в к л ю ч а е т гл о б а л ьн ую ф у н к ц и ю i m p o r t S c r i p t s , к о т о р у ю в ы м о ж е те и с п о л ь зо в а ть для и м ­ п о р т а о д н о го и л и более J a v a S c rip t-ф айлов в ваш w ork er. Д л я и с п о л ь з о в а н и я ф у н к ц и и i m p o r t S c r i p t s вам н у ж н о н р о с т о пе р е д а ть е й с п и с о к р а з д е л е н н ы х з а п я т ы м и ф а йл о в л и б о U R L адресов, к о т о р ы е в ы х о т и т е и м п о р т и р о в а т ь :

i m p o r t S c r i p t s ( "h t t p : / / b i g s c i e n c e . o r g / n u c l e a r . j s ", "h t t p : / / n a s a . g o v / r o c k e t . j s ", " m y l i b s / a t o m s m a s h e r . j s ") ;

П о м е с т и т е в im p o r tS c r ip t s нужное к о ­ ли ч е с т во (или нуль) разделенны х з а п я ­ т ы м и U R L -адресов J a v a S c r i p t -ф айлов. З а те м , ко гд а ф у н к ц и я i m p o r t S c r i p t s будет вы зв а н а , к а ж д ы й и з U R L -адресов J a v a S c rip t-ф айлов будет и з в л е ка ть с я и о ц е н и ­ в а ть с я н о н о рядку. С ледует о т м е т и т ь , ч т о i m p o r t S c r i p t s я в л я е тс я н о л н о ц е н н о й ф у н к ц и е й , в сил у ч е го (в о т л и ч и е о т о н е р а т о р о в im p o r t во м н о г и х я з ы к а х ) в ы с м о ж е те н р и н и м а т ь р е ш е н и я об и м н о р т е в о в р е м я в ы п о л н е н и я , к а к н о ка за н о далее:

if

(ta sk T y p e == " s o n g d e t e c t i o n " ) { im p o r tS c r ip ts(" a u d io .js" );

Поскольку i m p o r tS c r ip t s — ф у н кц и я , вы см ож ет е и м п о р т и р о в а т ь код по м е р с т о го , как эт о го б уд е т т р е боват ь определенная задача.

дальш е ►

527


м ножест во Мандельброта

Захват виртуальных земель И с с л е д о в а те л и м н о ж е с т в а М а н д е л ь б р о т а у ж е з а х в а т и л и о б л а с ти в и р т у а л ь н о й с е л ь с к о й м е с т н о с т и и дал и и м н а з в а н и я вр о д е к р а с и в ы х « Д о л и н а м о р с к и х к о н ь к о в » ( Seahorse Valley), « Р адуж ны е о стр о в а »

( Rainbow Islands) и л и у с тр а ш а ю щ е го « Ч е р н а я ды ра» ( Black Hole). А у ч и т ы в а я с е го д н я ш н и е ц е н ы н а р еаль­ н у ю н е д в и ж и м о с т ь , н о х о ж е , ч т о е д и н с т в е н н ы й н р о с т о р о ста л ся в в и р т у а л ь н о м п р о с т р а н с т в е . П о э т о м у м ы со б и р а е м с я со зд а ть н р и л о ж е н и е для м н о ж е с т в а М а н д е л ь б р о т а н о д н а з в а н и е м F ra c ta l E x p lo re r, ч т о ­ б ы п о у ч а с тв о в а т ь в э т о м д е й с тв е . В о о б щ е -то м ы д о л ж н ы н р и з н а т ь с я , ч т о у ж е со зд а л и н р и л о ж е н и е , од­ н а к о о н о м е д л е н н о р а б о та е т — н е р е м е щ е н и е н о всем у м н о ж е с т в у М а н д е л ь б р о т а м о ж е т за н и м а ть о ч е н ь д о л го е в р е м я , н о э т о м у над еем ся, ч т о вм е сте с м о ж е м у с к о р и т ь е го . К а к м ы н о д о зр е в а е м , р е ш е н и е м д а н ­ н о й н р о б л е м ы м о ж е т с та ть A P I-и н т е р ф е й с W eb W o rk e rs .

•*

+

^ http /i'lix jlhn'.l,1- Rrlh/HTMl S,1Fr.u1.il/fr.ic1.il.html

He х о т е л и St?i п р и о б р е с т и дом с видом на пляж у самого края « Л а зу р н о г о во доворот а»?

Осмотритесь П о с е т и т е с т р а н и ц у h t t p : / / w i c k e d ly s m a r t . c o m / h f lit m l5 / c h a p t e r l0 / s in g le t h r e a d / fr a c ta l.h tm l, ч т о б ы ув и д е ть в и з у а л и з а ц и ю м н о ж е с т в а М а н д е л ь б р о та . Щ е л к н и т е в л ю б о м м есте к н о п к о й м ы ш и — и в ы у в е л и ч и т е с о о т в е т с т в у ю щ у ю о б л а сть к а р т ы . П р о д о л ж а й т е щ е л ка ть , ч т о б ы иссл е д о в а ть р а з л и ч н ы е о б л а с ти , л и б о п е р е з а гр у з и ­ те с т р а н и ц у и н а ч н и т е все сначала. О с т е р е га й т е с ь о б л а с те й с ч е р н ы м и д ы р а м и , н о с к о л ь к у о н и будут п ы т а т ь с я за т я н у ть вас. Н а н а ш взгляд, х о т ь п е й з а ж и и в ы гл я ­ д я т н р е в о с х о д н о , п р о гр а м м а п р о с м о т р а м огл а б ы р а б о та ть н е м н о го б ы с тр е е ... К а к в ы счи тае те? К р о м е т о г о , б ы л о б ы з д о р о в о , если бы на ш е п р и л о ж е н и е обладало т а к о й п р о и з в о д и т е л ь н о с т ь ю , ч т о б ы м о ж н о б ы л о р а зв е р н у ть п р е д с та в л е н и е н а все о к н о браузера! Д а в а й те о б е с н е ч и м все э т о , д о б а в и в в е б -с ц е н а р и и w o r k e r в н р и л о ­ ж е н и е F ra c ta l E x p lo re r.

528

глава 10


применяем ja v a s c rip t на деле

Если вдруг вы математик, т о вам и з в е с т н о , ч т о м н о ж е с т в о М а н д е л ь б р о т а ге н е р и р у ­ ется н о ср е д ств о м ур а в н е н и я : % +1

=

% 2 +

с

и ч т о е го о т к р ы л и иссл е до ва л Б енуа М а н д е л ь б р о т. В ы т а к ж е зн а е те , ч т о э то н р о с т о м н о ж е с т в о к о м п л е к с н ы х ч и с е л (ч и с е л с в е щ е с т в е н н о й и м н и м о й ч а с т ь ю ), ге н е р и ­ р у е м ы х с н о м о щ ь ю д а н н о го у р а в н е н и я . Е сли ж е в ы н е м а т е м а т и к , т о н а и л у ч ш и й с п о с о б п р е д ­ с та в и ть себе м н о ж е с т в о М а н д е л ь б р о т а — э то с ч и т а т ь е го б е с к о н е ч н о с л о ж н ы м ф р а к т а л ь н ы м и з о б р а ж е н и е м , нод к о то р ы м ноним ается изображ ение, ко то р о е м о ж но у в е л и ч и в а т ь до л ю б о й с т е н е н и и н а х о д и т ь л ю б о п ы т н ы е с т р у к т у р ы . В з гл я н и т е н а н е к о т о р ы е к а р т и н ы , к о т о р ы е м о ж н о о т ы с к а т ь п у те м н е р е м е щ е н и я н о м н о ж е с т в у :

П о ч е м у ж е о н о нас т а к и н те р е с у е т? Д а н н о е м н о ж е с т в о обладает р я д о м л ю б о н ы т н ы х с в о й с т в . В о -н е р в ы х , о н о ге н е р и р у е т с я п о с р е д с т в о м о ч е н ь н р о с т о г о у р а в н е н и я (о н о н р и в о д и л о с ь в ы ш е ), к о т о р о е м о ж е т б ы т ь в ы р а ж е н о в с е го л и ш ь н е с к о л ь к и м и с т р о к а м и ко д а . В о -в т о р ы х , ге н е ­ р и р о в а н и е м но ж е ства М андельброта заним ает изряд ное к о л и ч е с т в о в ы ч и с л и т е л ь н ы х ц и к л о в , ч т о делает е го о т ­ л и ч н ы м н р и м е р о м для и с н о л ь з о в а н и я в с о ч е т а н и и с A P Iи н т е р ф е й с о м W eb W o rk e rs . И н а к о н е ц , э то ж е кл а с с н а я вещ ь, с к о т о р о й м о ж н о н о р а б о т а т ь , и у нас е сть зам еча­ те л ь н о е н р и л о ж е н и е , ч т о б ы з а к о н ч и т ь и м к н и гу .

П окойся С м и р о м ,

ееН9« М я н Э е л ,б р о т ,

скоНыавмийся, когда Z п и с а л , э т у кн и гу .

Нам повезло зн ако м ы м и с т а к челобекоМ , как w w -

дальш е ►

529


вы числение фракталов

С ледует о т м е т и т ь , ч т о наша цель з а к л ю ч а е т с я не в т о м , чтобы с д е ла т ь из вас с п е ц и а л и ­ с т а по ч исленн ом у а на ли зу ( к о ­ т о р ы й у м е е т п и с а т ь уравнен и я П р е ж д е ч е м и с н о л ь з о в а т ь в е б -с ц е н а р и и w o rk e r, в згл я н е м , к а к о б ы ч н о н р и х о д и т с я с т р у к т у р и р о в а т ь ко д для в ы ч и с л е н и я м н о ж е ­ с и с по ль зо вани ем ко м плек сны х ств а М а н д е л ь б р о та . М ы не х о т и м удел ять м н о г о в н и м а н и я п о д р о б ­ чисел), а в т о м , чтобы а д а п ­ т и р о в а т ь т р е б у ю щ е е большого но стя м в ы чи сл е ни я зн а че н и й ни ксе л о в м нож ества М андельброта, объем а вычислений прилож ение т а к к а к у ж е н о л н о с т ь ю н о з а б о т и л и с ь о с о о тв е т с тв у ю щ е м ко д е и к испо льзо вани ю веб -сцен а риев со б и р а е м с я п р о д е м о н с т р и р о в а т ь е го ч у т ь н о з ж е . А се й ч а с м ы н р о worker. Если вас и н т е р е с у ю т с то х о т и м , ч т о б ы в ы р а зо б р а л и с ь в о б щ е й к а р т и н е : численные а спект ы множ ест ва Д л я вычисления м нож ест ва М а н ­ М андельбро т а — « В и к и п е д и я » д ельброт а м ы со вер ш а ем цикл по м о ж ет н а ч а т ь исследование по каждой с т р о к е изображения. данного вопроса.

Как Вычисляется мноЖестВо Мандельброта

Г

fo r

(i

=

va r

<

0; ro w

=

n u m b e r O fR o w s ;

i+ + )

c o m p u te R o w ( i) ;

{

И для каждой с т р о к и вы числяем пикселы.

d ra w R o w (ro w );

А з а т е м р и с у е м каждую с т р о к у на экране.

Вы, в е р о я т н о , смож ет е у в и д е т ь п о с т р о ч н у ю о т р и с о вк у изображения, когда з а п у с т иАте т е с т о в ы й код в браузере. В т е к у щ и й м о м е н т д а н н ы й ко д н р и з в а н б ы ть н р о с т ы м п с е в д о к о ­ дом . К о г д а ж е дело д о й д е т до н а н и с а н и я ко д а н о -на сто я щ е м у, н а м н о т р е б у е т с я р а зо б р а ть с я с д о п о л н и т е л ь н ы м и д е та л я м и: н а н р и м е р , для в ы ч и с л е н и я с т р о к и н а м н о т р е б у е т с я зн а ть ее ш и р и н у , к о э ф ф и ­ ц и е н т у в е л и ч е н и я , ч и с л е н н о е р а з р е ш е н и е , до к о т о р о г о м ы х о т и м н р о и з в е с т и ее в ы ч и с л е н и е , а т а к ж е н р о ч и е м е л ки е де та ли. М ы м о ­ ж е м со б р а ть все э т и д е та л и в о д н о м о б ъ е кте ta s k :

ш ирина

К оэф фициент увелич ени я

fo r

(i

=

0;

i

<

n u m b e r O fR o w s ;

var

ta s k F o r R o w

var

ro w

=

=

i+ + )

{

c re a te T a s k F o rR o w (i ) ;

c o m p u te R o w (ta s k F o rR o w );

Объект ta s k F o rR o w

d ra w R o w (ro w );

t Передаем ta skF o rR ow ф у нкции c o m p u te R o w , к о т о р а я в о з в р а ­ т и т вы численную с т р оку.

содерж а данные, необхо­ димые Зля вы ч и сл ен и я с т р о к и .

Уровень т о ч ­ н о ст и для вычисления

Х и т р о с т ь будет з а кл ю ч а т ь с я в следую щ ем : н у ж н о в зя ть все э то и д о р а б о та ть т а к и м о б р а зо м , ч т о б ы р а с­ п р е д е л и т ь в ы ч и с л е н и я м е ж д у н е с к о л ь к и м и w o r k e r , а за те м д о б а в и т ь ко д , к о т о р ы й за й м е тс я о б р а б о т ­ к о й р а зд а ч и зад ач в е б -с ц е н а р и я м w o r k e r , а т а к ж е о б р а б о т к о й д е й с т в и й с р е зул ьта та м и , к о гд а все w o r k e r за в е р ш а т в ы н о л н е н и е с в о и х задач.

530

глава 10


применяем ja v a s c rip t на деле

Как задействовать сразу несколько веб-сценариев worker Вы уже знаете, как создавать новые веб-сценарии worker, однако как их использовать для чегото более сложного, например вычисления строк множества Мандельброта? Или применения к изображению эффекта, как в Photoshop? Или генерирования сцены из видеофильма методом трассировки лучей? Во всех этих случаях мы можем разбить работу на небольшие задачи, над которыми веб-сценарии worker смогут трудиться независимо друг от друга. Мы будем придер­ живаться множества Мандельброта (однако шаблон, который мы собираемся использовать, может быть применен к любому из этих примеров). Для начала браузер создает группу веб-сценариев worker в качестве помощников (но не очень много, ибо веб-сценарии worker могут дорого обойтись, если создать их слишком много, — по­ говорим об этом позже). В нашем примере мы используем пять worker: Ьраузерный JavaS cript-код создает группу w orker для пол нения некоторой работы.

Здесь изображение ра зб и вает ся на н е <г- больш ие област и. М ы будем р а зд а ва т ь ^ э т и област и в е б ^ сценар иям w o r k e r ^ для вычисления. ^

Браузер Вот р е зу л ь т а т , который мы х о т и м получит ь п у т е м вы ­ числений. Ъраузерному коду пот ребует ся разбить работу по вычислению данного изобра­ жения на несколько небольших задач, выполнением которых зай м ут ся веб-сценарии worker.

Наши w o r k e r г о ­ т овы п р и с т у п и т ь к вы числениям! дальш е ►

531


как производит ь вы числения с пом ощ ью w orker

Далее браузерный код начинает раздавать раз­ ные части изображения каждому из веб-сценариев worker для вычисления:

Б раузер р а зд а е т част и изображения для в ы ­ числения каждым из веб -сц ен а ри ев worker.

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

R O D

[

*I ►j {+

Fractal txplorer

http

,iIionhoM,'-"Beln/MlMLV/FMtUl/f'jcUi 1

Закончив р а б о т у , веб -сц ен а ри и w o r k e r о т с ы л а ю т об рат но част и изображе­ н и я , кот о ры е они вы ч исляли .

532

глава 10


применяем ja v a s c rip t на деле

По мере того как части изображения поступают обратно от веб-сценариев worker, они собираются в единое изображение в браузере. И если еще остаются части, вычисление которых необходимо произвести, эти новые задачи поручаются веб-сценариям worker, ко­ торые не заняты работой.

Все ч аст и изображения, ген е р и р у е м ы е в е б -сц е н а р и я м и w o r k e r , соби­ р а ю т с я в ит ого во е изображение.

Когда будет вычислена последняя часть изображения, его сборка завершится и веб­ сценарии worker будут бездельничать, пока пользователь не щелкнет кнопкой мыши для увеличения изображения, после чего все начнется сначала... [«1►1f+

й] Сек- 1РЭЧ'<

Сборка изображения заверш ена и в е б сценарии w o r k e r м о гу т отдыхать до т е х n o p , пока снова не п о я ви т с я работ а.

дальш е ►

533


как веб-сценарии w orker улучш аю т прилож ения

Что произойдет, если я разделю работу на части и рас­ пределю и х между веб-сценариями w orker? Я хочу сказать, что у меня в компью тере останется все тот же про­ цессор, поэтом у как вычисления см огут ускориться?

Их ускорение возможно двумя путями... С н а чал а н р е д с та в ьте себе н р и л о ж е н и е , в к о т о р о м в ы п о л н я ­ ется масса в ы ч и с л е н и й и к о т о р о е д о л ж н о б ы ть о т з ы в ч и в ы м н о о т н о ш е н и ю к п о л ь з о в а те л ю . Е сл и ваш е н р и л о ж е н и е ста­ н е т о т н и м а т ь у й м у J a v a S c rip t-в р е м е н и , т о п о л ь з о в а те л и с то л ­ кн у тс я с м ед л енной р а б о то й ин терф ейса, ко т о р ы й , но и х о щ у щ е н и я м , будет н о д т о р м а ж и в а т ь (о н я т ь -т а к и , из-за т о г о J a v a S c rip t ф у н к ц и о н и р у е т в о д н о н о т о ч н о м р е ж и м е ). Д о б а в л е ­ н и е ве б -сц е н а р и е в w o rk er в т а к о е н р и л о ж е н и е сразу ж е н о л о ж и т е л ь н о с к а ж е т с я н а о щ у щ е н и я х п о л ь з о в а те л е й н р и р а б о те с н и м . П о че м у? А н о то м у , ч т о J a v a S c rip t н о л у ч и т в о з м о ж н о с т ь р е а ги р о в а т ь н а в з а и м о д е й с т в и е п о л ь з о в а те л е й в п р о м е ж у т ­ к а х м е ж д у п о л у ч е н и е м р е зул ьта то в о т ве б -сц е н а р и е в w ork er, ч е го о н н е с м о ж е т делать, е сли все будет в ы ч и с л я т ь с я в глав­ н о м н о т о к е . Т а к и м о б р а зо м , и н т е р ф е й с п о л ь з о в а те л я с та н е т более о т з ы в ч и в ы м , — и п о л ь з о в а те л и будут ощущать , ч т о ваш е н р и л о ж е н и е р а б о та е т б ы с тр е е (д а ж е е сли в н у т р и о н о н е бу­ д ет ф у н к ц и о н и р о в а т ь х о т ь ч у т ь -ч у ть б ы с т р е е ). Н е в е р ите ? П о н р о б у й т е э то сделать и д а й те р е а л ь н ы м п о л ь з о в а те л я м но р а б о та ть с в а ш и м н р и л о ж е н и е м . А за те м с н р о с и т е , ч т о о н и дум аю т. В т о р о й н у т ь действительно более быстрый. П о ч т и все с о в р е м е н ­ н ы е н а с т о л ь н ы е к о м н ь ю т е р ы и м о б и л ь н ы е у с т р о й с т в а снаб ­ ж а ю т с я м н о г о я д е р н ы м и п р о ц е с с о р а м и (и л и д а ж е н е с к о л ь ­ к и м и п р о ц е с с о р а м и ). М н о го я д е р н о с т ь подр а зум е ва е т, ч т о н р о ц е с с о р с м о ж е т на р а л л е л ь н о в ы н о л н я т ь м н о ж е с т в о задач. П р и о д н о м н о т о к е у н р а в л е н и я J a v a S c rip t в б раузере н е задей­ ств уе т в а ш и д о п о л н и т е л ь н ы е я д р а и л и п р о ц е с с о р ы , о н и н р о с т а и в а ю т без дела. О д н а к о е сли в ы п р и м е н и т е A P I-и н т е р ф е й с W eb W o rk e rs , т о в е б -с ц е н а р и и w o rk er с м о гу т в о с п о л ь з о в а ть с я п реим ущ ествам и в ы п о л н е н и я на р а зн ы х ядрах, и в ы увид ите р е а л ь н о е у с к о р е н и е с в о е го н р и л о ж е н и я , н о с к о л ь к у н а н е го будет т р а т и т ь с я б о льш е п р о ц е с с о р н ы х р е с у р с о в . Е сли у вас м н о г о я д е р н ы й к о м н ь ю т е р , н у ж н о л и ш ь н о д о ж д а ть , и в с к о р е в ы у в и д и т е р а зн и ц у.

534

глава 10


применяем ja v a s c rip t на деле

А может л и у меня быть столько веб­ сценариев w o rke r, сколько я пожелаю ?

О

В теории — да, но не на практике. В е б -с ц е н а р и и w o rk er не п р е д н а з н а ч е н ы для и с п о л ь ­ з о в а н и я в б о л ьш о м к о л и ч е с т в е . Н е с м о т р я н а т о ч т о с о зд а н и е w o rk er в ы гл я д и т н р о с т ы м в ко д е , о н н о т р е бует д о п о л н и т е л ь н о й п а м я т и и н о т о к а в о п е р а ц и ­ о н н о й си сте м е , ч т о м о ж е т д о р о го о б о й т и с ь в нл а не в р е м е н и за п уска и р е сур со в . Т а к и м о б р а зо м , о б ы ч н о у вас будет в о з н и к а т ь ж е л а н и е созд ать о гр а н и ч е н н о е к о л и ч е с т в о ве б -сц е н а р и е в w o rk er , к о т о р ы е в ы ста н е ­ те п о в т о р н о и с п о л ь зо в а ть н о н р о ш е с т в и и в р е м е н и . В о зь м и те на ш п р и м е р с м н о ж е с т в о м М а н д е л ь б р о та : в т е о р и и в ы м о гл и б ы н а з н а ч и т ь w ork er , к о т о р ы й стал бы за н и м а ть с я в ы ч и с л е н и е м к а ж д о го о д и н о ч н о ­ го п и кс е л а , ч т о , в е р о я т н о , б ы л о б ы н а м н о го н р о щ е с т о ч к и з р е н и я р а з р а б о т к и ко д а . О д н а к о , у ч и т ы в а я то , ч т о в е б -с ц е н а р и и w o rk er я в л я ю т с я « тя ж е л о в е с н ы м и » с р е д с тв а м и , м ы н и к о гд а б ы не в ы б р а л и т а к о й н о д х о д п р и р а зр а б о тке н а ш е го н р и л о ж е н и я . В м е с то э т о го м ы и с п о л ь зу е м г о р с т к у ве б -сц е н а р и е в w o rk er и с т р у к ­ т у р и р у е м в ы ч и с л е н и я т а к и м о б р а зо м , ч т о б ы о н и за­ д е й с тв о в а л и и х п р е и м у щ е с тв а . Д а в а й те н е м н о го у гл у б и м ся в р а з р а б о т к у F ra c ta l E x p lo re r, а за те м в е р н е м с я и н о э к с н е р и м е н т и р у е м с к о л и ч е с т в о м ве б -сц е н а р и е в w ork er , ч т о б ы р а зо ­ б р а тьс я , к а к э т о т н о ка з а те л ь в л и я е т н а у р о в е н ь п р о ­ изводительности.

дальш е ►

535


разработ ка кода как упражнение для ума

Ш ТУРМ У вас, несомненно, уже имеется масса знаний о том, как создавать приложения с применени­ ем API-интерфейса Web Workers, как генерировать и использовать веб-сценарии w o r k e r . Вы также немного знаете о том, как решать проблемы с объемными вычислениями путем разбив­ ки их на небольшие задачи, которые могут быть выполнены веб-сценариями w o r k e r , и даже чуть-чуть в курсе того, как вычисляются множества Мандельброта. Попробуйте соединить все это воедино и задумайтесь над тем, как бы вы переписали приведенный ниже псевдо­ код, чтобы он задействовал веб-сценарии w o r k e r . Сначала можете предположить, что у вас будет так много веб-сценариев w o r k e r , как вам потребуется (например, по одному w o r k e r на каждую одиночную строку), а затем введите ограничение на количество w o r k e r (число веб­ сценариев w o r k e r меньше, чем количество строк):

for

(i = 0; i < numberOfRows; i++)

{

var taskForRow = createTaskForRow(i); var row = computeRow(taskForRow); drawRow(r }

сделать для того, чтобы добавить сюда веб-сценарии worker?

Свои заметки напишите здесь:

536

глава 10


применяем ja v a s c rip t на деле

Займемся созданием приложения Fractal Explorer

Создать HTML-страницу

Создать веб-сценарии worker

к уцршр^ленито

Вот что нам потребуется сделать:

| ^ | Запустить веб-сценарии worker □ j

Создать HTML-страницу.

I I

Ввести весь готовый к употреблению код (или загрузить его на свой компьютер).

Создать веб-сценарии w o rk er и раздать им задачи для выполнения.

Запустить веб-сценарии w o rk er , чтобы они выполняли свои задачи.

РеаЛИЗОВаТЬ КО Д w ork er.

Обработать результаты веб-сценариев w o r k e r , когда они закончат выполнять свои задачи.

Обработать события

c lic k

и

re s ize

Реализовать код worker | Обработать результаты Код, касающийся взаимо­ действия с пользователями

в интерфейсе пользователя.

Создание HTML-разметки для приложения Fractal Explorer С начал а н у ж н о с ф о р м и р о в а т ь H T M L -с т р а н и ц у для р а зм е щ е н и я н а ш е го н р и л о ж е н и я . Н а м н о т р е б у е т с я созд ать ф айл f r a c t a l . h tm l и д о б а в и т ь туда н р и в е д е н н у ю н и ж е разм етку.

< ! d o c t y p e h tm l>

^

Chtml la n g = " en " >

^ К а к обычноj

стандартный H T M L S -ф ай л.

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

<head> < title > F r a c ta l E x p lo r er < /title >

А. в о т т у т б удет J a v a S c r ip t код,

<meta c h a r s e t = " u t f - 8 ">

I

< l i n k r e l = " s t y l e s h e e t " h r e f = " f r a c t a l . c s s "> / < s c r ip t sr c= " m a n d ellib . j s " x / s c r i p t > < s c r i p t s r c = " m a n d e l. j s " > < / s c r i p t >

< /h e a d > <body>

U

ко т ор ы й мы собираемся н а п и с а т ь ... X"

'

/

^ л и вам интересно, где будет р а з м ещ ат ься код worker, то п о м н и т е , что мы не ст анем указывать п р я м ую ссылку на J a vaS crip t-ф айл w o rker, а будем ссылаться Иа данный ф а й л , когда создадим worker в коде.

C canvas i d = " f r a c t a l " w id th = " 8 0 0 " h e i g h t = " 6 0 0 " X / c a n v a s > < /b o d y > < /h tm l>

/\а н н ы й код б удет р а з м е щ а т ь с я в ф ай ле fractal.htm l.

ЧЧ

j

' досм от рит е-ка! Наш друг <canvas> вернулся!

<body> в к л ю ч а е т э л е м е н т <canvas>. Мы задали для него исходный р а з м е р SOO х (ooo п и к с е ло вj однако позже м ы за й м е------м с я ---------------и зм е н е н и е м его р а з м е р а с п о м о щ ь ю J ava Script. 8 конце концов , н а м необходимо т а к о е большое множ ест во М а н д е л ь б р о т а , какое м ы т о л ь к о смож ем п о л у ч и т ь ! дальше ►

537


гот овы й к упот реблению код для ф ракт альны х изображений

вы м ож ет е ска ч ат ь весь код по адресу W t t p : //w ic k e d ly s m a r t.c o m / h F h tm lS

Напоминание:

У"*ojpoBo X ^oTDj=»0g^0HUI<>

Должны признаться, что планировали отвести целую главу чудесам вычислений множества Мандельброта... Мы собирались детально вам их объяснить, в том числе рассказать историю Бенуа Мандельброта, поведать о том, как он открыл множество, о его удивительных свойствах, пиксельных оптимизациях, цветовых картах и т. д., но после звонка от нашего редактора... Ну вы сами понимаете, какой это был ЗВОНОК. Мы немного запаздывали с работой над данной книгой, поэтому приносим свои из­ винения, однако все же дадим вам готовый к употреблению код для осуществления низкоуровневых вычислений графики, касающейся множества Мандельброта. Однако есть и положительный момент: мы сможем сосредоточиться на использовании APIинтерфейса Web Workers, не тратя время на математику и графику. Сначала взглянем на код, используемый для управления задачами и рисования строк фрактальных изображений. Введите данный код и сохраните его в файле m a n d e i i i b . j s. var canvas;

О б р а т и т е в н и м а н и е , чт о здесь п р и ­ с у т с т в у ю т наши canvas и c o n te x t .

var ctx;

v a r i_max = 1 . 5 ; v a r i_ m in = - 1 . 5 ;

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

v a r r_min = - 2 . 5 ; v a r r max = 1 . 5 ;

v a r m a x _ i t e r = 102 4; v a r e s c a p e = 1025; var p a l e t t e = []; Д анн ая функция упаковывает все f u n c t i o n c r e a t e T a s k (row)

{

var ta sk = { row: row, w id th :

r o w D a t a .w id t h ,

g en era tio n : r_m in:

g en er a tio n ,

данные, необходимые веб-сценарию w o rk e r для вычисления с т р о ки пикселов, в объект. Позже вы цвидите, как мы будем переда ва т ь э т о т объект веб-сценарию w o r k e r для использования.

r_m in ,

r_m ax: r_m ax, i : i_max + (i_ m in - i_ m a x )

row / c a n v a s . h e i g h t ,

m a x _ ite r: m a x _ ite r , escape: };

return task ;

538

глава 10

escape

Д а н н ы й код б удет р а з м е щ а т ь с я в ф а й ле mandelhb.js.


применяем javascript на деле w

"J"*ojpoBo X I j l l o 0 H U I °

( Создать HTML-страницу

| |

(п р о д о л ж е н и е )

J^otuoBoкупртре^ленито

Создать веб-сценарии worker

Запустить веб-сценарии worker

Реализовать код worker

I | Обработать результаты □

function m a k ePalette() { function wrap(x)

{

x = ( (x + 256) if

Код, касающийся взаимо­ действия с пользователями

& Oxlff)

- 256;

(x < 0) x = -x;

cm>o чисел в массив цвет ов R.QB. Мы 6ц дем использоват ь данный массив v a l e t t l

return x;

for

(i = 0; i <

this .max_iter wrap(5*i), w r a p (11*i)]);

p alette.p u s h ([wrap(7*1

функция d r a w R o w при н и м ает р е зу л ь т а т ь i о т w o rk e r и р и с у е т с о о т в е т ­ ст вую щ ие пикселы в canvas. function drawRow(workerResults)

{

var values = workerResults.values;

Д ля эт о го она использует перем ен н ую rowData; row D a ta — эт о одност роч­ ный объект Im ageD ata, содержащий фактические пикселы для с о о т в е т с т в у ­ ющей строки canvas.

var pixelData = rowData.data; for

(var i = 0; i < rowData.width; i++)

{

var red = i * 4; var green = i * 4 + 1; var blue = i * 4 + 2; var alpha = i * 4 + 3; pixelData[alpha] if

= 255; // set alpha to opague

(values[i] < 0) pixelData[red]

{ = pixelData[green]

= pixelData[blue]

0;

} else { var color = this.palette[values[i]] pixelData[red]

= color[0];

pixelData[green] pixelData[blue]

= c o l o r [1]; = color[2];

Вот где мы используем p a le tte для преобразования р е з у л ь т а т а о т w o rk e r (который п редст авляет собой число) в и,вет.

)

} c t x . put ImageData ( t h is . rowData f 0, w o rk e rR e su lts . row) ; Д д НН(?/ц код уже должен } Данный код будет р азм ещ ат ь ся в файле mandellib.js.

К

а 0т 2 5 запис 1 пикселы о ь е к т m age а 6 c w t e x t ^ м е н т я canvas!

быть вам знаком; он п о добен коду, который мы применяли в главе 8 для элем ен т ов video и canvas. дальше ►

539


готовый к употреблению код для фрактальных изображений

У"*o jp o B o X (п р о д о л ж е н и е ) setU p G rap hies задает глобальные п е р е ­ менныеj используемы е кодом для рисования всей гра ф и к и , а также применяемые при вычислении множества Мандельброта. function setupGraphics() {

canvas = document.getElementByld("fractal ctx = canvas.getContext("2d");

canvas.width = window.innerWidth;

Вот где мы извлекаем canvas и c o n te x t, а также задаем исход1*Г~ ную ширину и вы сот у canvas.

canvas.height = window.innerHeight;

var width = ((i_max - i_min) var r_mid = (r_max + r_min) r_min = r_mid - width/2;

* canvas.width / canvas.height); / 2;

^___ Переменные, используемые для в ы ­ числения множества Мандельброта.

r_max = r_mid + width/2;

< ir \ rowData = c t x .createlmageData(canvas.width,

makePalette();

1);

Здесь мы инициализиру­ ем п ерем ен н ую ro w D a ta (и с п ол ь зуе м у ю для записи пикселов в canvas).

А здесь мы инициализируем п а л и т р у цв ет о вj к о т о р у ю используем для рисования множества как ф р а к т а л ь ­ ного изображения.

Данный код будет ра зм ещ а т ься в файле mandelhb.js.

540

глава 10


применяем javascript на деле

J o r tio B o к ynomj=>eg jieH u i° (п р о д о л ж е н и е )

Данный готовый к употреблению код будет использоваться worker для математических вычислений множества Мандельброта. Именно здесь происходит вся магия чисел. Напечатайте и сохраните данный код В ф а й л е workerlib.j s!

function computeRow(task)

c o m p u te R o w вычисляет одну с т р оку данных множества М андельброта. Этой функции передается объект , в который упакованы все значения, необходимые ей для вычисления данной строки.

{

var iter = 0; var c_i = task.i;

О б р а т и т е внимание, что в случае с каждой ст рокой отображения мы с оверш а ем два цикла — один для каждого пиксела в строке...

var max_iter = task.max_iter; var escape = task.escape * task.escape; task.values = []; for

(var i = 0; i < task.width; var c_r = task.r_min +

i++)

Это масса вычислений, Хорошо!

{

(task.r_max

task.г min)

i / task.width;

var z_r = 0, z_i = 0;

for

(iter = 0; z_r*z_r + z_i*z_i < escape && iter < max_iter;

iter++)

{

// z -> zA2 + с var tmp = z_r*z_r - z_i*z_i + c_r; z_i = 2 * z_r * z_i + c_i; z_r = t m p ;

} if

max_iter)

(iter iter

-

1;

} task.values.push(iter)

} return task;

Данный код будет р а зм ещ а т ь с я в файле workerlib.js.

{

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

Р е зу л ь т а т о м всех этих вычислений является значение, добавляемое в массив именованных значений, который помещ ает ся назад в объект ta sk , чтобы w o rk e r смог от о сл а т ь р е з у л ь т а т обратно основному коду. V Ч ут ь позже мы пристальнее взглянем на э т у часть.

дальше ►

541


как управлять веб-сценариями worker и задачами

Создание веб-сценариев worker и раздача им задач... Разобравш ись с готовым к употреблению кодом, переклю чим впимапие па паписапие кода, которы й будет геперировать и раздавать задачи вебсцепариям wo г ке г .

Мы создадим массив веб-сценариев worker, которые первона­ чально ничем не будут заняты. А также изображение, для кото­ рого ничего не будет ВЫЧИСЛЯТЬСЯ (nextRow = о).

n extR ow = о

Мы будем совершать итерацию по массиву и генерировать объект каждого Свободного worker.

task ДЛ Я

Worker

Продолжим совершать итерацию в поисках следующего незаня­ того worker, чтобы поручить ему задачу. Следующим по очереди nextRow = 1 у нас будет идти n e x t R o w = 1 . И так далее...

542

глава 10


применяем javascript на деле O ' Создать HTML-страницу

Написание кода

|

s/(

|

Теперь, когда мы зпаем, как будем создавать паши веб-сцепарии worker и управлять ими, папиш ем соответствую щ ий код. Для этого пам потребу­ ется пачальпая фупкция, поэтом у давайте создадим в mandel. js фупкцию init, — мы также предусмотрим там м погое другое для обесп еч еп и я фупкциопировапия пашего прилож епия (паприм ер, позаботим ся об ипициализации графики).

Сначала определим п ерем ен н ую , которая будет содержать нужное нам количество s веб-сценариев worker. Мы используем / число S, и вы можете свободно поэкспери 1 о п т и р о в а т ь с э т и м пока за т ел ем , когОа ваше приложение заработ ает .

var numberOfWorkers =

Пустой массив для размещения наших w o rk e r

var workers = [];

Зададим обработчик onload, который будет вызывать функцию init, когда страница полност ью загрузит ся.

window.onload = init;

|~отоо'3о к ynorjpebjienuK *

| Создать веб-сценарии worker

Запустить веб-сценарии worker

j |

Реализовать код worker

Q

Обработать результаты

Код, касающийся взаимо­ действия с пользователями

Почему 2? Так с л у ­ чилось, что у нас имеет ся к о м п ью т е р с 2 я драм и} п о э т о ­ м у т акое количество хорошо с о ч е т а е т ­ ся с возможностями нашего ко м пью т ера. Но даже если вы не будет е ра сп о л а га т ь т аким количеством ядер, число 2 с т а н е т подходящим п о к а ­ з а т е л е м , кот орый следует испробовать в п ер вую очередь.

Данная функция определена в го т о вом коде и обрабаты вает извлечение co n te x t э л е ­ setupGraphics() м е н т а canvas, изменение р а зм ер о в canvas в со от вет ст вии с р а зм ер а м и окна браузера и прочие графические детали. Теперь мы соверш аем ит ерацию по определенному количеству worker... for (var i = 0; i < numberOfWorkers; i++) { ...И создаем новый w o rk e r из "worker.js", <г var worker = new Worker ("worker.js который мы еще не написали.

function init()

{

w o r k e r .onmessage = function(event) { processWork(event.target,

wo r k e r .idle

event.data)

true;

workers.push(worker)

З а т е м задаем для обработчика сообщений каждого w o rk e r ф ун кцию , кот орая вы зы ­ вает ф ункцию processW ork, и передаем ей e v e n t.ta rg e t ( w o rk e r , кот орый только что закончил выполнение задачи) и eve n t.d a ta (р е зу л ь т а т ы от данного worker).

Помните, что нам будет нужно цзнать сценарии w o rk e r заням ,,, * у зн а т ь, какие ве б -

Ад» L o z o нам

startWorkers()

присваиваем еще не поручили сценариям w o rk e r никакой работы. Д обавляем только что создан­ ный w o rk e r в массив workers.

И наконец, в к а ко й -т о м о м е н т нам пот ре б у е т ся за п у с т и т ь эт и веб-сценарии worker. Мы п о м е с т и м со о т ве т с т в ую щ и й код в ф ункцию s ta r tW o r k e r s , к о т о р у ю нам еще нужно написать.

Данный код будет разм ещ ат ься в файле mandel.js. дальше ►

543


запуск ваших worker для вычисления фрактальных изображений Создать HTML-страницу

|у< |^| ^ощоВо кl j U o СНиК>

Запуск веб-сценариев worker

[71Создать веб-сценарии worker □

Итак, пам п еобходим о разобраться с еще песколькими делами: запустить веб-сцепарии worker, паписать фупкцию, которая см ож ет обработать р е­ зультаты, поступающ ие обратпо от веб-сцепариев worker, а также паписать код для worker. Н ачпем с паписапия кода для запуска веб-сцепариев worker:

var generation =

Код, касающийся взаимодеиствия с пользователями

функция sta r tW o r k e r s будет за п ус к а т ь веб-сценарии w orker, а также п е р езап уска т ь их, если пользоват ель увеличит изображение. Таким образом, при каждом з а ­ пуске веб-сценариев w o rk e r мы будем сбрасывать значение nextR ow до нуля и увеличиват ь значение generation.

function startWorkers() generation++; nextRow = 0;

(var i = 0; i < w o r k e r s .length; i++) var worker = workers [i],

if

Обработать результаты

Каждый раз, когда пользоват ель увеличивает изображение м н о жества М андельброта, мы запускаем вычисление нового и зоора~ укения. Переменная gen eratio n отслеж ивает, сколько раз мы эт о сделали. Ъолее подробно об э т о м поговорим позже.

var nextRow = 0;

for

Реализовать код worker

Сначала идет n ex tR ow , которая отслеж ива­ е т , на какой ст роке мы находимся, по м е р е т ого как мы продвигаемся по вычисляемому изображению.

Д обавляем еще две глобаль-

и“

Запустить веб-сценарии worker

(worker.idle)

обе эти п е р е м е н ­ К ак используют ся н о вам с т а н ет яснее ч ут ь позже... Теперь мы соверш аем цикл по всем веб ­ сценариям w o r k e r в массиве workers...

{

* var task = createTask(nextRow);

worker.idle = false; worker.postMessage(task),

nextRow++;

{

„и проверяем, не сидит ли без дела определенный worker.

Если выясняется, что w o rk e r ничем не занят, мы ген ер и р уем объект task, чтобы поручит ь е м у задачу. Данная задача будет з а к л ю ч а т ь ­ ся в вычислении строки множества М андель­ брота. функция createTask определена в mandellib.js и возвращ ает объект task со в с е ­ ми данными, кот оры е необходимы w o rk e r для вычисления с о о т ве т с т в ую щ е й строки.

Теперь мы подошли к т о м у , чтобы дат ь w o rk e r к о е - к а ­ кую р а б о т у , п о э т о м у задаем для свойства idle значение false (эт о п о др азум евает , что он будет занят делом). И наконец, мы у в е ­ личиваем значение nextR ow , чтобы с л е ­ дующий w o r k e r п р и ­ с т уп и л к вычислению следующей строки.

544

глава 10

А здесь мы даем указание w o r k e r начат ь р а б о ­ т у , для чего от пра вля ем сообщение, содержа­ щее объект task, w o rk e r ведет прослушивание на п р е д м е т поступления сообщений, п о э т о м у когда он получит данное сообщение, он начнет выполнение со о т ве т с т в ую щ е й задачи.

л

-

я х .а,™ У'аТ - , разм ещ ат ься в файле mandel.js.


применяем javascript на деле f y j f ' Создать HTML-страницу

Реализация кода worker

|y f gfomoSo к Создать веб-сценарии worker

Теперь, когда у пас есть код для запуска worker путем передачи каждому из пих объекта task, займемся паписапием кода worker. Затем пам остапется лишь верпуться и обработать результаты от оп ределепп ого worker, как толь­ ко оп закопчит вы числепие своей части фрактальпого изображ епия. Одпако преж де, чем мы пачпем писать код для worker, давайте взгляпем па то, как оп долж еп работать.

ф Веб-сценарию worker передается объект task

А

Запустить веб-сценарии worker |

| Реализовать код worker

|

| Обработать результаты

j |

Код, касающийся взаимо­ действия с пользователями

worker берет этот объект task и передает его функции, входящей в готовый код, дл Я вычисления соответствующей строки.

отправить ее обратно коду Результат отправляется обратно от основной страницы, worker также с помощью postMessage.

Итак, приступим к реализации. Введите и сохрапите в файле w o r k e r .js код, которы й приведеп далее.

определенную в данном библиотечном файле. / . .

/

l m p o r tScn p t s ("workerlib.j s") ; onmessage = function

,ч ,

(task)

{

У —

Всеj что делает w o rk e r, — эт о задает обработчик onmessage. Ему нет нужды делат ь чт о-либо еще, поскольку ем у лишь ’ j /• т реб у е т ся ждать сообщений от mandel.js для начала работы! г

var workerResult = computeRow(task.data) :.data); postMessage(workerResult);

f

|Г ^

Он извлекает содержимое в виде данных из task и передает его функции с о т р и te R o w , тяжелую р а б о т у по выкоторая выполняет — числению множества Мандельброта

Р е зу л ь т а т вычислений, сохраненный в перем ен ной w orkerR esult, о т п р ав л я е м с я обратно о с новному J a v a S c r ip t-коду с помощ ью postMessage.

Данный код будет р а зм ещ а т ь с я в файле worker.js. дальше ►

545


подробности об объекте task для вычисления фракталов

Короткий п и т-сто п ... Мы с вами рассм отрели массу кода иа предыдущих страпицах. Давайте сделаем короткий пит-стоп, чтобы «до­ заправить» паши баки и желудки. Вам паверпяка захочется загляпуть украдкой «за кули­ сы» и узпать, па что п охож и task и worker Re suit вебсцепария worker (опи очепь п охож и друг па друга, в чем вы убедитесь далее). Итак, бер и те бутылку лю бим ой мипералки и давайте взгляпем па пих, пока вы будете отдыхать...

ta sk п о д у в е л и ч и т е л ь н ы м с ш е к л ^ м

Итак, ранее ВЫ видели ВЫЗОВ createTask

И

postMessage, ДЛЯ КОТОрЫХ ИСПОЛЬЗуеТСЯ task:

var task = createTask(nextRow); worker.postMessage(task);

При этом вам, возможно, интересно, на что похож task. Что ж, это объект, состоящий из свойств и значений: О пределяет с т р о к у , для кот орой мы ген ер и р уем значения пикселов. task = { row:

task содержит все значения, необходимые веб-сценарию w o r k e r для выполнения его вычислении.

1,

width:

О предел яет ширину строки. 102 4,

generation:

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

1,

r_ min: 2.074, r_max:

О п редел яю т вычисляемую нами об ­ ласт ь множества Мандельброта.

-3.074,

i: -0.252336, max_iter: escape:

};

546

глава 10

102 4,/

1025

J

Г- К о н т р о л и р у ю т точность вычислений.


применяем javascript на деле

/>

w o r k e ^ e ^ u lt л ° д у в е л и ч и т е л ь н ы м с ш е к л ° м А как насчет результатов (workerResult), которые мы получаем, когда worker заканчивает вычисление строки? var workerResult = computeRow(task.data); postMessage(workerResult);

На ЧТО ПОХОЖ о б ъ е к т workerResult? Он ОЧвНЬ

СХОЖ С task:

workerResult = { row:

w o rk e r прин им ает п е р е ­ данный ем у объект ta s k , а з а т е м добавляет в него свойство values, содержащее данные, необходимые для р и ­ сования строки в canvas.

Здесь все т о же са м о е , что и в task. И эт о здорово, поскольку когда мы получим workerResult от w o r k e r , мы будем зн а т ь все о task.

1,

width:

102 4,

generation:

1,

r_min:

2.074,

r_max:

-3.074,

i: -0.252336, max_iter:

102 4,

escape:

1025,

values:

[3,

9,

56,

- 1 , 22 ]

А э т о ч т о - т о новень­ кое. Здесь п р е д с т а в л е ­ ны значения каждого из пикселов, которые нам все еще нужно п р е о б ра зов ат ь в цвета (что делается в drawRow).

Пора снова в путь... Благодарим, что вы уделили п ек отор ое время и взгляпули вместе с пами па task и workerResult. Сделайте п оследпий больш ой глоток своей мипералки — мы спова отправляемся в путь!

дальше ►

547


обработка результатов работы worker fy ]

Возвращаемся к коду: как осущ ествляется обработка результатов работы worker

B

Q

Создать HTML-страницу ' I f l овдоВо к ynpiyppfijIfHulo

Создать веб-сценарии worker

[ y f ' Запустить веб-сценарии worker Реализовать код worker

I~~| Обработать результаты Вы уже видели, как веб-сцепарии worker геперирую т результаты. Теперь Код, касающийся взаимовзгляпем, что произойдет, когда мы получим их от worker. Как вы помпите, деиствия с пользователями когда мы создавали паши веб-сцепарии worker, мы задали обработчик со­ общ еп ий с им епем processWork: Наш обработчик сообщений вызыва­ var worker = new W o r k e r ("worker.js"); е т функцию processW ork, передавая ей event.data от w o r k e r , а также wo r k e r .опте ssage = function(event) { e v e n t.ta r g e t, представляющий собой processWork(event.target, event.data); ссылку на w o rk e r, который прислал } с о о т ве т с т в ую щ и е данные.

Когда worker отправит пам обратпо сообщ епи е со своими результатами, их обработкой займется фупк­ ция processWork. Как вы м ож ете видеть, ей передаю тся два параметра: target сообщ епия, представ­ ляющ ий со б о й ссылку па worker, которы й его отправил, и data сообщ епия (это объект task со зпачепиями для строки изображ епи я). Таким образом , теперь паша работа будет заключаться в том, чтобы паписать processWork (введите приведеппы й далее код в m a n d e l .j s):

function processWork(worker, workerResults)

Передаем р е з у л ь т а т ы d r a w R o w для рисования пикселов в canvas. Наш w o rk e r оказывается полностью свободным, п о э т о м у мы можем п о р у ­ чить ем у уже новую задачу. Для эт ого напишем функцию reassignWorker.

drawRow (workerResults); reassignWorker(worker);

Мы п о ч т и д о с т и г л и цели, так что давайте бы стро папиш ем фупкцию reassignWorker, раз уж мы о п ей заговорили. Вот как опа работает: мы проверяем строку, которую вычисляем, используя глобальпую перемеппую next Row, и если остаю тся ещ е строки для вычислепия (что мож по выяспить, взгляпув па количество строк в пашем canvas), мы поручаем worker повое задапие. В противпом случае, если боль­ ше п е остапется работы , которую требуется сделать, мы п росто присвоим свойству worker с имепем idle зпачепие true. Введите приведеппы й далее код тож е в m a n d e l .j s: л *лм ш пгкег сл е д у ю щ у ю с т р о к у , М ы создаем ся пор учим» э т о м у w o r k e r с У ^ которую необходимо ^ ^ ^ Г е м значение nextRow (чтобы function reassignWorker(worker) var row

if

nextRow++;

(row >= canvas.height)

{

worker.idle = true; } else { var task = createTask (row) ; worker.idle = false;

Если строка превысит высоту canvas либо сравняется с ней по положению, дело сделано! Мы заполнили весь canvas результатами от веб-сценариев, использован­ ных для вычисления множества Мандельброта, canvas — это глобальная переменная, которая была задана, когда мы вызвали setup Graphics в нашей функции init. \ Z t Ha^ еСЛ1 Z HaC

же 0С^ У ^ я строки для вычисления

worker.postMessage(task)

} Данный код будет р азм ещ а т ь ся в файле mandel.js.

548

глава 10


применяем javascript на деле

ъпо

Психоделический тест-драйв

SEJ

Ну хватит уже кода! Давайте проведем тест-драйв пашего прилож епия. Загрузите файл fractal.html в браузере и п осм отрите, как веб-сцепарии worker займутся работой. В зависимости от «пачипки» вашего компьютера ско­ рость прилож епия Fractal Explorer долж па стать пем по­ го выше, чем была рапее. Мы, собствеппо говоря, еще пе паписали пикакого кода для обработки изм епепия разм еров окпа браузера или щелчков с целью увеличепия фрактальпого изображ епия. П оэтом у все, что вы см ож ете увидеть па даппы й момепт, — это и зобр аж еп и е, к отор ое п риведепо справа. Тем пе м епее пока все хорош о, да?

Обработка собы тия click

* Такие дела! Очень жаль, что мы не можем уве­ личивать изображение и что оно пока еще не заполняет все окно, но мы дойдем до этого...

Наши веб-сцепарии worker трудятся пад вы числепием мпож ества Мапдельброта и возвращ ают результаты, чтобы мы могли парисовать их в canvas. Н о что произойдет, если вы щелкпете кпопкой мыши, чтобы увеличить изображ епие? К счастью, поскольку мы используем веб-сцепарии worker для осущ ествления иптепсивпы х вы числепий в ф оповом реж им е, иптерф ей с пользователя долж еп живо среагировать соответствую щ им образом па ваш щелчок. Тем пе м епее пам потребуется паписать пем пого кода для ф актической обработки собы тия click.

Создать HTML-страницу

J"оП)оГС оКIplonlpC&JICHUK» Q

Создать веб-сценарии worker Запустить веб-сценарии worker

\ у \ Реализовать код worker

Р Г Обработать результаты □

Код, касающийся взаимо­ действия с пользователями

Первое действие, которое нам потребуется предпринять, — это добавить обработчик, чтобы позабо­

<D титься о событиях, инициируемых щелчками мыши (помните, что щелчки осуществляются в нашем элементе canvas). Для этого мы просто добавим обработчик для свойства canvas с именем onclick: canvas.onclick = function(event) { handleClick(event.clientX,

};

e v ent.clientY)

Если пользоват ель щелкнет на canvas, мы вызовем ф у н к ­ цию handleClick с использова­ нием координат х и у м е с т а , где был сделан щелчок.

Добавьте данный код ниже вызова setUpGraphics в функции init в m a n d e l .j s.

©

Остается лишь написать функцию handleClick. Прежде чем мы это сделаем, на секунду задумаемся вот над чем: когда пользователь щелкает на canvas, это означает, что он хочет увеличить соответ­ ствующую область (вы можете вернуться к однопоточной версии по адресу http://wickedlysmart.com/ hfhtml5/chapter10/singlethread/fractal.html, чтобы увидеть данное поведение). Таким образом, когда пользователь щелкнет на canvas, нам нужно будет получить координаты области, которую он хочет увеличить, а затем привлечь все веб-сценарии worker кработе по генерированию нового изображения. Также не забывайте, что у нас уже имеется функция startWorkers для поручения новой работы любому незанятому worker. Давайте испытаем ее... дальше ►

549


тестирование и улучшения

Вызов kandleClick происходит когда пользоват ель щелкает на canvas, чтобы увеличить

фр—

Мы передаем координаты x, у м е с т а , где был сделан щелчок, то ест ь мы будем зн ат ь, в какой именно части экрана щелкнул пользователь.

6ражу

function handleClick (х, ^

Данный код изменяет ра зм ер ы о б "\ ласти ф ракт альн ого изображения, I к о т о р у ю мы вычисляем, используя У координаты X, у в центре новой

^

var width = r_max - r_min; var height = i_min ■ i max; var click_r = r_min

+ w id th * v /

var click_i = i_max + height

var zoom = 8;

r_min = click_r - width/zoom; г_шах = click_r + width/zoom; i_max = click_i - height/zoom; i_min = click_i + height/zoom;

startWorkers();

Еще один тест-драйв

, , c a n v a s .w id th ;

У /

Ч области. Он также следит за т е м , \ чт о6ы у но$ой 0§ласт и было т акое соот н ошение ш ирины и вы сот ы , как у сущ ест вую щ ей области.

c a n v a s .h e ig h t; ) ж е

Задаем значения для глобальных п е р е м е н ­ ных, используемых для создания объектов task для веб-сценариев worker, уровень увеличения определяет , насколько сильно мы увеличили ф ракт альн ое изображение, что, в свою оче­ редь, определяет , какие значения множества Мандельброта будут вычисляться.

Теперь мы готовы к п ерезапуску веб-сценариев worker.

Данный код будет разм ещ ат ься в файле m andel js.

Прекрасно! У нас появилась возмож­ ность увеличиват ь изображение, однако нам все еще нужно изм енит ь ра зм ер ы canvas, чтобы полност ью подогнать его под разм ер ы окна браузера. * чу

П роверим , какой эф ф ект произведут впесеппы е пами в код изм епепия. П ерезагрузите fractal .html в браузере и па этот раз щелкпите где-пибудь в canvas. Сделав это, вы увиди­ те, как веб-сцепарии worker пачпут работать пад увеличеппым представлением. Теперь у вас долж па появиться возмож пость приступить к исследованию ! П осле того как вы пемпого поиграете, впесем ряд фипальпых и зм епепий, чтобы довести даппую реа­ лизацию до копца.

550

глава 10


применяем javascript на деле

Подгоняем canvas под размеры окна браузера

[ y j f ' Создать HTML-страницу

|v f ^

|ог,)о!}о к i p i p e Hut°

[ у ] Создать веб-сценарии worker

Как уже отмечалось рапее, пам п еобходи м о, чтобы фрактальпое и зобра­ ж еп и е заполпяло окпо браузера, а это озпачает, что пам потребуется изм е­ пить размеры canvas, если измепятся размеры окпа. К роме того, если мы изм епим размеры canvas, то пам также придется поручить веб-сцепариям worker повый пабор задач по перерисовке фрактальпого изображ епия, чтобы опо заполпяло canvas с повыми размерами. Давайте папиш ем код для подгопки размеров canvas под размеры окпа браузера, а также п ереза­ пустим веб-сцепарии worker, раз уж мы об этом заговорили.

function resizeToWindow() { canvas .width = window.innerWidth;

Запустить веб-сценарии worker O ' Реализовать код worker Q T Обработать результаты □

Код, касающийся взаимо­ действия с пользователями

Функция resizeToWindow следит за т е м , чтобы ширина и высота canvas задавалась в со от вет ст вии с новыми р а зм ер а м и окна.

canvas.height = window.innerHeight; var width = ((i_max - i_min) var r_mid = (r_max + r_min)

* canvas.width / canvas.height); / 2;

r_min = r_mid - width/2; r_max = r_mid + width/2; rowData = c t x .createlmageData(canvas.width,

startWorkers () ;

S

И снова п ерезапускаем веб-сценарии worker.

1)

Она также обновляет значения, ко орые w o r k e r будет использоват ь ^ для осуществления своих вычислении, взяв за основу новую ширину и высоту (мы заботимся о т о м , чтобы ф р а к ­ тальное изображение всегда совпадало по р а зм е р а м с canvas и сохраняло с о ­ отношение ширины и высоты окна).

Есть одна адм инист рат ивная дет ал ь, использующая г л о ­ бальную перем ен н ую , о кот орой мы вам еще не говорили: rowData. row D ata - эт о объект \m ageD ata, который мы используем для рисования пикселов в ст роке canvas. Таким образом, при изменении р а зм е р о в canvas нам по т ре б у е т с я вновь создат ь объ ект ro w D a ta , чтобы он имел значение ш и ­ рины, совпадающее с новым значением ширины canvas. В згл я ­ ните на функцию d r a w R o w в mandellib.js, чтобы у ви д ет ь, как ro w D ata использует ся для рисования пикселов в canvas.

Теперь пам пужпо устаповить resizeToWindow в качестве обработчика для собы тия, инициируем ого при изм епеп и и разм еров окпа браузера: w in d o w .o n r e s iz e

=

f u n c t i o n ()

{

r e s iz e T o W in d o w ( ) ;

}; Даппы й код пужпо поместить в фупкцию init в mandel. js, прямо под вызовом setUpGraphics.

Данный код будет разм ещ ат ься в файле mandel.js. дальше ►

551


управление фрактальными поколениями

Дотошный ппгф mrftajL программист Осталась еще одпа вещь, без к оторой код попросту пе будет корректпым. Давайте вместе поразмыш ­ ляем пад следующ ей ситуацией: у вас им еется группа веб-сцепариев worker, которы е успеш по трудятся пад вы числепием своих строк, и вдруг у пользователя возпикает н еобходим ость щелкпуть па изображ епии, чтобы увеличить его. Н ичего хорош его в этом пет, поскольку веб-сцепарии worker уже работаю т пад вы числепием своих строк, а теперь пользователю понадобилось измепить и зображ епи е целиком, что делает всю их работу беспол езпой . Еще хуже то, что веб-сцепарии worker пе будут иметь попятия о том, что пользователь произвел щелчок, и в лю бом случае стапут отправлять свои результаты обратпо. А еще хуже то, что код в осп овп ой страпице будет охотп о припимать и отображать даппы е строки! Это пе копец света, по мы столкпемся с точпо такой ж е п роблем ой, если пользователь изм епит размеры ° КПа"

для редактора: извиняемся за небольшую напыщенность здесь но после ^ столь большого количества пройденных ст раниц эта новость может додить вас...

Зам етка

На даппы й м омепт вы, вероятпо, пи разу бы пе обратили па это впимапия, поскольку у вас им еется пе так мпого веб-сцепариев worker, при этом опи очепь бы стро вычисляют одпи и те ж е строки для пового и зображ епия, перезаписы вая предыдущ ие, пекорректпы е строки. Тем пе м епее возпикает ощущ епие, что здесь что-то пе так. К роме того, впести исправлепия пастолько легко, что мы п росто обязапы это сделать. Следует призпаться: мы зпали, что так будет, и вы, возм ож по, помпите малепькую перемеппую generation, с к оторой мы сталкивались рапее. П ри каждом перезапуске паших веб-сцепариев worker мы увеличиваем зпачепие generation. Также п е забывайте об объекте worker Results, которы й посту­ пает обратпо от worker: у каждого результата имеется собствеп п ое поколепие в качестве свойства. Та­ ким образом , мы мож ем использовать перемеппую generation для того, чтобы узпать, получили мы результат, имею щ ий отпош епие к текущей или ж е к предыдущ ей визуализации. В песем п еобходим ы е исправлепия в код, а затем смож ем поговорить о том, как опи работают. Отредак­ тируйте фупкцию processWork в m a n d e l .j s и добавьте туда эти две строки: function processWork (worker, workerResults) { if

(workerResults . generation == generation) drawRow (workerResults) ;

^

Mb/ проверяем р е з у л ь т а т

{

0m Wo,r^ lrJ чтобы выяс­ н и т ь , с о о т в е т с т в у е т ли его поколение т екущ ем у.

} тт

,

,

,

х

reassignWorker (worker) ;

В л„А м * м« вручаем w o r k e r уже новую ра б о т у '

Если с о о т в е т с т в у е т , то мы р и и п су е м с т р о к у , в прот ивном случае }°А Ж Н °

ст ар ой , и шя проигн орируем ее.

Таким образом , мы удостоверяемся в том, что текущее поколепие, пад которы м мы работаем , соответ­ ствует поколепию результата, возвращ еппого веб-сцепарием worker. Если так опо и есть —отличпо, тог­ да пам потребуется парисовать строку. Если ж е соответствия пет, строка, скорее всего, является старой, поэтом у мы п росто будем ее игнорировать (очепь жаль, что паш worker впустую потратил па п ее свое время, одпако мы пе хотим рисовать старую строку из предыдущ его и зображ епи я па экрапе). Итак, вот и все, па этот раз по-пастоящему. П ора убедиться в том, что вы впесли все приведеппы е выше изм епепия, и подготовиться к...

552

глава 10


применяем javascript на деле

Время финального mecm-gpauBa! Вот и всё! Ваш код долж ен быть полностью готов к работе. Загрузите файл fractal .html в браузере и посм отрите, как веб-сценарии worker займутся де­ лом. Данная версия долж на работать бы стрее и быть более отзывчивой, чем оригинальная однопоточная версия (если в вашем компью тере установ­ лен п роц ессор с более чем одним ядром, то она будет работать намного бы стрее).

Создать HTML-страницу

I

^ JoJUpBo кIpPiDpCoJIfHUIo

Q

Создать веб-сценарии worker Запустить веб-сценарии worker Реализовать код worker

Я Г Обработать результаты

Код, касающийся взаимо­ действия с пользователями

Поразвлекайтесь... попробуйте увеличить и зо­ браж ения... исследуйте их. Д айте нам знать, если найдете во м нож естве М андельброта какую-нибудь ранее неизвестную «территорию » (отправь­ те свои скриншоты на #hfhtml5 ч ер ез Твиттер, если пож елаете).

Щ е лка й т е, увеличивайт е,

дальше ►

553


г В ЛАБОРАТОРИИ Е сл и вы п и ш е т е в ы с о к о п р о и з в о д и т е л ь н ы й ко д , то з а х о т и т е п р о в е р и т ь , к а к к о л и ч е с т в о в е б -с ц е н а р и е в worker п о в л и я е т на в р е м я в ы п о л н е н и я р а б о ты в а ш и м п р и л о ж е н и е м . Д л я э то го вы м о ж е т е в о с п о л ь з о в а т ь с я м о ­ н и т о р о м за д а ч ка к в о п е р а ц и о н н о й с и с т е ­ ме O S X , т а к и в W in d o w s . Е с л и в е р н у т ь с я к наш ей о р и ги н а л ь н о й о д н о по то чн о й версии (п о а д р е с у h ttp ://w ic k e d ly s m a rt.c o m /h fh tm l5 / c h a p te r l O /s in g le th r e a d /fra c ta l.h tm l), то к а р т и ­ ну и с п о л ь з о в а н и я я д е р пр и в ы п о л н е н и и п р и ­ л о ж е н и я на н а ш е м к о м п ь ю т е р е вы м о ж е те у в и д е т ь на д и а гр а м м е , п р и в е д е н н о й с п р а в а . Н а ш к о м п ь ю т е р и м е е т в о с е м ь я д е р , ко т о р ы е б у д у т д о с т у п н ы п р и л о ж е н и ю F ra c ta l E x p lo re r с в е б -с ц е н а р и я м и ли чество

worker,

worker,

и мы з а д а е м к о ­

со о тв е тств ую щ е е этом у

ч и с л у я д е р , у к а з а в numberOfWorkers = 8. К а к вы м о ж е т е в и д е ть на м о н и т о р е а к т и в н о ­ с ти , все 8 я д е р и с п о л ь з у ю т с я по м а к с и м у м у . К а к вы д у м а е т е , ч т о будет, е с л и м ы з а д а д и м к о л и ч е с т в о в е б -с ц е н а р и е в worker, р а в н о е 2, 4, 16 ил и 3 2 ? И ли р а в н о е к а к о м у -т о п р о ­ м еж уточном у значению ? П о п р о б у й т е т а к с д е л а т ь на с в о е м к о м п ь ю ­ те р е и вы я сните , ка ки е зн а че н и я явл яю тся н а и б о л е е п о д х о д я щ и м и д л я ва с.

О О О

v 3 нашем к о м п ь ю т е р е — восемь ядер. Одно из них использует ся по м а к с и м у м у и не может вычислять бы ст рее, чем позволяет его рабочая част от а. Остальные семь ядер н и ­ чего не д е л а ю т , чтобы помочь ему. Теперь все наши в о ­ семь ядер загружены работ ой, и вычисление ф ракт альн ого и зо ­ бражения о с у щ е с т ­ вляется НАМНОГО быстрее.

О О О

554

глава 10


применяем javascript на деле

ЗАСТО ЛБИ ТЕ С ЕБ Е УЧАСТО К! Вы сделали это! Вы создали полностью функциональное приложение Fractal Explorer, которое готово к исследованию областей множества Мандельбро­ та. Так чего же вы ждете — приступайте и найдите свой кусочек виртуаль­ ной Вселенной. А когда отыщете, запечатлейте и вставьте его сюда, а затем присвойте своему новому участку название. О О О

[' <

[V

Fractal Explorer | [ + 1Q http': //focal host j - Beth/HTML 5/fracta I/f racta l~.tr <5 |

(O*

GoogTe

*)

ВСТАВЬТЕ СЮДА СВОЙ УЧАСТОК ИЗ МНОЖЕСТВА МАНДЕЛЬБРОТА

А


дополнительная функциональность api-интерфейсэ web workers

Вам не кажется, что с л ед у ет знать кое-что ещ е об A PI-и н т е р ф е й с е W eb W orkers? Изучите с л е д у ю щ и е пару страниц, чтобы узнать о б о всем , что мы не рассказали в этой главе.

П р е р ы в а н и е В ы п о л н е н и я w o rk er Вы создали веб-сценарии worker для вы полнения задачи, и после того как она была выполнена, захотели избавиться от всех этих worker (они отнимаю т ценную память браузера). Вы м ож ете п ре­ рвать вы полнение worker из кода своей осн овн ой страницы следу­ ющим образом: w o r k e r .terminate() ;

Данная строка приведет к отм ене выполняющ егося сценария worker, поэтом у используйте ее осторож н о. Прервав вы полнение worker, вы не см ож ете повторно использовать его; вам придется создать новый worker. worker также м ож ет сам остановить свое вы полнение, вызвав close () ; (изнутри worker).

• о ц ж а о ш и б о к w o rk er v

J

Ч то будет, если с worker случится какая-то ужасная ошибка? Как ее устранить? И спользуйте обработчик one г г or для перехвата любых ош ибок, а также для получения отладочной информации: worker.onerror

function(error)

{

document.getElementByld("output") .innerHTML = "There was an error in

+ er r o r .filename +

" at line number " + error.lineno + ": " + error.message;

556

глава 10


применяем javascript на деле

Цс31°Ль5«>Вание

ддгг г}^0КГ^2а11Г°СоБ

Вы не см ож ете вставлять новые элементы <script> для вы полнения JSO N P-запросов из worker, однако у вас будет возм ож ность использовать importScripts для соверш ения JSO NP-запросов сле­ дующим образом: function makeServerRequest() { importScripts("h t t p ://SomeServer.com?callback=handleRequest") ;

function handleRequest (response)

{

postMessage (response);

} makeServerRequest () ;

Помните JSONP ? Включите свою финкшю обратного вызова в URL-запрос, и она бидет вызываться с передачей JSON -результатов параметре response.

IfciiojibSoBaHue ixo^ort^trij^tg Б worker Вы могли упустить это из виду (мы бы стро прош ли мимо данного аспекта

д Г “ И1а™ <,UO“ ' J=)> ТаК" М ° браЗОМ' ЧТОбЫ ° Н °™ Р “

взглянув ня

т

п р ои зв ол ь н ую ™ ^ ™

var quotes - [ i hope life isn't a joke, because I don't get it.", "There is a light at the end of every t unnel... just pray it's not a train!”, "Do you believe in love at first sight or should I walk by again?"]; function postAQuote() { var index = Math, floor (Math, r a n d o m () * quotes.length) ; 7 Помещаем эт и две строки postMessage (quotes [index] ) ;

} postAQuote () ; setlnterval (postAQuote,

3000) ;

j

в функции? postAQuote...

„вызываем postA Q u ote для немедленной от правки задаем интервал отправки ^ ц и т а т ы , ал з а т е м заииьт и п т ^ у и /» для ----^ __ У дополнительных, ц и т а т , равный 3 секундам.

Ц одм астее^ье ^ W o rk er Если вашему worker потребуется помощь в вы полнении его задачи, он сможет создать свои соб­ ственные веб-сценарии worker. Допустим, вы поручаете своему worker области изображ ения, ко­ торы е он долж ен вычислить, a worker при этом м ож ет решить, что если область превышает некий разм ер, то работу по ее вы числению следует распределить между его собственны ми субсценария­ ми subworker. worker генерирует subworker тем ж е путем, посредством которого код в вашей странице создает worker:

, . .... var worker = new W o r k e r ("subworker.js );

П ом ните, что все subworker, как и обычные worker, являются довольно «тяжеловесными», они за­ нимают память и выполняются как отдельные потоки. П оэтом у будьте осторож ны с количеством создаваемых subworker. дальше ►

557


обзор аpi-интерфейса web workers

КЛЮЧЕВЫЕ — МОМЕНТЫ ■

Без веб-сценариев worker JavaScript является од­ нопоточным, то есть может выполнять только какоето одно действие за раз.

Вы можете выяснить, какой именно worker от­ правил сообщение, воспользовавшись свойством event.target.

Если вы взвалите на JavaScript-nporpaMMy слишком много работы, то на экране может появиться диало­ говое окно Slow Script (Медленный сценарий).

Сообщения копируются, а не совместно используют­ ся КОДОМ Вашей ОСНОВНОЙ СТраНИЦЫ И worker.

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

Код для веб-сценария worker располагается в от­ дельном файле и обособлен от вашего основного кода.

У веб-сценариев worker нет доступа к любым функ­ циям в коде вашей страницы, а также к объектной модели документа (DOM).

Код в вашей странице и веб-сценарий worker обща­ ются посредством сообщений.

Для отправки сообщения веб-сценарию worker ис­ пользуйте postMessage.

Вы можете отправлять строки и объекты веб­ сценарию worker С ПОМОЩЬЮ postMessage. Отправлять функции веб-сценарию worker нельзя.

Для приема сообщений обратно от worker не­ обходимо задать для свойства worker с именем onmessage фуНКЦИЮ обработчика.

Для получения сообщений веб-сценарием worker от кода вашей страницы необходимо задать для его свойства onmessage фуНКЦИЮ обработчика.

558

Когда worker готов к отправке результата обратно, он вызывает функцию postMessage и передает ей данный результат в качестве аргумента. Результаты работы worker инкапсулируются в объ­ екте event и располагаются в свойстве data.

глава 10

Вы можете использовать сразу несколько веб­ сценариев worker для осуществления объемных вычислений, которые могут быть разбиты на ряд небольших задач (например, при проведении вычис­ ления фрактальной визуализации или создании изо­ бражения методом трассировки лучей). Каждый worker выполняется в своем собственном потоке, поэтому ваш компьютер обладает многоядерным процессором, веб-сценарии worker смогут выполняться параллельно, что повышает скорость вычислений. Вы можете прервать выполнение worker, вызвав worker .terminate () ИЗ КОДЭ СВОвЙ СТраНИЦЫ. В результате выполнение сценария worker будет прекращено, worker также может сам остановить свое выполнение, вызвав close о . Все worker располагают СВОЙСТВОМ onerror. Вы можете задать для него значение в виде функции обработчика ошибок, которая будет вызываться в случае возникновении ошибки при выполнении сце­ нария worker. Для включения и использования JavaScriptбиблиотек в файле вашего worker используйте importScripts. Вы также можете использовать importScripts в сочетании с JSONP. Реализуйте функцию обратно­ го вызова, которая передается в URL-запросе, в фай­ ле worker. Несмотря на то что у веб-сценариев worker нет доступа к объектной модели документа (DOM) и к функциям в вашем основном коде, они могут исполь­ зовать XMLHttpReguest И localStorage.


применяем javascript на деле

1 Л Щ ,5 - К Г °ссК °Г Д Здорово! Вы добрались до конца главы 10. Откиньтесь на снинку стула, расслабьтесь, а затем закрените изученны й материал, немного но раб отав другим нолуш арием своего мозга и разгадав кроссворд.

По горизонтали

По вертикали

3. Аппаратная особенность процессора, дающая ему воз­ можность выполнять более одной задачи за раз. 6. Свойство, используемое для регистрации обработчика с целью приема сообщений. 7. В нашем первом примере мы использовали эту игру. 9. Вы можете передавать______________ веб-сценариям worker С ПОМОЩЬЮ postMessage. 11. У веб-сценариев worke г нет доступа к _____________ . 12. Наиболее широко известный фрактал. 13. _______________ /веб-сценарий worker.

1. ________________выполнения. 2. Веб-сценарии worker могут использовать XMLHttpReguest И у НИХ ИМевТСЯ ДОСТуП К__________. 4. Посредством НИХ о б щ а ю тс я manager, js И Ввбсценарии worker. 5. Инструмент для импорта дополнительного кода В worker. 8. Что нужно ввести для того, чтобы прекратить выполне­ ние worker? 10. В случае с множеством Мандельброта используются числа. 14. ЧТО НУЖНО ВВеСТИ ДЛЯ ТОГО, ЧТОбы СОЗДаТЬ Worker.

15. Человек, который написал оригинальную версию Fractal Explorer. 16. Красивая область виртуальной сельской местности в множестве Мандельброта называется «____________ острова».

owie он cv)VY)dog

-02 ЭИ 020Wie wvg V(?20>iY)H IQW (OHQVV дальше ►

559


решение упражнения

(ТАНЬ 6рду>ер«м. Решение UjniUijio время прлгрВорлгрься браузером,

оП,0ниВа1°ЩиМ JaVa^cTi]3!— К°Д.

window.onload = f u n c t i o n () { var worker = new W o r k e r ("wor k e r .j s " ); worker.onmessage = f u n c t i o n (e v e n t ) { a l e r t ("Worker says " + event.data);

} for

(var i = 0; i < 5; i++)

{

wo r k e r . p o s t M e s s a g e ("pin g " );

Данный код о т п р а в и т пя т ь сообщений со строкой "ping" § сб-сценарию w o rk e r, к о ­ торый в о т в е т от ош л е т пят ь сообщений со строкой "pong", п о э т о м у на экране п о ­ явится пя т ь диалоговых, окон a le r t с т е к ­ с т о м "W ork er says pong".

} } window.onload = f u n c t i o n () { var worker = new W o r k e r ("wor k e r .j s " ); worker.ommessage = function(event) { a l e r t ("Worker says " + event.data);

}

Данный код о т п р а в и т пя т ь сообщений со строкой "pong" веб-сценарию wor,ken который пр о и гн о р и р ует их, поскольку они не вклю ч а ю т ст р о к у "pj^g"- Никакого вы ­ вода генерироват ься не будет.

for(var i = 5; i > 0; i— ) { wo r k e r . p o s t M e s s a g e (" p ong");

}

window.onload = function()

{

var worker = new W o r k e r (" w o rker.j s " ); worker.onmessage = fu n c t i o n (e v e n t ) { a l e r t ("Worker says " + event.data) wo r k e r . p o s t M e s s a g e (" p ing");

} wor k e r . p o s t M e s s a g e ("ping");

window.onload = function()

Данный код о т п р а в и т сообщение со с т р о ­ кой "ping"]'а каждый р а з назад б удет п о с т у п а т ь сообщение со строкой "pong"t он с т а н е т о т п р а в л я т ь новое такое же сообщение, п о э т о м у в р е з у л ь т а т е мы будем Iн аблюдать бесконечный цикл из появ­ ляющихся диалоговых окон a fert с т е к с т о м "Worker says p o n g u\.......................................................

{

var worker = new W o r k e r ("wor k e r .j s " ); worker.onmessage = function(event) { a l e r t ("Worker says " + event.data);

} setlnterval(pinger,

1000);

function p i n g e r () { w o r k e r . p o s t M e s s a g e ("pin g " );

}

560

глава 10

Данный код б удет о т п р а в л я т ь сообщение со ст рокой "pi^g" каждую секунду, п о э т о ­ м у мы ст а н ем получ ат ь в о т в е т сообще­ ние со ст рокой "pong" всякий ра з, когда он будет о т п р а в л я т ь "ping".


применяем javascript на деле

|озьми в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Решение Несмотря на то что обычно веб-сценарии worker получают рабочие задания посредством сообщений, такой подход вовсе не обязателен. Взгляните на дан­ ный отличный и компактный способ сделать необходимую работу с помощью веб-сценариев worker и HTML. Когда вы разберетесь в том, что делает данный код, опишите это внизут <! doctype html>

quote.htm l

<html lang="en"> <head> <title>Quote</title> <meta charset="utf-8"> </head> <body> <p id="quote"></p> <script> var worker = new W o r k e r ("quote.js"); w o r k e r .оптеssage = function(event) { document.getElementByld("quote").innerHTML = event.data;

} </script> </body>

< /h tm l>

qwote.js

var quotes = ["I hope life isn't a joke, because I don't get it.", "There is a light at the end of every tunnel....just pray it's not a train!", "Do you believe in love at first sight or should I walk by again?"]; var index = Math.floor(Math.random() * quotes.length);

postMessage(quotes[index]);

Свое описание приведите здесь:

В НТМL у нас имеется скрипт , создающий w orker, выполнение кот орого зап ускает ­ ся незамедлит елт о. worker произвольно выбирает цит ат у из массива quotes и о т ­ правляет ее основному коду с помощью postMessage- O сновной код извлекает цит а­ т у из event.data и добавляет ее на страницу в элемент <р> с id в виде "quote".

дальше ►

561


решение упражнения

562

глава 10


применяем javascript на деле

Как было бы здорово, если бы это уже был конец книги. Если бы не было больше никаких ключевых моментов, головоломок, JavaScriptлистингов или чего-то еще. Об этом aa^w HO лишь мечтать...

Доздравляем! 1)ьх Д о Ш Л и Д о ХонДа.

Конечно же, еще есть приложение. И выходные сведения. А также адрес нашего сайта... Так просто сбежать у вас не получится — мы серьезно!

дальше ►

563



П р и л ож ен и е. О ста в ш и еся

+

т е м ы

Десять важных тем

(которые мы не рассмотрели)

Мы изучили множество различных тем, и вы почти закончили читать эту книгу. Нам грустно с вами расставаться, но прежде, чем мы это сделаем, поведаем еще кое о чем, чтобы подготовить вас к выходу в реальный мир. Вообще-то изначально мы включили в книгу все, что читателям следует знать о HTML5 (не рассмотренное в предыдущих главах), уменьшив размер шрифта до 0,00004. Но такой мелкий текст невозможно было прочитать. По­ этому нам пришлось выбросить большую часть и оставить в приложении только десять самых важных тем.


modernizr и audio

№ 1. Modernizr Читая книгу, вы, вероятно, обратили внимание на то, что нри н е­ обходи м ости выяснить, ноддерж ивает ли браузер тот или и н ой API-интерф ейс, оказывается, что едины й сн особ сделать это отсут­ ствует; фактически, ноддерж ка ночти лю бого API-интерф ейса детек­ тируется но-разному. Н анример, в случае API-интерф ейса G eolocation мы ищ ем объект geolocation как свойство объекта navigator, в то время как в API-и нтерф ей се Web Storage мы нроверяем , он ределен ли localStorage в объекте window. Что касается API-интерф ейса V ideo, то в дан ной ситуации мы нроверяем , есть ли у нас возмож ность соз­ дать элем ент video в объектной модели документа (DOM ) и т. д. На­ верняка существует сн особ но лучше? M odernizr — это JavaScript-библиотека с открытым исходны м кодом, кото­ рая обеснечивает едины й ин тер ф ей с для детектирования того, что им енно ноддерж ивает конкретны й браузер. M odernizr охватывает всевозмож ны е детали различны х снособов детектирования, включая даж е ф акторинг в сложных ситуациях с устаревшими браузерами. Домаш няя страница M odernizr рас­ полагается но адресу h t t p : //w w w .m o d e r n iz r .c o m /. Библиотека M odernizr ш ироко ноддерж ивается раз­ работчиками, и вы будете часто сталкиваться с ее н рим енением в И нтернете. Мы рекомендуем вам ее.

Включение Modernizr В сбою страницу Д ля нснользовання M odernizr вам нужно загрузить эту JavaScript-библиотеку в свою страницу. Для этого сначала нотребуется зайти на сайт M odernizr (h t t p : //w w w .m o d e r n iz r .c o m /d o w n lo a d /), где вы см ож ете нрои звести пользовательское конф игурирование библиотеки, которая в итоге будет содержать только н еобходим ы й вам код для детектирования (либо м ож ете включить в н ее сразу все, находясь на стра­ н ице но данному адресу). Сделав это, сохраните библиотеку в файле и загрузите его в свою страницу (н осети те веб-сайт Modernizr, чтобы найти дополнительны е учебны е материалы и документацию но оптимальным методикам работы ).

Как определяется, ч то именно поддерживает браузер П осле инсталляции M odernizr нроц есс детектирования НТМ Ьб-элементов и API-интерф ейсов JavaScript станет намного легче и нроще: Пример определения поддержки APIинтерф ейсов d eolocatio n , VJeb Storage и Video последовательным образом.

^

Примечание: возможности библиот е­ ки M odernizr п р о ст и р а ю т ся значительно дальше прост ого детектирования поддержи­ ваемых A P I-инт ерф ейсов; она также п о ­ зволяет определят ь поддерживаемые CSSп а р а м е т р ы л видеокодеки и многое другое. П оэтому обязательно ознаком ьт есь с ней!

566

приложение

if

(Modernizr.geolocation)

{

console.l o g ("You have geo!");

if

(Modernizr.localstorage)

{

console.l o g ("You have web storage!");

if

(Modernizr.video)

{

console.l o g ("You have video!");


оставшиеся темы

№ 2. Элемент audio и A PI-интерфейс Audio HTM L5 предусматривает стандартны й сн особ восн рои зведен ия аудио на ваших страницах с использо­ ванием не плагинов, а элемента <audio>: Выглядит знакомо? Д а , audio < a u d i o s r c = " s o n g . i n p 3 n i d = Mb o o m b o x n c o n t r o l s > поддерживает аналогичную ф у н к S o r r y b u t a u d io i s n o t s u p p o r t e d i n y o u r b r o w s e r . Циональность> как и video ( е с т е < /a u d io > ственно, за исключением возмож ­ ности воспроизводить видео). П омимо элемента <audio>, существует соответствую щ ий API-интерф ейс A udio, ноддерж иваю щ ий ме­ тоды , которы е вы и ожидали бы увидеть, нанример play, pause и load. Если вам все это нокажется знакомым — это хор ош о, носкольку API-интерф ейс A udio является отраж ением (в соответствую щ их случаях) API-интерф ейса V ideo. API-интерф ейс A udio также ноддерж ивает м ногие свойства, с кото­ рыми вы сталкивались в API-и нтерф ей се V ideo, нанример src, currentTime и volume. Н иж е нриведен небольш ой связанный с аудио код, чтобы вы ночувствовали, как данны й API-интерф ейс иснользуется в сочетании с элем ентом в странице: va r

a u d io E le m e n t = d o c u m e n t. g e tE le m e n t B y ld ( "b o o m b o x ") ;

a u d io E le m e n t . v o lu m e

=

.5 ;

Извлекаем ссылку на элем ен т audio, после чего у м ен ьш аем гр о м к о с т ь звука на 1 / 2 и запускаем воспроизведение.

a u d io E le m e n t.p la y ( ) ;

Как и в случае с видео, каждый браузер но-своему реализует внеш ний вид элементов унравления нроигрывателем (в число которы х обы чно входит нолоса воснроизведения, кнонки ностановки на наузу и регулирования громкости). Н есм отря на нростую функциональность, элем ент audio и API-интерф ейс A udio нредоставляю т вам ш ирокий контроль. П одобн о тому как мы ностунали с элем ентом video, вы см ож ете создавать и н терес­ ные веб-нриложения, предусматривая скрытие элементов унравления из виду и унравление воснроизведением аудио в своем коде. А с номощ ью HTM L5 тенерь у вас есть возмож ность делать это без н ео б ­ ходим ости иснользовать (и изучать) нлагины.

С тан д ар т В сфере аудцоформатов П рискор бно, но, как и для видео, стандартного ф ормата для аудио нет. Понулярны три формата: MP3, WAV и O gg Vorbis. Вы увидите, что ноддерж ка данны х форматов ва­ рьируется среди браузеров (на м омент нанисания книги Chrom e был единственны м браузером, ноддерживавш им все три формата).

дальше ►

567


j Query

He забывайте, что Ajax — эт о всего лишь н а звание шаблона использования XM L H ttpRequest для извлечения данных, как отмечалось в главе 6 .

3 . j Q uery

jQ uery нредставляет со б о й JavaScript-библиотеку, иризваиную уменьшить количество, а также унростить большую часть JavaScript-кода и синтаксиса, которы е н еобходим ы для работы с объектной моделью документа (DO M ), использования Ajax и добавления визу­ альных эф ф ектов к вашим страницам. jQ uery является весьма нонулярной, ш ироко иснользуемой библиотекой и ноддерж ивает возмож ность расш ирения носредством своей нлагиновой модели. jQ uery не нозволяет сделать ничего такого, чтобы было бы невозм ож но с номощ ью JavaScript (как мы уже говорили, jQ uery является всего лишь JavaScript-библиотекой), од­ нако она дает возмож ность сократить количество кода, к оторое вам нридется нанисать. Понулярность jQ uery говорит сама за себя, хотя м ож ет потребоваться н ек отор ое время, чтобы вы нривыкли к ней. П осм отрим, что м ож но сделать с номощ ью библиотеки jQuery. И сследуйте ее бол ее нристально, если реш ите, что она будет вам нолезна. Для начала вонрос: ном ните ли вы все те функции w indow .onload, которы е мы нисали \ но ходу книги? Нанример: т а к т и ч е ск о е 3 наши они ^ window, on load = f u n c t io n () { ^ а н и е jQ uery являете a l e r t ("the page i s lo a d e d !" );

деЗНЫМ навыКОМ> п о м о га ет , п о н я т ь код,

,

д .п А вот то ж е самое, но с иснользованием jQuery: $ (document) . read y ( fu n c tio n () { <— a l e r t ("the page i s lo a d e d !" );

писанный другими. К ак и в нашей версии: когда за гр узка докум ент а б удет закончена, вызвать м о ю функцию.

}) ; М ожно сократить данный код ещ е больше, до: $ ( fu n c tio n ()

{

Это классно, но чтобы привы кнут ь, п от реб ует ся немного времени. Не беспокойтесь — все эт о быстро

a l e r t ("the page i s lo a d ed ! ") ;

^

^

npiAgm i M

делоМ.

}) ; А что с извлечением элементов и з объектной модели документа (DOM)? И м енно здесь jQ uery блистает. Донустим, в вашей странице им еется якорь с id в виде "buynow" и вы хоти те назначить обработчик со­ бы тий, инициируемы х нри щелчке кнонкой мыши, для собы тия c l i c k данного элемента (как мы уже делали ранее несколько раз). Вот как это м ож но сделать: Так что же здесь происходит ? Сначала мы задаем ф ун кцию , кот орая будет вызываться по завершении загрузки страницы. $ (fu

n c tio n

() { _____

$ ( "# b u y n o w M) a le r t (пI

D ' >) ;

568

приложение

. c lic jM fu n c tio n w ant

to

buy

()

{

Д алее мы извлекаем якорь с id в виде "buynow" (следует о т м е т и т ь , что jQ u e ry использует CS S -синтаксис для выборки элем ен т ов).

n o w ! 11) ;

З а т е м мы вызываем jQ u e ry - м е т о д click в отношении р е з у л ь т а т а для задания обработчика onclick.


оставшиеся темы

Н а самом деле это лишь начало; мы м ож ем так ж е легко задать обработчик собы тий c l i c k для каждого якоря на странице: Для эт ого нам п о т р еб ует ся использовать $ ( f u n c t i o n () { лишь с о о т ве т с т в ую щ е е имя тега. $ ( " а ” ) . c l i c k ( f u n c t i o n () a le r t ( " I

w ant

to

{

buy

n o w !")

;

});

Сравните показанное здесь с кодом, который вам пришлось бы н ап и сат ь, используя J a v a S c rip t без jQ uery.

}); Н апр им ер, мы можем найти все элемент ы <Н>, кот оры е являются дочерними по о т ­ ношению к э л е м е н т у с id в виде "playlist".

Мы также мож ем делать бол ее сложны е вещи: $ ( f u n c t io n ()

Г

{

>

$ ( " # p la y lis t

li" )

.a d d C la s s ( " f a v o r it e " )

\\ .

;

^

Д

з а т е м добавить

^ их в класс "favorite".

X

Ч_ Вообще т о здесь jQ u e ry лишь « ра зо гр е ва е т с я »; данная библиотека позволяет делат ь вещ и, намного сложнее этик.

У jQ uery есть соверш енно другая сторона, которая нозволяет осуществлять лю боны тны е и н тер ф ей с­ ные трансф ормации элементов, как ноказано далее: $ ( f u n c t i o n ()

{

$ ( " # s p e c i a l o f f e r " ) . t o g g l e ( f u n c t i o n () $ ( t h i s ) . a n im a t e ( {

},fu

n c t i o n ()

b a c k g r o u n d C o lo r :

" y e llo w "

b a c k g r o u n d C o lo r :

" w h ite "

},

800);

{

$ ( t h i s ) . a n im a t e ( {

; }) ;

{

1

},

300);

Э т о т код п ереклю чает элем ен т с id в виде "speda!offer" из состояния, в к о т о ро м он желтый и и м еет ширину 2 0 0 пикселов, в состояние, в к о т о ­ р о м он белый с шириной ЗОО пикселов, при э т о м п е р е ­ ход между двумя данными состояниями анимируется.

Как вы м ож ете видеть, с номощ ью jQ uery возм ож но м ногое, нри этом мы даже еще не начинали раз­ говор об иснользовании дан ной библиотеки для общ ения с веб-службами и обо всех нлагинах, которы е работаю т с jQuery. Если вы заинтересовались дан ной тем ой, введите в браузере адрес h ttp ://jq u e r y . с о т / и изучите имею щ иеся там учебны е материалы и документацию. А также загляните в книгу « И зу ч а е м р а б о т у с j Q u e r y » (Head First jQuery)!

дальше ►

569


XHTML и SVG

№ 4 . XHTML м ертв, 9a здравствует XHTML Мы довольно ж естко новели себя с XHTM L в этой книге, сначала во время дискуссии «XHTML мертв», а затем н оздн ее, когда вели речь о «JSON нротив XML». Вся нрав да заключается в том, что когда дело доходи т до XHTM L, то здесь им еется в виду версия XHTM L 2 и выше, которая умерла, нри этом вы, фактически, м ож ете нисать свою НТМЬб-разметку, иснользуя XHTM L-стиль, если захотите. П очему вы м ож ете этого захотеть? Ч то ж, вам м ож ет потребоваться осуществлять валидацию или трансф ормацию своих документов как XML либо обеснечить ноддержку XML-технологий вроде SVG (см. тему № 5), ко­ торы е работаю т с HTML. Давайте взглянем на н р остой XHTM L-документ, а затем нройдем ся но основны м аснектам (для нас не нредставлялось возмож ны м новедать обо всем, что вам нотребуется знать но дан ной теме, как и обо всех вещах, связанных с XML, носкольку вы бы стро запутались бы). То же самое определение < ! D O C TY P E h t m l >

.

_____ d o c ty p e , что и раньше!

~ Chtml xmlns="http://www.w3.org/1999/xhtml">

Это XML, нам нужно ^ _ у пр о с т р а н ст ^о имен!

<head> < title > Y o u C m e ta

Все элементы должны быть правильными; / о б р а т и т е здесь внимание на идущие о конце сиМ ош исП0ЛЬЗуеАЛЬ1е для зак ры -

R ock!< /title >

c h a r s e t = " U T F - 8 '-

/>

тия данного п уст ого элемент а.

</head> <body>

<p>I'm kinda liking this XHTML!</p> <svg xmlns="h t t p ://www.w3.org/2000/svg"> <rect stroke="black" fill="blue" x="45px" y="45px" width="200px" height="lOOpx" stroke-width="2 " /> </svg> </bod >

° У </html>

^

4.

можем вложить XML прямо в страницу! И эт о очень здорово.

Мы используем SVCi для рисования прямо угольника на нашей странице. Изучите т е м у N~S (на следую щей ст ранице)> чтобы у ЗИа т ь больше о SVQ.

А тенерь давайте взглянем на ряд вещ ей, которы е вам нотребуется нринимать во внимание в случае с вашими XHTM L-страницами: Закры т ие всех ваших э л е м е н ­ т о в , кавычки вокруг значений ■ Ваша страница долж на нредставлять со б ой нравильный XML. а т р и б у т о в , допуст им ое вл о­ жение элемент ов и т. п. ■ Ваша страница долж на загружаться с иснользованием тина MIME application/xhtml+xml, для чего вам нотребуется удостовериться в том, что ваш сервер обеснечивает данны й тин (нроверив это са­ м остоятельно либо связавшись с адм инистратором вашего сервера). ■

О беснечьте и включите пространство имен XHTM L в свой элем ент <html> (что мы уже сделали в коде чуть выше).

Как мы уже отмечали ранее, относительно XML существует масса дополнительны х вещ ей, о которы х м ож но узнать, а также м нож ество вещ ей, с которы ми следует быть осторож ны м и. И, как и всегда в слу­ чае с XML, да нребудет с вами Сила...

570

приложение


оставшиеся темы

№ 5. SVG Scalable Vector Graphics («Масштабируемая векторная графика» ), или SVG, иредставляет со бой еще один сн особ — номимо canvas — включения графики нативно в ваши веб-страницы. SVG существует уже дол­ гое время (с 1999 года или около того) и в настоящ ий м омент ноддерж ивается во всех текущих версиях основны х браузеров, включая Internet Explorer 9 и выше. В отличие от canvas, которы й, как вы знаете, иредставляет со бой элемент, нозволяю щ ий рисовать никселы на н оверхн ости для растрового рисования с номощью JavaScript, SVG-графика определяется использованием XML. XML, вы говорите? Да, XML! Вы будете создавать элементы , которы е нредставляют графику, а затем объединять эти элементы друг с другом комплексными путями для создания гра­ ф ических сцен. Давайте взглянем на очень н р остой SVG-нример: Мы используем HTMLS в XHTM Lстиле п о т о м у , что применяем SVQ, что основывается на XML.

<!DOCTYPE html> <html xmlns="h t t p :/ / w w w . w 3 .org/1999/xhtml"> <head> <title>SVG</title> Мы используем элем ен т <meta charset="utf-8" /> <svg> прямо в нашей </head> HTML -разм е т к е ! ^ <body> Наш SVG - п р и м е р прост: он сооер <div id="svg"> v^ m w кот 0рый pacno <svg xmlns=”http: //www.w3.org/2000/svg"> у ______ ~ K00pduHamaM X=50, y=SO > У ложен по <circle id="circle" и обладает радиусом 2-0 пикселов

S

c x = " 5 0 " c y = "50 "

r= "2

s tro k e = " # 3 7 3 7 3 7

" s tro />

fill= " # 7 d 7 d 7 d "

</svg> </div> </body> </html>

0" k e -w id th = " 2

" ^ ...снабжен линией обводки шириной 2 пик села, имеющей т ем н о -с е р ы й цвет...

...и заливкой с исп оль­ зованием серого цвета со средним значением.

SVG онределяет ряд базовых фигур, таких как круги, нрямоугольники, многоу­ гольники, линии и т. д. Если вам нотребуется нарисовать более сложные фигуры, то вы также см ож ете онределить контуры с номощ ью SVG — естественно, в этот м омент вещи начнут становиться более сложными (как вы уже могли убедиться в случае с контурами в canvas). Однако существуют графические редакторы , ко­ торы е нозволят вам нарисовать сцену или экспортировать ее как SVG, избавляя вас от головной боли, которую вам доставила бы н еобходим ость самостоятель­ но разбираться со всеми этими контурами! Вы см ож ете масштабировать свою графику, увеличивая или уменьшая ее но своему усм отрению , и она нри этом не подвергнется никселизации, которая и м еет м есто нри масштабировании и зо ­ браж ений в ф ормате jp e g или png. Это облегчает новторн ое использование гра­ фики в различны х ситуациях. А носкольку SVG определяется с использованием текста, в случае с SVG-файлами м ож но осуществлять ноиск, индексировать их, нрименять к ним сценарии, а также сжимать их. И сследуйте данпую технологию но др о б н ее, если она вас заинтересовала.

Вы можете извлечь данный элем ен т circle, как и любой другой элем ен т из объектной модели докум ент а Р О М , и сделат ь с ним т о, что вам необ­ ходимо... н а п р и м е р , добавить о б р а б о т ­ чик событий click и изменять зн аче­ ние а т р и б у т а fill элем ен т а circle на 11r e d 11, когда п о л ь ­ зоват ель щелкнет на данном э л е м е н ­ те мышью. дальше ►

571


автономные веб-приложения и api-интерфейс web sockets

№ 6. Автономные 6еб-прилоЖенця Е с л и у вас им еется см артф он или нланш етный комнью тер, то вы, вероятно, выхо­ дите в И нтернет, находясь в пути, и благодаря Wi-FI и сетям сотовой связи ночти все время подключены к В сем ирной наутине. А как насчет того врем ени, когда вы не подключены к ней? Разве не будет здор ов о, если вы см ож ете нродолжать иснользовать все эти веб-нрилож ения HTM L5, которы е создаете для себя?

Ч то ж, тенерь у вас есть такая возмож ность. Автономны е веб-нрилож ения ноддер- ^ ж иваются всеми настольными и мобильными браузерами (с одним исключением: ^ благодаря т а Internet Explorer). кой вещ и, как Как ж е сделать свои веб-нрилож ения достунными в автоном ном режиме? Нужно авт о но мные создать файл манифеста кэша, которы й будет содержать снисок всех файлов, необвеб-приложения, ходимы х вашему нрилож ению для работы, и браузер загрузит все эти файлы и неу вас ест ь реключится на локальные файлы, когда ваше устройство н ерей дет в автономны й возможность реж им. Ч тобы сообщ ить своей веб-странице о том, что у н ее имеется файл манипользоваться ф еста, пужно н росто добавить его ф айловое имя в тег <html>, как ноказано далее: своими льобиМЫМи веб прилож ениям и, когда вы не п о д КЛМЧены к И н т ернету'.

Chtml manif est="notetos elf .manifest " >

Вот что содерж и т файл notetoself .manifest: САСНЕ

M A N IF E S T

САСНЕ:

4 ------^

notetoself.html К notetoself.css notetoself .js

)

~ С э т о го должен начинаться каждый ф а й л м а н и ф е с т а кэша.

3 секции CACHE нужно ук а за т ь все ф айлы , которые вы х о т и т е кэшировать: файлы с HTML- р а зм е т к о й , с CSS и J a v a S c r ip t-кодом , файлы изображений и т. п.

Данны й файл «говорит»: нри заходе на веб-страницу, указывающую на данны й файл, следует загрузить все файлы, указанные в секции CACHE этого файла. Вы также м ож ете добавить две дополнительны е секции в данны й файл — f a l l b a c k и n e t w o r k . f a l l b a c k онределяет то, какой файл будет иснользоваться, если вы ноны таетесь нолучить достун к файлу, которы й не был кэш ирован, a NETWORK онределяет файлы, которы е никогда не должны кэшироваться (нанример, в случае с ресурсами, отслеживающ ими уровень посещ аем ости). А тенерь, нреж де чем реш ите ноиграть со всем этим, вам н еобходи м о узнать о двух вещах: во-нервых, вам будет пужно убедиться в том, что ваш веб-сервер обеснечивает корректны й тин MIME в случае с файлами м аниф еста кэша (точно так ж е, как нам это было нужно сделать, когда речь шла о видеоф ай­ лах в главе 8 ). Н анример, если вы иснользуете сервер A pache, то добавьте нриведенпую далее строку в файл . htaccess на верхнем уровне вашего веб-каталога: AddType text/cache-manifest

.manifest

В тор ое, что вам будет пужно знать, заключается в том, что тестирование автономны х веб-нрилож ений осущ ествляется мудреным снособом ! Мы рекомендуем вам изучить соответствую щ ие снравочны е мате­ риалы на эту тему, а также спецификацию автономны х веб-нрилож ений HTML5. Как только у вас заработает базовое кэш ирование, вы см ож ете иснользовать JavaScript для нолучения уведомлений о связанных с кэшем собы тиях, которы е инициирую тся, нанрим ер, когда файл м аниф е­ ста кэша подвергается обновлению , а также о состоянии кэша. Для нолучения уведом лений о собы тиях н еобходим о добавить обработчики собы тий в объект window. applicationCache, как ноказано далее: window. applicationCache.addEventListener("error", errorHandler,

572

приложение

false);

Реализуйт е errorH andler для получений уведолллений, если в случае с кэш ем произойдет ошибка.


оставшиеся темы

№ 7. A PI-интерфейс Web Sockets В э т о й книге мы рассм отрели два сн особа коммуникации: XMLHttpRe quest и JSONP. В обои х случаях мы иснользовали модель « за н р о с/о тв ет» на основе HTTP. То есть мы нрименяли браузер для соверш ения занроса и сходн ой веб-страницы, CSS и JavaScript, и каждый раз, когда нам требовалось что-то другое, мы соверш али новый занрос с иснользованием XMLHttpRe quest или JSONP. Мы даже соверш али занросы, когда для нас не было никаких новых данных, что иногда случалось в нрим ере с Mighty Gumball. Web Sockets — это новый API-интерф ейс, которы й нозволяет ноддерживать откры тое нодклю чение к веб-службе, чтобы каждый раз, когда становятся достунными новы е данны е, эта служба могла нрисылать их вам (и ваш код мог нолучать соответствую щ ие уведомления). Считайте все это откры той тел еф он н ой линий между вами и службой. Вот вы сокоуровневы й об зо р того, как следует иснользовать данны й API-интерфейс: сначала для созда­ ния веб-сокета вам нотребуется нрименить конструктор WebSocket: о б р а т и т е внимание: в с л у чае с данным URL-адресом используется прот окол WS, va r

socket =

new W e b S o cke t ( "ws

:/ / y

o u r d o m a in /y o u r s e r v ic e "

"

); a не п р о т о к о л HTTP.

И п о м н ит е, что вам либо к о м у - т о д р у ­ го м у придет ся написат ь серверный код, чтобы у вас было с чем «общ ат ься».

Вы см ож ете нолучить уведом ление, как только сокет будет открыт носредством собы тия open, для кото­ рого м ож но назначить обработчик: Здесь мы п р едусм о т рел и обработчик, который ст а н е т вы зываться, когда сокет будет полност ью s o c k e t . o n o p e n = f u n c t i o n () { п о т к р ы т и гот ов к коммуникации. a le r t( " Y o u r

socket

is

now

open

w ith

th e

w eb

s e r v ic e " ) ;

} Вы см ож ете отнравить веб-службе сообщ ени е с номощ ью м етода postMessage: Здесь мы от правляем серверу с т р о к у j s o c k e t.p o s tM e s s a g e ( - - p la y e r m o v e d

r ig h t- - ) ;

двоичные данные н а с т у п а ю т , но пока еще не поддерживаются широко.

А для нолучения сообщ ени й необходим о зарегистрировать другой обработчик, как показано далее: s o c k e t,

onmessage = function ( event )

alert ("From socket:

*'

{

" + event.data);

З ар еги с т р и р ова в обработчик, мы сможем получат ь все сообщения, содержа­ щиеся в свойстве event.data.

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

573


дополнительно о api-интерфейсе canvas

№ 8. Дополнительно об A PI-интерфейсе Canvas Мы уже нровели весело время с canvas в главе 7, создавая наш стартан TweetShirt. Однако есть еще много интересны х вещ ей, связанных с canvas, которы е м ож но сделать, и мы хотим рассказать здесь о некоторы х и з них. Мы очень кратко уноминали, что вы см ож ете сохранять и восстанавливать context элемента canvas с номощ ью, соответственно, методов save и restore. Зачем вам м ож ет потребоваться сделать это? Д о ­ пустим, вы задали значения для ряда свойств context, нанрим ер fillStyle, strokeStyle, lineWidth и т. д. А затем у вас возникла н еобходим ость врем енно изменить их значения для того, чтобы кое-что сделать, нанример нарисовать фигуру, однако вы нри этом не хоти те заниматься восстановлением всех эти х значений, чтобы верпуться к тем значениям свойств, что были у вас нреж де. Для этого вы м ож ете воспользоваться м етодами save и restore: . м м задаем значения для группы свойств в c o n tex t и осущ ест вляем рисование.

context.fillStyle = "lightblue";

Теперь мы сохраняем context. Значения всех эплих свойств б у ду т надежно сохранены. Mbi сможем изм ени т ь их...

context.s a v e () context.fillStyle = "rgba(50, context.filiRect(0,

50, 50,

.5)";

0 , 100 , 100 );

...а з а т е м в ер н ут ь всех их об ра т н о, сделав их т а к и м и , какими они были прежде, когда мы сохраняли эт и значения, для чего прост о вызовем м е т о д restore! 3 э т о т м о м е н т все наши свойства п р и ­ о б р е т у т значения, кот орые они имели перед сохранением. Д анны е методы особен н о нридутся кстати, когда вам нотребуется транслировать или новерпуть canvas для того, чтобы что-то нарисовать, а затем верпуть его в нолож ен и е но умолчанию. Что делаю т методы translate и rotate? Давайте носмотрим... context.resto r e () ;

Loo*Wh«ItVe* I4

/^ЧУ нас в странице имеется canvas размером 400x400 пикселов. Если мы нарисуем прямоугольник с коорди­ натами х=0, у=0, то он появится в верхнем левом углу, как мы и ожидали бы. context.filiRect(0, 0, 100,

100);

/JVТеперь мы берем canvas и перемещаем его на 200 пикселов вправо и на 200 пикселов вниз. Если мы нарисуем еще один прямоуголь­ ник с координатами х=0, у=0, то он появится на 200 пикселов правее и на 200 пикселов ниже первого нашего прямоугольника. Мы только что транслировали canvas. context.translate(200, 200); context.filiRect(0, 0, 100,

574

приложение

100);


оставшиеся темы

/0\ А что, если ми повернем canvas до того, как нарисуем прямоугольник? canvas вра­ щается вокруг своего верхнего левого угла (по умолчанию), и поскольку мы только что переместили верхний левый угол в позицию 2 00,2 00, там и будет вращаться canvas.

LwtLWucI l>f-

ш

context.translate(200, 200); context.rotate(degreesToRadians(36)); context.fillRect(0, 0, 100,

т

36

100);

Когда вы т р а н с л и р уе т е иди п о ­ ворачиваете canvas., он п е р е м е ­ щается по координатной сет ке, которая позиционируется о т ­ носительно верхнего левого угла окна браузера. Если вы прим ен ит е CSS для позиционирования canvas, то данные значения б у дут п р ин и­ м а т ь ся в расчет. Попробуйте!

А тенерь давайте соединим все это! Вы м ож ете иснользовать методы t r a n s l a t e и r o t a t e сообщ а для создания интересны х эф ф ектов. var canvas = document.getElementByld("canvas" var context = canvas.getContext("2d"); var degrees = 36;

натной сетке после т ого , как мы context.s a v e (); context.translate (200, 200) context.fillStyle

for

;

Mw т р а н сли р уем наш canvas, з д dag npu э т о М з н а ч е н и я 2-00, ZOO.

" rgba(50, 50, 50,

(var i = 0; i <360/degrees; i++)

context.fillRect(0, 0, 100,

.5

{ ^

100);

^

А вот итогооыи р е з у л ь т а т . Интересно выглядит!

Мы р и су е м Ю п р я м о уго л ь -

НиК° в пУмеМ

поворот а canvas на 36° перед т ем ,

ри соват ь пря м оугольник о n o Теперь наш canvas возвра- зищли О, О, при щ ает ся в свое исходное каж дом вы полне-

context.rotate(degreesToRadians(degrees));

} context.restore ();

полож ение/ Иии цикла. К омбинируйте эти нросты е трансф орм ации с другими даж е ещ е более мощными (и сложными!) методиками вроде комнозиции и п реобразова­ ний, и возм ож ности но созданию графических и зображ ен и й с использо­ ванием canvas стапут безграничными. дальше ►

575


api-интерфейс selectors и кое-что еще

№ 9. A P I-интерфейс Selectors Вы уже знаете как нронзводнть выборку элементов и з объектной модели документа DOM с номощью document.getElementByld; мы иснользовали данны й м етод как сн особ сделать так, чтобы HTML и JavaScript работал и сообщ а. Вы также увидели, как сл едует иснользовать document.getElementsByTagName (данный м етод возвращ ает массив всех элементов, соответствую щ их заданному тегу) и даж е метод getElementsByClassName (возвращающий, как вы уже догадались, все элементы в он ределенн ом клас­ се). Благодаря HTM L5 сейчас у нас им еется новы й сн особ выборки элементов из объектной модели до­ кумента DOM , основанны й на j Query. Тенерь вы м ож ете задействовать те ж е селекторы , которы е при­ м еняете в CSS с целью выборки элементов для стилизации в своем JavaScript, для выборки элементов из объектной модели документа DOM с использованием м етода document.querySelector. Допустим, у нас им еется приведенная далее нростая HTML-разметка: <!doctype html> <html lang="en"> <head> Пристально взгляните на с т р у к т у р у < t it l e > Q u e r y s e l e c t o r s < / t i t l e > данной HTML-разм ет ки. Мы собираемся <meta c h a r s e t = " u t f - 8 "> __ использовать A P I -инт ерф ейс Selectors < /h e a d > gbl$0p KU элементов из страницы. <body> С— <div class="content"> <р id="avatar" class="level5">Gorilla</p> У нас &сть элем ен т <div> С классом <р id="color">Purple</p> ^ " c o n te n t” и два элем ен т а <р>, каждый </ div> из которых обладает собственным </body> и ден т иф ик а т ор ом , при э т о м у одно </html> го из ниу имеет ся класс "le v e lsп.

Тенерь давайте воспользуемся API-интерф ейсом Selectors для выборки элемента <р> с id в виде "avatar": document.queryS elect or ("# avatar" ) ; 4*—

П о сути, это то ж е самое, что и document . getElementld ("avatar"). Тенерь давайте иснользуем класс элемента для его выборки: ^ ^ U , Сейчас мы используем имя т ега document.querySelector("p.Ievel5"); u класс для его выборки. Мы также мож ем нрои звести выборку элемента <р>, которы й является дочерни м но отнош ению к элементу < d iv > , следующим образом: мы ислользуем селектор дочерних d o c u m e n t.q u e ry S e le c to r (" d iv > p " )

;

эл е м ен т о 0 child для выборки элем ен т а <р>,

или даж е так: л /" document.querySelector (". content>p") ;

^

J

v

* '

который является дочерним по отношению к э л е м е н т у <div>. По умолчанию он выбил ,,лл р а е т первый элемент.

А если нам но надобятся все элементы <р> в <div>, то мы см ожем воспользоваться другим м етодом в APIи н тер ф ей се Selectors с им енем queryS elect orAll: , п _ Теперь мы извлекаем все дочерние document.queryS elect о г All ("div>p" ) ; элемент ы <р> элем ен т а <dtv>! queryS el ectorAll возвращ ает массив элементов точно так ж е, как и м етод getElementsByTagName. Вот и всё! В API-интерф ейсе Selectors им еется только два метода. Данны й API-интерф ейс является н е­ большим, однако он нривносит новую мощпую функциональность для выборки элементов.

576

приложение


оставшиеся темы

№ 10. Однако есть даЖе еще кое-что! Мы действительно хотели ограничиться десятью темами, которы е не рассм о­ трели в дан н ой книге, но, п охож е, что нам есть ещ е куда двигаться, и вместо того чтобы стоять между вами и чтением алфавитного указателя, мы поведаем вам о нескольких дополнительны х темах на одн ой странице. Вот они (им ейте в виду, что некоторы е из эти х обл астей все ещ е развиваются, одпако мы поним а­ ли, что вам потребуется зпать о них па будущее):

A P I-интерфейс Indexed Database и Web SQ L Е с л и в ы ищ ете нечто бол ее индустриальное, чем API-интерф ейс Web Storage, для сохрапени я свои х данны х локальпо, следите за сф ер о й баз данны х, функци­ онирую щ их в И п тер н ете. В настоящ ее время там присутствуют два конкуриру­ ю щ их реш ения: Web SQL и In d exed D B . По ирони и судьбы, технология Web SQL обр ел а бол ее широкую поддерж ку по сравнению с In d exed D B , одпако недавпо комитет стандартов выступил против нее (то есть он не реком ендует перепимать ее как стандарт, и вам, вероятно, не следует основывать на п ей свой следу­ ющ ий стартап). С другой стороны , технология In d exed D B пока не реализовала ш ироко, однако поддерж ивается со стороны G oogle и Firefox. In d exed D B обеспечи вает бы стры й доступ к обш и р н ой коллекции индексированны х данпы х, в том время как Web SQL является компактным SQL-движком, работающ им в браузере. Следите за тем, куда движутся эти технологии; они бы стро меняются!

A P I-интерфейс Drag and Drop Веб-разработчики уже долгое время обеспечи ваю т возм ож пость перетаскивать и помещ ать элем енты с помощью мыши, используя для этого jQ uery, а теперь данная функциональность пативно поддерж ивается в HTM L5. И споль­ зуя API-ин терф ейс Drag and Drop, вы м ож ете определить что-либо для перетаскивания, а также м есто, куда п ер е­ таскиваемый элем ент м ож но будет пом естить, и JavaScript-обработчики, которы е будут уведомляться о различны х собы тиях, инициируем ы х при перетаскивании и пом ещ ении элем ентов. Ч тобы сделать элем ент поддерж иваю ­ щим возм ож ность перетаскивания с помощ ью мыши, нужно лишь задать для атрибута draggable значение true. Перетаскивать мож но почти любы е элементы: и зобр аж епия, списки, параграфы и т. д. Вы м ож ете конф игуриро­ вать пов едеп и е, связанное с перетаскиванием , путем прослуш ивания собы тий, наприм ер, dragstart и dragend, и даже измепять стиль элем ента, чтобы во время перетаскивапия он п риобретал такой впеш ний вид, которы й вы пож елаете. Вы м ож ете отправлять небольш ое количество данпы х наряду с перетаскиваемы м элем ептом , исполь­ зуя свойство dataTransf ег; обращ аться к нему м ож но посредством объекта event, чтобы узнать, наприм ер, п ер е­ мещается ли определ ен н ы й элем ент или ж е копируется. Как вы м ож ете видеть, благодаря такому API-интерф ейсу HTM L5, как Drag and D rop, п ер ед вами откры вается масса прекрасны х возм ож н остей по обесп еч ен и ю повы х взаи­ м одействий с и н тер ф ей сом пользователя.

A P I-интерфейс Cross-document Messaging В главе б мы использовали ш аблон передачи данпы х, известны й как JSONP, чтобы избеж ать м еж дом енны х коммуникационпых проблем , возникаю щ их в случае с XMLHttpReguest. Существует ещ е одип сп о со б коммуника­ ции между документами — даже документами, находящ имися в разны х дом енах. API-ин терф ейс C ross-docum ent M essaging определяет, что вы см ож ете отправить сообщ еп и е документу, которы й загрузили, используя элем ент ifram e. Данны й документ даже м ож ет располагаться в другом дом ене! Теперь вам не потребуется загружать про­ сто любойдокумепт в свой iframe; вам будет нужно удостовериться в том, что он исходит из дом ена, котором у вы довер я ете, и настроить его па прием ваших сообщ ен и й . В результате вы получаете сп о со б отправлять сообщ ения туда-сюда между двумя HTM L-до куме птам и.

U мы могли бы продолЖать и дальше... Захватывающая вещь относительно HTM L5 заключается в том, что больш ое количество новы х фупкциональпы х возм ож н остей разрабаты вается довольно быстрыми темпами; на эт о й страпице мы могли бы привести ещ е боль­ ше материала, однако для этого просто не осталось места. П оэтом у заходите к нам на сайт в И п тер н ете по адресу h t t p : //w ick ed ly sm a rt.co m , чтобы узнавать о б о всех новейш их разработках в области HTML5!

дальше ►

577


htm 15-руководство по новым конструкциям

Не верится, что книга почти закончилась. Прежде чем мы с вами расстанемся, у нас есть для вас прощальный подарок от города Веб­ вилль; это руководство по НТМЬ5-элементам (атакже по новинкам в CSS3), которое мы вам обещали. Замечательный город этот Вебвиль, не правда ли?!

578

приложение


оставшиеся темы

HTMLS-pykoBogcmBo по новым конструкциям Здесь, в Вебвилле, мы недавно внесли ряд дон олнен и й в наши «строительные» коды и нодготовили удобное руководство но всем новым конструкциям, которы е могут нредставлять для вас интерес. Так, в частности, мы добавили грунпу новых семантических элементов, которы е обеснечат для вас даж е ещ е более ш ирокие возм ож ности но созданию страниц. Однако наше руководство не является и счер­ пывающим; верн ее, наша цель здесь заключалась в том, чтобы дать вам, онытному разработчику, достаточно материала для того, чтобы вы были хорош о знакомы с новыми НТМ Ьб-элементами и CSSS-свойствами и смогли иснользовать их в вебнрилож ениях, создание которы х изучаете в данной книге, когда будете к этому готовы. П оэтом у если вам требуется краткое уч ебн ое н особи е но семантическим нововведениям в HTM L5, то м ож ете взять один экземнляр — они БЕСПЛАТНЫ (но лишь в теч ен и е ограниченного врем ени).

дальше ►

579


семантические элементы html5

Вебвилльское руководство по сем антическим элементам HTML5 Здесь, в Вебвилле, мы внесли ряд свежих изменений в наш «строительный» код и подготовили

<div> вместо <header>, <nav>, <f ooter> и <article> для блоговых статей,

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

то у нас есть для вас новые строительные блоки. Итак, давайте взглянем на них. <section>

<section> — это «общий документ». Вы могли бы использовать <section>

для разметки, например, «Руководства по HTML». Или чтобы заключить в него HTML. <section> не является общим контейнером — это работа <div>. И помните, что нужно использовать <div>, если вы просто группируете эле­ менты в целях стилизации.

<article>

<articie> — это отдельный блок содержимого, которым вы можете захотеть

поделиться с другой страницей или веб-сайтом (или даже со своим псом). Идеально подходит для блог-постов и новых статей.

<header>

<header> предназначен для верхуш ек элементов вроде <section> И <article>. <header> также может использоваться в верхней части <body> для создания основного заголовка страницы .

<footer>

<footer> предназначен для нижней части элементов. Таких элементов, как <section>, <article> И <div>. Вы МОГЛИ ПОДуМЭТЬ, ЧТО ДОПуСКЭвТСЯ ТОЛЬКО ОДИН <footer> в странице; на самом деле вы можете использовать его всякий раз, когда вам будет необходимо разместить содержим ое нижнего колонтитула в <section> вашей страницы (например, б иограф ические данны е или ссы лки на некую статью ). <hgroup>

Это мудреный элемент. В отличие от <header>, который может содержать любые элементы, связанные с заголовком, <h group> специально предна­ значен ДЛЯ группирования заголовков (<hl>...<h6>) внутри <header>. Хорошо подходит для структур.

580

приложение


оставшиеся темы

Вебвилльское руководство по сем антическим элементам HTML5 <nav> <nav> — это навигация, и данный элемент, конечно же, предназначен для ссы-

лок. Но не для любых ссылок: используйте <nav>, когда у вас имеется группа ссылок, например навигация для вашего сайта или блога. Не используйте его для одиночных ссылок в параграфах.

< a s id e >

<aside> удобен для размещения всевозможных вещей, которые представляют

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

< tim e >

Ну наконец-то! Здесь речь идет о дате/времени. Вы можете использовать <time> для определения даты/времени. Не нужно спешить; найдите время и сделайте все правильно — изучите допустимые форматы для <time>.

< p ro g re s s >

Почти закончили? Да, мы с успехом продвигаемся вперед по этим HTML5элементам... <progress> представляет то, насколько далеко вы продвинулись в завершении выполнения задачи. Используйте немного CSS и JavaScript для создания красивых эффектов.

< a b b r>

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

< m a rk >

Используйте <mark> для пометки слов, например, с целью выделения или редак­ тирования. Данный элемент хорошо подходит для использования в сочетании с результатами, выдаваемыми поисковыми движками.

дальше ►

581


css3-ceo0cmea

Добавление стиля в ваши новые конструкции с помощью CSS 3 Вебвилльское руководство по CSSS-свойствам Теперь, когда ваши новые строительные блоки заняли свое место, пора задуматься о дизайне интерьера. Вам ведь захочется, чтобы все ваши новые конструкции выглядели красиво, не так ли?

Новые свойства В CSS3 имеется порядочное количество новых свойств, многие из которых делают то, что соз­ датели веб-страниц претворяли в жизнь довольно долго посредством различных витиеватых манипуляций с HTML, изображениями и JavaScript. Примеры:

_________Д е л а е т э л е м е н т непрозрачным на SO%. opacity:

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

0. 5;

border-radius: брх; box-shadow:

5рх 5рх Ю р х

#373737;

Новые макеты

Тень длиной s пикселов, высотой s пиксе­ лов, размытием с радиусом г о пикселов, имеющая темно -серый цвет.

Появилась пара новых мощных способов создания макетов страниц с помощью CSS, которые выходят за рамки обычного позиционирования и намного более просты в применении. Примеры: display:

table;

display:

table-cell;

display:

flexbox;

flex-order:

I Эт о даст вам табличный м а к ет без HTML-таблиц. Благодаря flexbox вы получает е больший конт роль над т е м , как б р аузер будет подходить к р а з м е щ е ­ нию блоков, наприм ер элем ен т ов d iv на странице

1; <-

Новые анимации

Благодаря анимациям у вас есть возможность анимировать переход между значениями свойств. Например, вы можете сделать так, чтобы что-нибудь исчезало из виду путем перехода из не­ прозрачного состоянии в полупрозрачное:

Свойство transition определяет свойство для перехода в кон­ transition: opacity 0.5s ease-in-out; кретное состояние и выхода из Задавая для opacity значение О, opacity: 0; п него (в данном случае речь идет например, о случае наступления о непрозрачности), время, ко­ события, инициируемого при на­ ведении курсора мыши на элемент, торое будет занимать переход, мы можем создать анимацию его и функцию замедления, чтобы исчезновения/появления снова. он был постепенным.

Новые селекторы

Появилась целая масса новых селекторов, включая nth-child, который позволяет на­ целиваться на специфические дочерние элементы, заключенные в том или ином элементе. Наконец-то у вас появилась возможность задавать цвет фона чередующихся строк в списке, не прилагая при этом сумасшедших усилий. ^ п < ~

v

v

3

ul l i : nth-child (2n)

582

приложение

м

J

{ color:

gray;

}

Это означает: выдрать? каждый вт орой элем ен т списка и з а ­ дат ь серый цвет фона.


информация о книге «Изучаем программирование на HTML5»

+Выходные сведения

Дизайн всех внутренних макетов был выполнен Эриком 1рименом и Элизабет Робсон. Кэти Сиерра и Берт Бэйтс придумали стиль оформления книг из серии «Изучаем...». При производстве данной книги были использованы программы Adobe InDesign CS и Adobe Photoshop CS. К числу мест, где осуществлялось написание данной книги, относятся следующие: Бэйнбридж Айленд, штат Вашингтон; Портленд, штат Орегон; Лас-Вегас, штат Не­ вада; Порт-оф-Несс, Шотландия; Сисайд, штат Флорида; Лексингтон, штат Кентукки; Туксон, штат Аризона и Анахейм, штат Калифорния. На протяжении долгих дней, пока мы писали эту книгу, нам придавал силы кофеин в чае «Honest Tea», «GT’s Kombucha», а также музыка таких исполнителей, как Sia, Sigur Ros, Том Вейте, OMD, Филип Глас, Muse, Епо, Кришна Дас, Майк Олдфилд, Одра Мэй, Devo, Стив Роач, Beyman Brothers, Pogo и всех людей на turntable.fm, а также музыка огром­ ной массы исполнителей 1980-х годов, которые вас, возможно, не заинтересуют.

дальше ►

583


/ А вы знаете о нашем веб-сайте? \ Там приводятся ответы на некоторые вопросы из этой книги, а также руководства, из которых можно научиться дополнительным вещам, и ежедневные обновления вблоге от авторов! ]

^

b i н е проЩ а^ Заходите на

с Вами!


Э. Фримен, Э. Робсон Изучаем программирование на HTML5 Серия «Head First O’Reilly» Перевел с английского В. Черник

Заведующий редакцией Руководитель проекта Ведущий редактор Литературный редактор Художник Верстка

К. Галицкая Д. Виницкий М. Моисеева М. Моисеева Л. Адуевская Е. Леля

ООО «Мир книг», 198206, Санкт-Петербург, Петергофское шоссе, 73, лит. А29. Налоговая льгота — общероссийский классификатор продукции ОК 005-93, том 2; 95 3005 — литература учебная. Подписано в печать 10.09.12. Формат 84x108/16. Уел. п. л. 67,200. Тираж 2000. Заказ 0000. Отпечатано с готовых диапозитивов в типографии «Вятка». 610033, Киров, ул. Московская, 122.


Изучаем С#. 2-е изд. Head First С#, 2nd Ed. Э. Стиллмен, Дж. Грин

Эндрю Стиллмен Дженнифер Грин

Изучаем 2-е издание Воэ-мй секрета

4■бС«««ломим *р4 Г«рОН«М J

мучвеь эффектом!о

коопьимп

ISBN:978-5-459-00422-9 Объем: 696 с. Дата выхода: сентябрь 2011

В отличие от большинства книг по программированию, построенных на основе скучного изложения спецификаций и примеров, сэтой книгой читатель сможет сразу приступить к написанию собственного кода на языке программирования C# с самого начала. Вы освоите минимальный набор инструментов, а далее примете участие в забавных и интересных программных проектах: от разработки карточной игры до создания серьезного бизнес-приложения. Второе издание книги включает последние версии C# .NET 4.0 и Visual Studio 2010 и будет интересно всем изучающим язык программирования С#.Особенностью данного издания является уникальный способ подачи материала, выделяющий серию «Head First» издательства O'Reilly в ряду множества скучных книг, посвященных программированию.


Изучаем HTML, XHTML и CSS Head First HTML with CSS & XHTML Э. Фримен, Э. Фримен

Устали от чтения таких к н и г по HTML, ко то р ы е понятны то л ько специалистам

Изучаем ТХФТУ/ГТ x h t m l

U l l v l J j и css

ISBN: 978-5-49807-113-8 О бъ ем : 656 с. Дата вы хо да : февраль 2010

в этой области? Тогда самое время взять в р уки наше издание. Хотите изучить HTML так, чтобы ум еть создавать веб­ страницы , о ко то р ы х вы всегда мечтали? Так, чтобы более эф ф ективно общаться с друзьям и, семьей и п р ивередл ивы м и клиентами? Хотите действительно обслуж ивать и улучш ать HTML-страницы по п рош ествии времени, чтобы они работали во всех браузерах и м обильны х устройствах? Тогда эта книга для вас. П рочитав ее, вы узнаете все секреты создания веб-страниц. Благодаря ей вам больш е не придется думать, ка ки е цвета нуж н о использовать, чтобы они сочетались м еж ду собой, к а к пр а вильно пр им е нять шрифты, чтобы они не «плавали» по э кр а н у и верно отображ ались в различны х браузерах. Вы узнаете, к а к работаю т проф ессионалы, чтобы получить визуально привлекательны й дизайн, и ка к м аксим ально эф ф ективно использовать HTML, CSS и XHTML, чтобы создавать такие веб-страницы , м им о ко то р ы х не п р о йд е т ни один пользователь.


Изучаем JavaScript Head First JavaScript М. Моррисон

Майкл Моррисон

ISBN: 978-5-459-00322-2 О бъ ем : 592 с. Дата вы хо д а : о ктя б р ь 2011

Вы готовы сделать ш аг вперед в своей п р а кти ке в е б -п р о гр а м м ир о в а н ия и перейти от верстки в HTML и CSS к созданию по лно ц е нн ы х д и н а м и ч е ски х страниц? Тогда приш л о время познаком и ться с самым «горячим» язы ко м пр о гр а м м и р о в а н и я — JavaScript! С пом ощ ью этой к н и ги вы узнаете все о я зы ке JavaScript: от перем енны х до циклов. Вы поймете, по че м у разны е браузеры п о -р а зн о м у р е а ги р ую т на ко д и ка к написать универсальны й код, поддерж иваем ы й всеми браузерами. Вам станет ясно, по че м у с ко д о м JavaScript ни когда не придется бе спо ко и ться о пе р е гр уж е н н о сти стр а н иц и ош ибках передачи данны х. Не пугайтесь, даж е если ранее вы не написали ни одн о й с тр о ч ки кода, — благодаря у н и ка л ьн о м у формату подачи материала эта кни га с л е гко стью проведет вас по всему пути обучения: от написания п р о стейш его ja v a -скр и птэ до создания слож ны х веб -проектов, ко то р ы е будут работать во всех соврем енны х браузерах. О собенностью д а н н о го издания является у ни ка л ьн ы й способ подачи материала, выделяю щ ий серию «Head First» издательства O'Reilly в ряду множ ества скучн ы х кн и г, посвящ енны х пр о гр а м м и р о в а н и ю .


Изучаем SQL Head First SQL Л.Бейхли

Л и н н Бейли

ISBN: 978-5-459-00421-2 О бъ ем : 592 с. Дата вы хо да : сентябрь 2011

В совр е м е нн о м м ире наивы сш ую ценность имеет инф орм ация, но не менее важ но уметь этой инф орм ацией управлять. Эта книга посвящ ена я зы ку за п р о со в SQL и уп р а вл е ни ю базами данных. М атериал излагается, начиная с описания базовы х за п р о со в и заканчивая слож ны м и м анипул яциям и с пом ощ ью о б ъ единений, п о д за п р о со в и тр а н за кц ий. Если вы пытаетесь разобраться в о р га н и за ц и и и упр а вле ни и базами данны х — эта кни га будет отличны м п р а кти ч е ски м пособием и предоставит вам все необходим ы е инструм енты . О собенностью да н н о го издания является уни ка л ьн ы й способ подачи материала, выделяю щ ий серию «Head First» издательства O'Reilly в ряду м ножества с кучн ы х кни г, посвящ енны х пр о гр а м м и р о в а н и ю .


Паттерны проектирования Head First Design Patterns Э. Фримен, Э. Фримен, К. Сьерра, Б. Бейтс

Эрик Фримен, Элизабет Фримен яри ^частик Кэчтн Сьерра и Берта Бейтса

ISBN: 978-5-459-00435-9 О бъ ем : 656 с. Дата вы хо д а : март 2011

В м ир е по сто янно кто-то сталкивается с таким и ж е проблемами п р о гр а м м и р о в а н и я , ко то р ы е во зн и ка ю т и у вас. М н о ги е р а зр а б о тчики реш аю т со верш енно ид ентичны е задачи и находят п о хо ж ие реш ения. Если вы не хо ти те изобретать велосипед, используйте готовы е шаблоны (паттерны ) п р о е кти р о в а н и я , работе с ко то р ы м и посвящ ена эта книга. Паттерны появились, потом у что м н о ги е р а зр а б о тчики искали пути повы ш ения ги б ко сти и степени п о в то р н о го использования своих п рограм м . Н айденны е реш ения воплощ ены в кр а тко й и л е гко пр и м е ни м о й на п р а кти ке форме. О собенностью д а н н о го издания является уни ка л ьн ы й способ подачи материала, вы деляю щ ий серию «Head First» издательства O'Reilly в ряду множ ества скучн ы х кн и г, посвящ енны х пр о гр а м м и р о в а н и ю . Книга будет интересна ш и р о ко м у к р у гу веб -разраб отчиков, от начинаю щ их до проф ессионалов, ж елаю щ их освоить работу с паттернами пр о е кти р о в а н и я .


Программируем для iPhone и iPad Head First iPhone and iPad Development, 2nd Ed. Д. Пилон, Т. Пилон

ISBN: 978-5-459-00375-8 О бъ ем : 592 с.

К н и га п р е д н а зн а ч е н а для п р о ф е с с и о н а л ь н ы х п р о гр а м м и с т о в , ж е л а ю щ и х с о зд а в а ть п р и л о ж е н и я для iP h o n e и iP od с п о м о щ ь ю A p p le SDK и я зы ка п р о гр а м м и р о в а н и я O b je c tiv e -C . В о тл и ч и е о т б о л ьш и н ств а к н и г по п р о гр а м м и р о в а н и ю , п о с т р о е н н ы х на о с н о в е с к у ч н о го и з л о ж е н и я с п е ц и ф и ка ц и й и п р и м е р о в , с этой к н и го й чита те л ь с м о ж е т п р и с т у п и т ь к н а п и с а н и ю с о б с т в е н н о го кода с с а м о го начала. Вы о с в о и т е м иним альны й набор инструм ентов и п р и м е те у ч а с ти е в за б а в н ы х и и н те р е с н ы х п р о гр а м м н ы х п р о е кта х : о т р а з р а б о т к и и гр д о с о зд а н и я с е р ь е з н ы х б и з н е с -п р и л о ж е н и й . Н е ста н д а р тн ы й с п о с о б п о д а ч и м атери ала о б л е гч а е т п о н и м а н и е и зн а ч и т е л ь н о у в е л и ч и в а е т с к о р о с т ь в о с п р и я ти я , заставляя вас д ум а ть го л о в о й . Не п у га й те с ь , д а ж е если ра н е е вы не н а п иса л и ни о д н о й с т р о ч к и кода — б л а го д а р я с в о е м у у н и к а л ь н о м у в и з у а л ь н о м у ф орм ату п о д а ч и м атериала эта кн и га с л е гк о с т ь ю п р о в е д е т вас по всем у пути с о зд а н и я к а ч е с т в е н н о го п р и л о ж е н и я для iP h o n e и iPad.


Управление разработкой ПО Head First Software Development Д. Пилон, Р. Майлз

Дэн Пилон, Расс Майлз

ISBN: 978-5-459-00522-6 О бъ ем : 464 с. Дата вы хо д а : м арт 2011

Д аж е опы тны е разр а б о тчики п р о гр а м м н о го обеспечения по сто янно сталкиваю тся с трудностям и при реализации п р о гр а м м н ы х проектов: наприм ер, из-за смены требований за ка зчика ПО или непоним ания ко не ч ны м и пользователями л о ги ки работы с но во й п р о гр а м м о й. Если вы не собираетесь пасовать перед этими и д р уги м и распр о стр а не н ны м и проблем ам и управления IT-пр о е кта м и , изучите с п ом ощ ью этой у н и ка л ьн о й кн и ги передовы е методы и п р а кти ки , наработанны е в области разработки п р о гр а м м н о го обеспечения. Здесь вы получите всю необходим ую инф орм ацию о ка ж д о м этапе ж и з н е н н о го цикла разраб отки п р о гр а м м н о го о беспечения: пе р е го в о р ы с за ка зчи ко м и ф ормализация кл и е нтски х требований, пла ни р о ва ние процесса разработки ПО и п одготовка те х н иче ско го задания, постановка задач и написание и н стр укц и й , тестирование ПО и устр а н е ние «багов». О собенностью этой к н и ги является уни ка л ьн ы й способ подачи материала, вы деляю щ ий серию «Head First» издательства O'R eilly в ряду множества скучн ы х книг, посвящ енны х п р о гр а м м и р о в а н и ю и разработке ПО.


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.