jquery의 추가가 svg 요소와 작동하지 않습니까?


199

이것을 가정하면 :

<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>

왜 아무것도 보이지 않습니까?

jquery  html  svg 

답변:


249

에 마크 업 문자열을 전달하면 (또는와 같은 특수한 경우에 적합한 컨테이너) $의 브라우저 innerHTML속성을 사용하여 HTML로 구문 분석됩니다 . SVG 또는 HTML이 아닌 다른 컨텐츠를 구문 분석 할 수 없으며 SVG 네임 스페이스에 있다고 가정 할 수는 없습니다 .<div><tr>innerHTML<circle>

innerHTMLSVGElement에서는 사용할 수 없습니다. HTMLElement만의 속성입니다. 현재 innerSVG콘텐츠를 SVGElement로 구문 분석 하는 속성이나 다른 방법 (*)이 없습니다. 이러한 이유로 DOM 스타일 메소드를 사용해야합니다. jQuery를 사용하면 SVG 요소를 만드는 데 필요한 네임 스페이스가있는 메서드에 쉽게 액세스 할 수 없습니다. 실제로 jQuery는 SVG와 함께 사용하도록 설계되지 않았으며 많은 작업이 실패 할 수 있습니다.

HTML5는 향후 일반 HTML ( ) 문서 <svg>없이도 사용할 수 있도록합니다 . 그러나 이것은 당신이 사용할 수 없을 것이다, 그래서 SVG 콘텐츠는 여전히 SVG 네임 스페이스 SVGElements, 그리고 HTMLElements 될 것입니다 (**) 단지 파서 해킹 그들이 비록 심지어 보면 HTML 문서의 일부처럼.xmlnstext/htmlinnerHTML

그러나 오늘날의 브라우저에서는 SVG가 제대로 작동 하도록하려면 X HTML ( application/xhtml+xml로컬 테스트를 위해 .xhtml 파일 확장명으로 저장)을 올바르게 사용해야 합니다. SVG는 적절한 XML 기반 표준입니다. 이는 <스크립트 블록 내부 의 기호 를 이스케이프 처리 하거나 CDATA 섹션으로 묶어야하며 XHTML xmlns선언을 포함해야 함을 의미합니다 . 예:

<!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은 몇 년 전에 이러한 문제를 해결했습니다.


7
이 답변은 여전히 ​​관련이 있습니다! Chrome 요소 관리자에 추가 된 요소가 표시되는 이상한 버그가 있었지만 렌더링하지 않았습니다. 나는 경우 RMB> edit as htmlhtml 태그와 히트에 입력 한 모든 디스플레이 (하지만 모든 이벤트 리스너가 사라진다). 이 답변을 읽은 후 createElement 호출을 createElementNS로 변경했으며 이제 모든 것이 작동합니다!
kitsu.eb

7
DOM 메소드 createElementNS를 사용하여 생성 된 jquery로 SVG 요소를 조작 할 수 있습니다. makeSVG 함수를 'return $ (el)'으로 변경할 수 있으며 이제 jquery 메소드를 사용할 수있는 svg 요소가 있습니다.
호프만

6
아! 그래서 그것이 작동하지 않는 이유입니다. jQuery와 D3.js 에 각각 다른 두 개의 라이브러리를 사용하여 똑같은 것을 시도했습니다 . 두 가지를 모두 사용하여 HTML에서 정확히 동일한 소스 출력을 얻었 지만 jQuery 생성 요소는 렌더링하지 않지만 D3 생성 요소는 렌더링하지 않았습니다! : 나는 D3 사용하는 것이 좋습니다d3.select('body').append('svg').attr('width','100%');
chharvey

3
@ MadsSkjern : DOM 레벨 3 LS는 결코 브라우저에 그것을 만들지 않았습니다. 원래 모질라 전용 DOMParser 는 이제 더 광범위하게 지원되며 jQuery는을 지원 $.parseXML합니다.
bobince

1
여전히 관련이 있습니다. bobince는 HTML5의 혼란을 싫어합니다. 나는 웹 전체의 혼란을 싫어합니다 . 왜냐하면 그 혼란 때문에 좋은 코드 찾을 수 없기 때문입니다. WWW는 WWM World Wide Mess로 이름을 바꿔야합니다.
Olivier Pons

149

허용 답변 쇼도 방법을 복잡. Forresto가 자신의 답변 에서 주장한 것처럼 " DOM 탐색기에서는 DOM 탐색기에 추가하는 것 같지만 화면에는 표시되지 않습니다 "라는 이유는 html과 svg의 네임 스페이스가 다르기 때문입니다.

가장 쉬운 해결 방법은 전체 svg를 "새로 고침"입니다. 원 (또는 다른 요소)을 추가 한 후 다음을 사용하십시오.

$("body").html($("body").html());

이것은 트릭을 수행합니다. 원이 화면에 있습니다.

또는 원하는 경우 컨테이너 div를 사용하십시오.

$("#cont").html($("#cont").html());

그리고 컨테이너 div 안에 svg를 감싸십시오.

<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에 있음)를 편집 할 수 있습니다. 스크립트없이 "하드 코딩 된"예제에서 Raphael 등을 사용하여 만들었습니다.
  • 복잡한 요소 구조를 문자열로 추가 할 수 있습니다 (예 : $('svg').prepend('<defs><marker></marker><mask></mask></defs>');jQuery에서와 같이.
  • 요소가 추가되고 $("#cont").html($("#cont").html());속성을 사용하여 화면에 표시되면 jQuery를 사용하여 편집 할 수 있습니다.

편집하다:

위의 기술은 "하드 코딩 된"또는 DOM 조작 (= document.createElementNS 등) SVG에서만 작동합니다. Raphael을 사용하여 요소를 만드는 경우 (내 테스트에 따르면) Raphael 객체와 SVG DOM 간의 연결 $("#cont").html($("#cont").html());이 사용 되면 끊어집니다 . 이에 대한 해결 방법은 전혀 사용하지 $("#cont").html($("#cont").html());않고 더미 SVG 문서를 사용하는 것입니다.

이 더미 SVG는 먼저 SVG 문서의 텍스트 표현이며 필요한 요소 만 포함합니다. 우리가 원한다면. Raphael 문서에 필터 요소를 추가하기 위해 더미는 다음과 같을 수 있습니다 <svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg>. 텍스트 표현은 먼저 jQuery의 $ ( "body"). append () 메소드를 사용하여 DOM으로 변환됩니다. (filter) 요소가 DOM에있을 때 표준 jQuery 메소드를 사용하여 쿼리하고 Raphael이 생성 한 기본 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());라파엘을 사용할 때 작동하지 않습니다. 매우 짧은 해킹 일 것입니다.)


SVG 처리에 내 (홈 제작) 솔루션을 사용하고 있으며 $ (# picture) .html ...과 함께 "reparsing trick"을 사용할 때 Raphael과 동일한 문제가 있지만 내 솔루션은 캐시 된 SVG를 다시 초기화하는 것이 었습니다 요소 (사각형, 변환 등 표시)
halfbit

당신은 마법사입니다. 나는 받아 들여진 대답을보고 있었고 나는 사람과 같았습니다. 이것은 고통 스러울 것입니다. 그런 다음 이것을 보았고 한 줄로 필요한 모든 것을 수행합니다. 감사합니다!
작곡가

1
이것은 내 대리석을 잃어 버렸기 때문에 ... SVG 네임 스페이스에서 js DOM 느릅 나무를 마술처럼 사용할 수 있다고 생각했습니다.
거스 크로포드

기존 다각형 및 경로 태그를 새로 만든 부모 svg 태그에 추가 할 때 유용했습니다. 감사!
Kivak Wolf

1
$("#cont").html($("#cont").html());Chrome에서는 훌륭하게 작동했지만 IE 11에서는 작동하지 않았습니다.
CoderDennis

37

점점 더 인기있는 D3 라이브러리는 svg를 추가 / 조작 할 수있는 가능성을 매우 잘 처리합니다. 여기에 언급 된 jQuery 해킹과 달리 사용하는 것이 좋습니다.

HTML

<svg xmlns="http://www.w3.org/2000/svg"></svg>

자바 스크립트

var circle = d3.select("svg").append("circle")
    .attr("r", "10")
    .attr("style", "fill:white;stroke:black;stroke-width:5");

좋은 대답입니다. 그것은 여기서 어떤 문제에 도움이되었습니다.
ismail baig 2009 년

jQuery는 또한 SVG에서 클래스를 설정 / 가져 오기도합니다. 제쳐두고
QueueHammer

24

JQuery는 요소를 추가 할 수 없습니다 <svg>(DOM 탐색기에는 추가하지만 화면에는 나타나지 않는 것처럼 보입니다).

한 가지 해결 방법은 <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
      });
  });

http://jsfiddle.net/8FBjb/1/


고마워, 나에게 많은 도움이되었습니다! 이것은 매우 좋은 접근 방법입니다. <circle>복잡하고 느린 DOM 메소드 (예 : createDocumentFragment()또는 createElementNS())를 사용하여 개별적으로 또는 다른 요소를 개별적 으로 추가하는 대신 전체 svg 문서를 컨테이너에 추가하십시오. $ ( 'body') 대신 $ ( 'div')도 될 수 있습니다. 그런 다음 svg 문서는 DOM에 있으며 예를 들어 익숙한 방식으로 쿼리 할 수 ​​있습니다. $ ( 'c'). attr ( 'fill', 'red').
Timo Kähkönen

jsbin.com/inevaz/1 의 추가 예제를 만들었습니다 . 인터넷에서 iframe으로 tiger.svg 소스 코드를 가져오고 텍스트 영역에 복사-붙여 넣을 수 있습니다. 텍스트 영역의 내용은 인라인 svg의 소스로 사용되며 DOM을 통해 액세스 할 수 있습니다 (스트로크 스타일 변경).
Timo Kähkönen

이것은 대단합니다. 왜 모든 사람들이 단순히 효과가없는 다른 답변에 투표하는지 모르겠습니다.
Dustin Poissant 2016 년

이것은 나에게도 가장 좋은 대답이었습니다. <use xlink : href = "# icon">이있는 svg가 필요했으며 이것이 가장 짧은 답변이었습니다.
Eydamos 2016 년

17

누군가이 방법을 언급하지는 않았지만 document.createElementNS()이 경우 도움이됩니다.

올바른 네임 스페이스를 가진 일반 DOM 노드로 바닐라 Javascript를 사용하여 요소를 작성한 다음 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 요소를 개별적으로 만들어야하거나 작동하지 않는다는 것입니다.


2
Timo의 답변 (최고 투표)은 Chrome에서는 작동했지만 IE에서는 작동하지 않았습니다. 이 답변은 두 브라우저의 문제를 해결했습니다!
CoderDennis

1
좋은! 알아두면 좋은 점
Chris Dolphin

14

내가 가지고있는 모든 브라우저 (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>


5
그 새로 고침 줄은 내가 찾던 것입니다. 바보 같은 브라우저. 감사!
Sam Soffes

8

파이어 폭스에서 서클을 볼 수 있으며 두 가지 작업을 수행합니다.

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>

1
8 년 후에도 여전히 도움이됩니다!
Don 01001100

5

@ 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);

1
당신은 또한 할 수 있습니다 :$svg.append($s('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'));
Jonas Berlin

4

추가해야하는 문자열이 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))

3

Bobince의 대답은 짧고 휴대 가능한 솔루션입니다. SVG를 추가 할뿐만 아니라 조작 해야하는 경우 JavaScript 라이브러리 "Pablo"를 사용해 볼 수 있습니다 (필자가 작성했습니다). 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');

1

ajax를 사용하고 다른 페이지에서 svg 요소를로드하는 것이 좋습니다.

$('.container').load(href + ' .svg_element');

여기서 href는 svg가있는 페이지의 위치입니다. 이렇게하면 html 컨텐츠를 교체 할 때 발생할 수있는 불안한 영향을 피할 수 있습니다. 또한 svg 가로 드 된 후 포장을 풀어야합니다.

$('.svg_element').unwrap();

0

이것은 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");
}

만든다 :

Firefox 57에서 보이는이 SVG 이미지


추가하는 SVG 요소가 아니라 텍스트 내용입니다.
Robert Longson

그럴 수도 있지만 정적으로 인라인 된 SVG의 초기 페이지로드 후에 렌더링됩니다 .
paul_h

그래서, 그것은 질문되지 않습니다. 이것은 텍스트 내용이 아닌 svg 요소에 관한 것입니다.
Robert Longson

$(this).clone()SVG 요소를 복제하고 있습니다 (있는 경우 자식 임). 의 사용 과거를 살펴보십시오 text(). "Your New"가 포함 된 단일 tspan을 가져오고 두 개의 tspan으로 끝나고 하나는 "Your"가 있고 (블랙) 다른 하나는 "New in it"이 있습니다 (파란색). Jeez, 0 투표에서 -1로 감소 :-(
paul_h

0
 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.

-1

훨씬 간단한 방법은 SVG를 문자열로 생성하고 래퍼 HTML 요소를 만든 다음를 사용하여 svg 문자열을 HTML 요소에 삽입하는 것 $("#wrapperElement").html(svgString)입니다. 이것은 Chrome과 Firefox에서 잘 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.