Подтвердить что ты не робот

Может ли 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, которые я не понимаю, или есть лучший способ для меня сделать это?

4b9b3361

Ответ 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);
}

Я нашел готовое решение в этом сообщении в блоге