본문으로 바로가기

HTML 파일에서 SVG 파일 내의 엘리먼트 다루기

category 코딩/HTML & CSS 2022. 7. 19. 11:06

여기처럼 SVG 이미지를 inline 형태로 삽입하면 HTML 코드가 복잡해질 수 있다.

당연히 <embed>, <img> 태그처럼 삽입하여 간결하게 할 수 있지만, 반응형 css 또는 script를 적용하려고 하면 문제가 생긴다.

SVG 이미지가 DOM 형태로 삽입되다 보니 HTML과 SVG 파일 각각에 존재하는 엘리먼트가 서로를 참조하기 어렵다는 것.

비록 꼼수이긴 하나 이 문제를 해소할 수 있는 방법을 포스팅한다(결론은 아래 완성 부분).

 

SVG 파일 내부에서 css와 jquery 사용하기

HTML에 SVG 파일 삽입 방식

object 방식 또는 embed 방식 중에 사용한다.

<div class="svg_wrap">
	<object type="image/svg+xml" data="images/system.svg" id="svg_system"></object>
	<!-- 또는 -->
	<embed type="image/svg+xml" src="images/system.svg" id="svg_system">
</div>

추가로 아래처럼 jquery로도 가능하다.

$(".svg_wrap").load("images/system.svg");

 

SVG 파일에서 jquery 사용

SVG 파일에서는 .js 파일 참조 시 src 형식이 아니라 href 형식을 사용해야 한다.

xlink:hrefdeprecated 상태이므로 href 만 쓴다(여기 참고).

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
	<script href="../js/jquery-3.6.0.min.js"></script>
	<!-- 생략 -->
</svg>

 

window.frameElement를 사용하여 SVG 파일을 감싼 부모 엘리먼트에 접근하고 다룰 수 있다.

var wrap = window.frameElement.parentNode.parentNode;
console.log( wrap );
console.log( $(wrap).hasClass("in-view") );

 

하지만 정작 SVG 파일 내에 존재하는 엘리먼트에는 접근할 수 없다(undefined).

  • style : 부모 요소를 지정할 수 없음(SVG 파일 내 요소는 가능)
  • script : 부모 요소를 지정할 수 있음(SVG 파일 내 요소는 불가능)
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <script href="../js/jquery-3.6.0.min.js"></script>
    <style>
        .svg_wrap #moon { fill: #ff0000; }
        #globe { fill: #c0c0c0; }
    </style>
    <script>
        console.log( $("#moon") );
        console.log( $("#moon").attr("cy") );
    </script>
    <circle id="moon" cx="15" cy="285" r="15"/>
    <ellipse id="globe" cx="150" cy="150" rx="145" ry="145" fill="rgba(0,0,0,0)" stroke="rgb(0,0,0)" stroke-width="10"/>
</svg>

 

HTML 파일에서 SVG 파일 내의 엘리먼트 다루기(완성)

결국 inline 방식이 아니라면 SVG 파일 내부에서도, SVG 파일을 삽입한 HTML 파일에서도 css와 js 사용에 제한이 발생하기 때문에 약간의 꼼수를 사용해야 한다.

 

<div class="svg_wrap in-view">
    <img id="svg_system" xmlns="http://www.w3.org/2000/svg" class="svg" src="images/system.svg"/>
</div>
<script>
$(document).ready(function($) {

    //Redo XML
    jQuery("img.svg").each(function() {
        var $img = jQuery(this);
        var imgID = $img.attr("id");
        var imgClass = $img.attr("class");
        var imgURL = $img.attr("src");

        jQuery.get(imgURL, function(data) {
            // Get the SVG tag, ignore the rest
            var $svg = jQuery(data).find("svg");

            // Add replaced image"s ID to the new SVG
            if (typeof imgID !== "undefined") {
                $svg = $svg.attr("id", imgID);
            }
            // Add replaced image"s classes to the new SVG
            if (typeof imgClass !== "undefined") {
                $svg = $svg.attr("class", imgClass+" replaced-svg");
            }

            // Remove any invalid XML tags as per http://validator.w3.org
            $svg = $svg.removeAttr("xmlns:a");

            // Replace image with new SVG
            $img.replaceWith($svg);

        }, "xml");
    });

});

$(window).on("mousewheel", function() {

    if ( $(".svg_wrap").hasClass("in-view") ) {
        $("#svg_system").children().attr("class", "in-view");
    }

});
</script>

SVG 파일을 embed 또는 object 형태로 삽입하지 않고, img 태그를 사용한다.

그리고 스크립트에서 마치 SVG 파일을 inline으로 삽입한 것처럼 각종 속성을 끼워 맞춘다.

그런데 이 경우에도 한 가지 문제는 남아있는데, SVG 파일 내의 엘리먼트에 addClass, removeClass 메서드를 사용할 수 없다.

따라서 attr("class")를 사용하여 클래스를 조정해야 한다.

 

끝.