Итак, после того, как мы
успешно внедрили SVG-картинку в HTML-документ, следующим шагом будет подвесить на неё события. С этом, оказывается, тоже не всё так просто, но управиться можно.
В передовых браузерах получение доступа из HTML-документа к SVG-документу тривиально. По событию load нам оказывается доступен элемент object, на него тоже можно навесить событие load и в его обработчике мы замечательным образом получим искомое. Посредством jQuery это можно было бы сделать примерно так:
$(
function(){
$("object#SceletonObject").load(
function(){
var SVGDocument=$(this)[0].getSVGDocument();
…
}
);
}
);
Проблемы возникают в Internet Explorer. В нём мы можем после загрузки страницы получить элемент embed и у него даже уже доступен SVG-документ, но только - вот беда! - он совершенно пуст. Навесить на элемент embed событие load мне не удалось; похоже, оно вообще не
поддерживается (впрочем, те из перечисленных событий, что я пробовал, тоже не работают).
Кроме того, позже выяснилась ещё одна подлянка: содержимое таких элементов, как object и embed
загружается асинхронно, в отдельном потоке. Это означает, как я понимаю, что, с одной стороны, пока не закончен парсинг основной страницы, элемент ещё недоступен для навешивания на него обработчика события, а когда он закончен - событие загрузки элемента может уже сработать и тогда обработчик навешивать уже бесполезно. Кажется, именно последний случай я периодически наблюдал в экспериментах, не улавливая никакой закономерности в глюке.
Да и по
спецификации, кстати, событие load у элемента object отсутствует - оно есть в HTML только у элемента body. Так что то, что оно вообще где-то работает - это неправильно!
Выход найден следующий (не очень элегантный, но… будем ещё думать!): событие load пишем внутри SVG-кода у элемента svg, вызывая оттуда функцию HTML-документа. Как-нибудь так:
Ну, или, чтобы, уж, единообразно работало во всех браузерах:
Или даже просто (поскольку parent в окне верхнего уровня указывает на само это окно):
В функции InitSVG мы уже можем получить SVG-документ и из него - все его элементы. Лепота!
Только следует иметь в виду, что работать с SVG-элементами средствами jQuery не получится (может быть, есть какой-то обходной маневр, но мне его раскопать или изобрести пока не удалось и лично я посчитал, что овчинка выделки не стоит). Дело в том, что его функции ожидают получить от метода getElementsByTagName результат типа HTMLCollection, из коего можно отбирать элементы по индексу, как из обычного массива. А тут мы получим (везде, кроме Firefox) результат типа NodeList, из коего элемент можно будет выцепить только посредством особого метода item(индекс). Фреймворк на такое не рассчитывает и обламывается. Так что придётся работать непосредственно с DOM-методами, держа кроссбраузерность в уме. Сие напряжно, но возможно.
Два частных наблюдения по скриптованию SVG-документа. Во-первых, обнаружилось, что заданные в нём стили изменять скриптом не получается; всю динамику надо реализовывать через атрибуты (что, конечно, не очень правильно, если речь идёт об оформлении, к примере о цветовой заливке - fill). Во-вторых, если у SVG-элемента не стоит никакой заливки, то события mouseover и mouseout срабатывают только на рамке и вполне могут не успеть сработать вообще (к счастью, можно прописать атрибут fill один раз у элемента-предка и он пронаследуется). Да, ещё у меня остались частные проблемы взаимодействия SVG-картинки с элементами HTML-документа, но с ними я разберусь в свой черёд.
Способ скриптования проверен и работает в Firefox 3.5, Opera 9.0+, Safari 4.0, Chrome 3.0, IE 7+.
P. S. Обнаружилось, что этот способ не работает локально в Chrome 5.0 из-за каких-то его заморочек с безопасностью!