SVG
Scripting
Поиск…
замечания
Scripting SVG с использованием собственных интерфейсов DOM в настоящее время (2016) в состоянии незначительного изменения. Текущий стандарт SVG (1.1) хорошо реализуется большинством основных веб-браузеров. Однако, поскольку стандарт SVG 2.0 находится в разработке, некоторые браузеры начали удалять функции SVG 1.1, которые будут устаревшими в версии 2.0. Вы можете увидеть полный список предлагаемых изменений от SVG 1.1 до SVG 2.0 в Приложении L SVG 2.0 .
Замена pathSegList
и другого использования SVGPathSeg
В SVG 1.1 элементы <path>
определены как pathSegList
свойство pathSegList
которое дает доступ к собственному представлению всех команд пути . Google Chrome v48 удалил это свойство в конце 2015 года в рамках подготовки к предлагаемой замене в SVG 2.0 . До тех пор, пока поддержка SVG 2.0 не будет добавлена, вы должны использовать polyfill, чтобы либо вернуть функциональность 1.1 , либо реализовать предлагаемый API 2.0 .
Замена getTransformToElement()
Chrome v48 также удалил метод SVGGraphicsElement.getTransformToElement()
. Для реализации старого метода существует простой полиполк.
Создание элемента
Самый простой способ понять, как создавать и изменять элементы SVG, - это работать с элементами, использующими базовые интерфейсы DOM Level 2 Core , как и с HTML или XML.
Крайне важно, чтобы элементы, созданные из JavaScript, создавались в том же пространстве имен, которое было объявлено в элементе SVG - в этом примере: « http://www.w3.org/2000/svg ». Однако почти все атрибуты элементов SVG не находятся в каком-либо пространстве имен. Вы не должны размещать их в пространстве имен SVG.
Здесь мы демонстрируем SVG, размещенный внутри HTML, поскольку это обычный случай:
<!doctype HTML>
<html><title>Creating an Element</title>
<body>
<svg xmlns="http://www.w3.org/2000/svg"
width="100%" height="100%"
viewBox="0 0 400 300"></svg>
<script>
var svgNS = "http://www.w3.org/2000/svg";
// Create a circle element (not part of the DOM yet)
var circle = document.createElementNS(svgNS,'circle'); // Creates a <circle/>
circle.setAttribute('fill','red'); // Note: NOT setAttributeNS()
circle.setAttribute('cx',150); // setAttribute turns 150 into a string
circle.setAttribute('cy','80'); // using a string works, too
circle.setAttribute('r',35); // give the circle a radius so we can see it
// Now, add the circle to the SVG document so we can see it
var svg = document.querySelector('svg'); // the root <svg> element
svg.appendChild(circle);
</script>
</body></html>
Существует несколько атрибутов, которые необходимо создать в определенном пространстве имен. Они перечислены с двоеточиями в их именах в Индексе атрибутов SVG . В частности, они: xlink:actuate
, xlink:arcrole
, xlink:href
, xlink:role
, xlink:show
, xlink:title
, xlink:type
, xml:base
, xml:lang
и xml:space
. Установите эти атрибуты с помощью setAttributeNS()
:
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var img = document.createElementNS( svgNS, 'image' );
img.setAttributeNS( xlinkNS, 'href', 'my.png' );
Если вы часто создаете элементы, особенно со многими атрибутами, вспомогательная функция, подобная следующей, может спасти вас при наборе текста, избежать ошибок и сделать код более удобным для чтения:
<!doctype HTML>
<html><title>Creating an Element</title>
<body>
<svg xmlns="http://www.w3.org/2000/svg"></svg>
<script>
var svg = document.querySelector('svg');
var circle = createOn( svg, 'circle', {fill:'red', cx:150, cy:80, r:35} );
// Create an SVG element on another node with a set of attributes.
// Attributes with colons in the name (e.g. 'xlink:href') will automatically
// find the appropriate namespace URI from the SVG element.
// Optionally specify text to create as a child node, for example
// createOn(someGroup,'text',{x:100,'text-anchor':'middle'},"Hello World!");
function createOn(parentEl,name,attrs,text){
var doc=parentEl.ownerDocument, svg=parentEl;
while (svg && svg.tagName!='svg') svg=svg.parentNode;
var el = doc.createElementNS(svg.namespaceURI,name);
for (var a in attrs){
if (!attrs.hasOwnProperty(a)) continue;
var p = a.split(':');
if (p[1]) el.setAttributeNS(svg.getAttribute('xmlns:'+p[0]),p[1],attrs[a]);
else el.setAttribute(a,attrs[a]);
}
if (text) el.appendChild(doc.createTextNode(text));
return parentEl.appendChild(el);
}
</script>
</body></html>
Атрибуты чтения / записи
Вы можете использовать либо методы DOM Level 2 Core getAttribute()
, getAttributeNS()
, setAttribute()
и setAttributeNS()
для чтения и записи значений из элементов SVG, либо вы можете использовать настраиваемые свойства и методы, указанные в setAttributeNS()
SVG 1.1 (интерфейс Определение языка).
Простые числовые атрибуты
Например, если у вас есть элемент окружности SVG:
<circle id="circ" cx="10" cy="20" r="15" />
вы можете использовать методы DOM для чтения и записи атрибутов:
var circ = document.querySelector('#circ');
var x = circ.getAttribute('cx') * 1; // Use *1 to convert from string to number value
circ.setAttribute('cy', 25);
... или вы можете использовать пользовательские свойства cx
, cy
и r
определенные для SVGCircleElement
. Обратите внимание, что это не прямые числа, а вместо этого, как и многие другие в SVG 1.1, они позволяют получить доступ к анимированным значениям. Эти свойства имеют тип SVGAnimatedLength
. Без учета единиц анимации и длины вы можете использовать такие атрибуты, как:
var x = circ.cx.baseVal.value; // this is a number, not a string
circ.cy.baseVal.value = 25;
Трансформации
Группы SVG могут использоваться для перемещения, поворота, масштабирования и, в противном случае, преобразования нескольких графических элементов в целом. (Подробнее о переводах SVG см. В главе 7 ). Вот группа, которая делает смайликом лицо, которое вы можете настроить размер, поворот и размещение, регулируя transform
:
<g id="smiley" transform="translate(120,120) scale(5) rotate(30)">
<circle r="20" fill="yellow" stroke-width="2"/>
<path fill="none" d="M-10,5 a 5 3 0 0 0 20,0" stroke-width="2"/>
<circle cx="-6" cy="-5" r="2" fill="#000"/>
<circle cx="6" cy="-5" r="2" fill="#000"/>
</g>
Использование сценария для настройки масштаба этого с помощью методов DOM требует манипулирования всем атрибутом transform
как строки:
var face = document.querySelector('#smiley');
// Find the full string value of the attribute
var xform = face.getAttribute('transform');
// Use a Regular Expression to replace the existing scale with 'scale(3)'
xform = xform.replace( /scale\s*\([^)]+\)/, 'scale(3)' );
// Set the attribute to the new string.
face.setAttribute('transform',xform);
С помощью SVG DOM можно пройти определенные преобразования в списке, найти нужный и изменить значения:
var face = document.querySelector('#smiley');
// Get the SVGTransformList, ignoring animation
var xforms = face.transform.baseVal;
// Find the scale transform (pretending we don't know its index)
for (var i=0; i<xforms.numberOfItems; ++i){
// Get this part as an SVGTransform
var xform = xforms.getItem(i);
if (xform.type == SVGTransform.SVG_TRANSFORM_SCALE){
// Set the scale; both X and Y scales are required
xform.setScale(3,3);
break;
}
}
- Для перемещения и управления количеством преобразований см.
SVGTransformList
. - Для управления отдельными преобразованиями см.
SVGTransform
.
Перетаскивание элементов SVG
Использование мыши для перетаскивания элемента SVG (или группы элементов) может быть выполнено с помощью:
- Добавление обработчика
mousedown
для запуска перетаскивания: добавление перевода элемента, который нужно использовать при перетаскивании (при необходимости), отслеживание событийmousemove
и добавлениеmouseup
для завершения перетаскивания. - Во время
mousemove
, преобразуя положение мыши из экранных координат в локальные координаты для объекта, который вы перетаскиваете, и соответственно обновите перевод. - Во время
mouseup
mousemove
mouseup
mousemove
иmouseup
.
// Makes an element in an SVG document draggable.
// Fires custom `dragstart`, `drag`, and `dragend` events on the
// element with the `detail` property of the event carrying XY
// coordinates for the location of the element.
function makeDraggable(el){
if (!el) return console.error('makeDraggable() needs an element');
var svg = el;
while (svg && svg.tagName!='svg') svg=svg.parentNode;
if (!svg) return console.error(el,'must be inside an SVG wrapper');
var pt=svg.createSVGPoint(), doc=svg.ownerDocument;
var root = doc.rootElement || doc.body || svg;
var xlate, txStartX, txStartY, mouseStart;
var xforms = el.transform.baseVal;
el.addEventListener('mousedown',startMove,false);
function startMove(evt){
// We listen for mousemove/up on the root-most
// element in case the mouse is not over el.
root.addEventListener('mousemove',handleMove,false);
root.addEventListener('mouseup', finishMove,false);
// Ensure that the first transform is a translate()
xlate = xforms.numberOfItems>0 && xforms.getItem(0);
if (!xlate || xlate.type != SVGTransform.SVG_TRANSFORM_TRANSLATE){
xlate = xforms.createSVGTransformFromMatrix( svg.createSVGMatrix() );
xforms.insertItemBefore( xlate, 0 );
}
txStartX=xlate.matrix.e;
txStartY=xlate.matrix.f;
mouseStart = inElementSpace(evt);
fireEvent('dragstart');
}
function handleMove(evt){
var point = inElementSpace(evt);
xlate.setTranslate(
txStartX + point.x - mouseStart.x,
txStartY + point.y - mouseStart.y
);
fireEvent('drag');
}
function finishMove(evt){
root.removeEventListener('mousemove',handleMove,false);
root.removeEventListener('mouseup', finishMove,false);
fireEvent('dragend');
}
function fireEvent(eventName){
var event = new Event(eventName);
event.detail = { x:xlate.matrix.e, y:xlate.matrix.f };
return el.dispatchEvent(event);
}
// Convert mouse position from screen space to coordinates of el
function inElementSpace(evt){
pt.x=evt.clientX; pt.y=evt.clientY;
return pt.matrixTransform(el.parentNode.getScreenCTM().inverse());
}
}