приложение jquery не работает с элементом svg?
предполагаю, что это:
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("svg").append('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
});
</script>
</head>
<body>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px">
</svg>
</body>
почему я ничего не вижу?
14 ответов:
когда вы передаете строку разметки в
$, Он анализируется как HTML с помощью браузераinnerHTMLсвойства<div>(или другой соответствующий контейнер для особых случаев как<tr>).innerHTMLне может анализировать SVG или другое содержимое, отличное от HTML, и даже если бы это было возможно, он не смог бы сказать это<circle>должен был быть в пространстве имен SVG.
innerHTMLнедоступно на SVGElement-это свойство только HTMLElement. Также в настоящее время нетinnerSVGсобственность или другой способ (*) разбора содержимого в SVGElement. По этой причине вы должны использовать методы DOM-стиля. jQuery не дает вам легкий доступ к методам пространства имен, необходимым для создания элементов SVG. На самом деле jQuery не предназначен для использования с SVG вообще, и многие операции могут завершиться неудачей.HTML5 обещает позволить вам использовать
<svg>безxmlnsвнутри простого HTML (text/html) документа в будущем. Но это всего лишь парсер hack (**), содержимое SVG все равно будет SVGElements в Пространство имен SVG, а не HTMLElements, поэтому вы не сможете использоватьinnerHTMLдаже если они посмотреть как часть HTML-документа.однако, для современных браузеров вы должны использовать XHTML (правильно служил как
application/xhtml+xml; сохранить .расширение файла xhtml для локального тестирования), чтобы заставить SVG работать вообще. (Это имеет смысл в любом случае; SVG-это правильный стандарт на основе XML.) Это означает, что вам придется бежать<символы внутри блока скрипта (или заключите в раздел CDATA) и включите XHTMLxmlnsдекларации. пример:<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"><head> </head><body> <svg id="s" xmlns="http://www.w3.org/2000/svg"/> <script type="text/javascript"> function makeSVG(tag, attrs) { var el= document.createElementNS('http://www.w3.org/2000/svg', tag); for (var k in attrs) el.setAttribute(k, attrs[k]); return el; } var circle= makeSVG('circle', {cx: 100, cy: 50, r:40, stroke: 'black', 'stroke-width': 2, fill: 'red'}); document.getElementById('s').appendChild(circle); circle.onmousedown= function() { alert('hello'); }; </script> </body></html>*: ну, есть DOM Level 3 LS parseWithContext, но поддержка браузера очень плохая. Изменить, чтобы добавить: однако, хотя вы не можете вводить разметку в SVGElement, вы можете ввести новый SVGElement в HTMLElement с помощью
innerHTML, затем перенесите его в нужную цель. Это, вероятно, будет немного медленнее:<script type="text/javascript"><![CDATA[ function parseSVG(s) { var div= document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+s+'</svg>'; var frag= document.createDocumentFragment(); while (div.firstChild.firstChild) frag.appendChild(div.firstChild.firstChild); return frag; } document.getElementById('s').appendChild(parseSVG( '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" onmousedown="alert(\'hello\');"/>' )); ]]></script>**: я ненавижу то, как авторы HTML5, похоже, боятся XML и полны решимости встроить функции на основе XML в жестокий беспорядок, который является HTML. XHTML решил эти проблемы много лет назад.
The принято отвечать показывает слишком сложный путь. Как Forresto претензии в ответ,"кажется, чтобы добавить их в DOM explorer, но не на экране " и причина этого-разные пространства имен для html и svg.
самый простой обходной путь- "обновить" весь svg. После добавления круга (или других элементов), используйте этот:
$("body").html($("body").html());это делает трюк. Круг на экран.
или если вы хотите, используйте контейнер div:
$("#cont").html($("#cont").html());и оберните ваш svg внутри контейнера div:
<div id="cont"> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px"> </svg> </div>функциональный пример:
http://jsbin.com/ejifab/1/editпреимущества этой техники:
- вы можете редактировать существующий svg (который уже находится в DOM), например. создано с использованием Рафаэля или как в вашем примере "жестко закодировано" без сценариев.
- вы можете добавить сложные структуры элементов в виде строк, например.
$('svg').prepend('<defs><marker></marker><mask></mask></defs>');как вы делаете в jQuery.- после того, как элементы добавляются и становятся видимыми на экране с помощью
$("#cont").html($("#cont").html());их атрибуты можно редактировать с помощью jQuery.
EDIT:
вышеуказанный метод работает с "жестко закодированным" или управляемым DOM ( = документ.createElementNS и др.) Только SVG. Если Рафаэль используется для создания элементов, (согласно моим тестам) связь между Рафаэлем объекты и SVG DOM нарушается, если есть. Обходной путь к этому не использовать
$("#cont").html($("#cont").html());вообще и вместо него используйте фиктивный SVG документ.этот фиктивный SVG является сначала текстовым представлением документа SVG и содержит только необходимые элементы. Если мы хотим, например. чтобы добавить фильтрующий элемент в документ Raphael, манекен может быть чем-то вроде
<svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg>. Текстовое представление сначала преобразуется в DOM с помощью jQuery $("body").метод append (). И когда (фильтр) элемент находится в DOM, его можно запросить с помощью стандартных методов jQuery и добавить к основному документу SVG, который создается Raphael.зачем нужен этот манекен? Почему бы не добавить фильтрующий элемент строго в созданный Рафаэлем документ? Если вы попробуете его с помощью, например.
$("svg").append("<circle ... />"), он создается как элемент html, и ничего не отображается на экране, как описано в ответах. но если весь документ SVG добавляется, то браузер автоматически обрабатывает преобразование пространства имен всех элементов в документе SVG.пример просветит технику:
// Add Raphael SVG document to container element var p = Raphael("cont", 200, 200); // Add id for easy access $(p.canvas).attr("id","p"); // Textual representation of element(s) to be added var f = '<filter id="myfilter"><!-- filter definitions --></filter>'; // Create dummy svg with filter definition $("body").append('<svg id="dummy" style="display:none"><defs>' + f + '</defs></svg>'); // Append filter definition to Raphael created svg $("#p defs").append($("#dummy filter")); // Remove dummy $("#dummy").remove(); // Now we can create Raphael objects and add filters to them: var r = p.rect(10,10,100,100); $(r.node).attr("filter","url(#myfilter)");полная рабочая демонстрация этой техники находится здесь:http://jsbin.com/ilinan/1/edit.
(Я (пока) не знаю, почему
$("#cont").html($("#cont").html());не работает при использовании Рафаэля. Это был бы очень короткий Хак. )
все более популярным D3 библиотека обрабатывает странности добавления / манипулирования svg очень красиво. Возможно, вы захотите использовать его в отличие от хаков jQuery, упомянутых здесь.
HTML
<svg xmlns="http://www.w3.org/2000/svg"></svg>Javascript
var circle = d3.select("svg").append("circle") .attr("r", "10") .attr("style", "fill:white;stroke:black;stroke-width:5");
JQuery не может добавлять элементы в
<svg>(Кажется, чтобы добавить их в DOM explorer, но не на экране).один обходной путь заключается в добавлении
<svg>со всеми элементами, которые вам нужны на странице, а затем изменить атрибуты элементов с помощью.attr().$('body') .append($('<svg><circle id="c" cx="10" cy="10" r="10" fill="green" /></svg>')) .mousemove( function (e) { $("#c").attr({ cx: e.pageX, cy: e.pageY }); });
Я не видел, чтобы кто-то упоминал этот способ, но
document.createElementNS()полезно в этом случае.вы можете создавать элементы с помощью vanilla Javascript в качестве обычных узлов DOM с правильным пространством имен, а затем jQuery-ify их оттуда. Вот так:
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); var $circle = $(circle).attr({ //All your attributes }); $(svg).append($circle);единственным недостатком является то, что вы должны создать каждый элемент SVG с правильным пространством имен по отдельности или он не будет работать.
Я вижу круг в firefox, делая 2 вещи:
1) переименование файла из html в xhtml
2) изменить скрипт на
<script type="text/javascript"> $(document).ready(function(){ var obj = document.createElementNS("http://www.w3.org/2000/svg", "circle"); obj.setAttributeNS(null, "cx", 100); obj.setAttributeNS(null, "cy", 50); obj.setAttributeNS(null, "r", 40); obj.setAttributeNS(null, "stroke", "black"); obj.setAttributeNS(null, "stroke-width", 2); obj.setAttributeNS(null, "fill", "red"); $("svg")[0].appendChild(obj); }); </script>
нашел простой способ, который работает со всеми браузерами, которые у меня есть (Chrome 49, Edge 25, Firefox 44, IE11, Safari 5 [Win], Safari 8 (MacOS)):
// Clean svg content (if you want to update the svg's objects) // Note : .html('') doesn't works for svg in some browsers $('#svgObject').empty(); // add some objects $('#svgObject').append('<polygon class="svgStyle" points="10,10 50,10 50,50 10,50 10,10" />'); $('#svgObject').append('<circle class="svgStyle" cx="100" cy="30" r="25"/>'); // Magic happens here: refresh DOM (you must refresh svg's parent for Edge/IE and Safari) $('#svgContainer').html($('#svgContainer').html());.svgStyle { fill:cornflowerblue; fill-opacity:0.2; stroke-width:2; stroke-dasharray:5,5; stroke:black; }<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="svgContainer"> <svg id="svgObject" height="100" width="200"></svg> </div> <span>It works if two shapes (one square and one circle) are displayed above.</span>
на основе ответа @chris-dolphin, но с помощью вспомогательной функции:
// Creates svg element, returned as jQuery object function $s(elem) { return $(document.createElementNS('http://www.w3.org/2000/svg', elem)); } var $svg = $s("svg"); var $circle = $s("circle").attr({...}); $svg.append($circle);
если строка, которую вам нужно добавить, является SVG, и вы добавляете правильное пространство имен, вы можете разобрать строку как XML и добавить к родителю.
var xml = jQuery.parseXML('<circle xmlns="http://www.w3.org/2000/svg" cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'); $("svg").append(xml.documentElement))
принятый ответ Bobince-это короткое портативное решение. Если вам нужно не только добавить SVG, но и манипулировать им, вы можете попробовать JavaScript библиотека "Пабло" (я писал это). Он будет чувствовать себя знакомым пользователям jQuery.
ваш пример кода будет выглядеть так:
$(document).ready(function(){ Pablo("svg").append('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'); });вы также можете создавать элементы SVG на лету, не указывая разметку:
var circle = Pablo.circle({ cx:100, cy:50, r:40 }).appendTo('svg');
Я бы предположил, что было бы лучше использовать ajax и загрузить элемент svg с другой страницы.
$('.container').load(href + ' .svg_element');где href-это расположение страницы с svg. Таким образом, вы можете избежать каких-либо нервных эффектов, которые могут возникнуть при замене содержимого html. Кроме того, не забудьте развернуть svg после его загрузки:
$('.svg_element').unwrap();
var svg; // if you have variable declared and not assigned value. // then you make a mistake by appending elements to that before creating element svg.appendChild(document.createElement("g")); // at some point you assign to svg svg = document.createElementNS('http://www.w3.org/2000/svg', "svg") // then you put it in DOM document.getElementById("myDiv").appendChild(svg) // it wont render unless you manually change myDiv DOM with DevTools // to fix assign before you append var svg = createElement("svg", [ ["version", "1.2"], ["xmlns:xlink", "http://www.w3.org/1999/xlink"], ["aria-labelledby", "title"], ["role", "img"], ["class", "graph"] ]); function createElement(tag, attributeArr) { // .createElementNS NS is must! Does not draw without let elem = document.createElementNS('http://www.w3.org/2000/svg', tag); attributeArr.forEach(element => elem.setAttribute(element[0], element[1])); return elem; } // extra: <circle> for example requires attributes to render. Check if missing.
это работает для меня сегодня с FF 57:
function () { // JQuery, today, doesn't play well with adding SVG elements - tricks required $(selector_to_node_in_svg_doc).parent().prepend($(this).clone().text("Your")); $(selector_to_node_in_svg_doc).text("New").attr("x", "340").text("New") .attr('stroke', 'blue').attr("style", "text-decoration: line-through"); }составляет:
гораздо более простой способ-просто сгенерировать SVG в строку, создать HTML-элемент оболочки и вставить строку svg в HTML-элемент с помощью
$("#wrapperElement").html(svgString). Это прекрасно работает в Chrome и Firefox.

Comments