Может ли Prototype расширять элементы SVG?
Я пытаюсь разработать интерактивную SVG-карту и не могу заставить Prototype расширять встроенные элементы SVG. Вот мой пример кода (удаленные данные пути из-за огромного):
<svg id="map" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="330" height="500" viewBox="-16037,-19651 28871,44234">
<g id="state_outline">
<path id="state" fill="white" stroke-width="200" d="..." />
<path id="water" fill="#a0a0ff" d="..." />
</g>
<g id="counties">
<path class="county" id="adams" d="..." />
...
</g>
</svg>
<div id="nottamap"></div>
<script type="text/javascript">
console.log($('nottamap'));
console.log($('nottamap').identify());
console.log($('counties'));
console.log($('counties').identify());
</script>
Результат выполнения:
<div id="nottamap">
nottamap
<g id="counties">
$("counties").identify is not a function
$() просто отказывается расширять переданный ему элемент, если он является частью элемента SVG. Есть ли что-то о взаимодействии прототипа с элементами XML, которые я не понимаю, или есть лучший способ для меня сделать это?
Ответы
Ответ 1
Прототип дополняет элементы с помощью Element.addMethods
. Если вы посмотрите на исходный код, вы можете увидеть эту важную часть:
var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
Element.prototype;
if (F.ElementExtensions) {
copy(Element.Methods, elementPrototype);
copy(Element.Methods.Simulated, elementPrototype, true);
}
Здесь он поддерживает HTMLElement.prototype
, которые элементы SVG не наследуют. Он возвращается к Element.prototype
в этих браузерах (кашель IE cough), которые также не поддерживают SVG. У вас есть выбор для непосредственного редактирования источника и дублирования всех действий копирования на SVGElement
.
Это похоже на большую работу, когда вы понимаете, что можно использовать более простой взлом. Статические методы Element.*
все еще работают при непосредственном использовании. Вместо $('counties').identify()
используйте Element.identify('counties')
. Где вы можете сделать что-то вроде этого:
$$('.classname').invoke('hide');
Вы можете принять хороший функциональный эквивалент, который:
$$('.classname').each(Element.hide);
// or replace Element.hide with Effect.fade or any other effect
Недостатком является то, что вы теряете способность использовать цепочку методов.
Ответ 2
clockworkgeek предложение изменить исходный код прототипа очень сработало для меня. В прототипе v. 1.7 все, что требуется, - это изменить соответствующую часть на
var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
Element.prototype;
if (F.ElementExtensions) {
if (window.SVGElement) {
copy(Element.Methods, SVGElement.prototype);
copy(Element.Methods.Simulated, SVGElement.prototype, true);
}
copy(Element.Methods, elementPrototype);
copy(Element.Methods.Simulated, elementPrototype, true);
}
В прототипе v. 1.7.1 необходимы следующие изменения:
var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
Element.prototype;
if (F.ElementExtensions) {
if (window.SVGElement) {
mergeMethods(SVGElement.prototype, Element.Methods);
mergeMethods(SVGElement.prototype, Element.Methods.Simulated, true);
}
mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
}
Я нашел готовое решение в этом сообщении в блоге