SVG이미지의 특징은 xml로 되어있어, 각 요소들에 대한 접근이 가능하다는 것이다.
일반적인 비트맵이미지로는 수행할 수 없는 엘리먼트 단위의 제어등이 가능하다. (특정 Path의 색상만을 바꾼다던지, 크기를 변경한다던지, 보이지 않게 한다던지 등..)
여러가지 프레임워크들이 이 SVG이미지를 지원하며, 여러 방법으로 제어할 수 있게 되어있다.
이 글은 JS에서 제공하는 SVG처리방법, 그리고 React에서 그것을 사용하는 방법에 대한 기록이다. 특히, svg의 엘리먼트에 접근하는 것에 중점을 둔다.
SVG파일 하나만으로 여러 작업을 수행할 수 있도록, SVG파일 내의 엘리먼트등을 자유롭게 조작할 수 있게 하는 것.
연습을 위한 목표 사양
ReactSVG 모듈을 통하여 SVG가 DOM에 로드가 완료되었을때의 시점에 접근을 할 수 있다.ReactSVG 컴포넌트의 afterInjection 어트리뷰트의 svg가 DOM에 로드가 완료된 SVG의 SVGSVGElement타입이며, 이 것을 이용하여 Element에 접근할 수 있다.SVGSVGElement의 classList에 추가되는 문자열은 CSS에서 접근할 수 있는 class가 된다.How to import a svg file in javascript
위 링크에서 말하는 내용은 다음과 같다.
img 태그로 가져올 수 있다.
매우 간편하지만, 이 경우 SVG파일의 엘리먼트 조작이 안된다. 즉, SVG이미지를 사용하는 의미가 퇴색된다.
object 태그로 가져올 수 있다.
type을 image/svg+xml로 하여 가져올 수 있다.
이 방법만이 위 사이트에서 제시하는 유일한 엘리먼트가 조작 가능한 SVG import 타입이다.
iframe 태그로 가져올 수 있다.
하지만 이 방법은 SVG의 엘리먼트를 가져올수도, 성능도 나빠 위 사이트에서는 전혀 추천하지 않는 방법이다.
하기 코드는 위 링크에 기재된 예시 코드이다.
다음으로 구분되어있다.
<!DOCTYPE html>
<html lang="en">
<body>
<object type="image/svg+xml"
data=
"https://media.geeksforgeeks.org/wp-content/cdn-uploads/20210205161739/Screenshot-2021-02-05-161721.png"
class="logo">
GFG Logo
</object>
</body>
</html>
이를 예시로서, 다음과 같이 구현하였다.
import kr_map from './kr.svg'
import React from 'react'
export default class map extends React.Component {
render(){
return <object
type = "image/svg+xml"
className = "main_map"
data = {kr_map}
></object>
}
}
해당 코드는 동작한다.
CSS가 조금 다르게 동작하지만, 동작 자체는 확인하였다.
img와 class는 다음과 같은 CSS환경에서 다르게 동작한다.
.main_map {
width: 100%;
height: auto;
}

img 태그에서 의도한 그대로 동작하는 모습
object 태그에서 조금 이상하게 동작하는 모습다음과 같은 방식으로 가져올 수 있다. 상기 링크를 참조하여 엘리먼트를 조작할 수 있게 코드를 바꾸어본다.
object 안의 무언가를 엘리먼트로 빼올 수 있을지 판단하기 위해 다음과 같은 코드를 작성하였다.
import kr_map from './kr.svg'
import React from 'react'
export default class map extends React.Component {
constructor(props){
super(props);
this.state = {
map_img : <object type = "image/svg+xml" className = "main_map" data = {kr_map}></object>
}
console.log(this.state.map_img)
}
render(){
return this.state.map_img;
}
}
[HMR] Waiting for update signal from WDS...
오류가 발생한다.
오류 해결 방법
오류를 해결하니 다음과 같은 결과를 준다.

단순한 React Element이며, SVG의 엘리먼트는 딱히 뺄 수 있을 것 같아보이지 않는다.
당연한 바이지만, React에서는 render()를 호출하기 전에는 DOM에 추가하지 않기 때문에, 다음과 같은 코드로는 목적을 달성할 수 없다.
constructor(props){
super(props);
this.state = {
map_img : <object type = "image/svg+xml" className = "main_map" data = {kr_map}></object>
}
//render()를 호출한 이후에 DOM에 추가되는데,
//constructor에서 호출하면 아무것도 불러올 수 없다.
console.log(document.getElementById("KOR2494"));
}
상기 기재된 방식은 SVG이미지가 object로 추가된 이후에 접근할 수 있는 방식인데, React특성상 render()가 호출이 되어야만 해당 컴포넌트가 DOM에 추가된다.
그리고 사실 render()를 호출한 직후에 컴포넌트가 DOM에 추가되는 것도 아니다. (여러 컴포넌트들의 render()를 모아서 한번에 추가함)
따라서 상기 방법으로 해결될 것으로 보이지는 않는다.
직접 수행해보려고 하였으나, 상기 작업으로 수행하는 것은 굉장히 번거로운것을 떠나 실행 가능성조차 희박하므로, 최적화된 라이브러리를 사용해서 원하는 작업을 수행하려고 한다.
이 모듈은 방금 상기 시도에서 좌절되었던 SVG가 DOM에 추가되기 전 / 추가된 후에 작업을 정해놓고, 수행할 수 있게 한다.
상기 링크의 설명서를 참고하여, 다음과 같이 작성하였다.
import kr_map from './kr.svg'
import React from 'react'
import { ReactSVG } from 'react-svg'
export default class map extends React.Component {
render(){
return <ReactSVG
afterInjection = {(error, svg) => {
if (error) {
console.error(error);
return;
}
console.log(svg);
}
}
src = {kr_map}
></ReactSVG>
}
}
console.log(svg)를 통하여, svg는 완벽하게 svg를 읽은 결과가 된다!
svg의 타입은 SVGSVGElement 라고 한다.
이 svg의 자식 element를 갖고 오려면
NodeListOf< ChildNode >)HTMLCollection)다음 링크에서는 어떻게 SVG엘리먼트에 CSS스타일을 적용시킬 수 있는지 기재되어있다.
다음 링크를 통하여 이벤트를 어떻게 넣는지 알 수 있다.
관련하여, 다음과 같이 코드를 작성하였다.
import kr_map from './kr.svg'
import React from 'react'
import { ReactSVG } from 'react-svg'
export default class map extends React.Component {
render(){
return <ReactSVG
afterInjection = {(error, svg) => {
if (error) {
console.error(error);
return;
}
svg.classList.add('region');
}
}
src = {kr_map}
></ReactSVG>
}
}
이 작업으로 인하여, svg의 class는 region이 되었다.
이 classList에 부여한 class이름은 CSS에서 적용된다.
svg파일은 다음과 같이 수정하였다.
<svg baseprofile="tiny" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" version="1.2" xmlns="http://www.w3.org/2000/svg">
<path d="M372.9 ... 이후 생략"/>
주요 변경점
CSS파일은 다음과 같이 수정하였다.
.region {
position:relative;
fill:blueviolet;
transition-duration: .2s;
z-index: 0;
}
.region :hover{
fill:crimson;
transition-duration: .2s;
z-index: 1;
}
주요 변경점
상기의 의도한 CSS설정과 완전히 다르게 동작하는 SVG에 대한 항목이다.
다음 링크를 통해서, SVG파일의 ViewBox와 ViewPort에 대해 알 수 있다.
주요 요점은 다음과 같다.
ViewBox는 SVG가 보일 영역을 지정할 수 있게 한다.ViewPort는 ViewBox와 비슷하지만, Pan과 Zoom이 가능하다는 특징이 있다.Pan과 Zoom의 기능은 뒤로 하고, 현재는 SVG의 영역을 지정해주는것에만 집중한다.
ViewBox를 시도하는 경우, 다음과 같이 수정한다.<svg viewBox = "0 0 1000 1300" 이하생략 >
<path>...</path>
</svg>
결과
지원함.
윈도우 사이즈에 영향을 받음

ViewPort를 시도하는 경우, 다음과 같이 수정한다.
<svg width = "1000" height = "1300" 이하생략 >
<path>...</path>
</svg>
결과

ViewBox와 ViewPort를 혼용하는 것으로 Zoom등이 가능하게 된다고 기재되어있다.import kr_map from './kr.svg'
import React from 'react'
import { ReactSVG } from 'react-svg'
export default class map extends React.Component {
constructor(props){
super(props);
}
render(){
return <ReactSVG
afterInjection = {(error, svg) => {
if (error) {
console.error(error);
return;
}
svg.setAttribute('width','1000');
svg.setAttribute('height','1300');
svg.setAttribute('viewBox','0 0 1000 1300');
svg.setAttribute('preserveAspectRatio',"xMinYMin meet");
svg.classList.add('region');
}
}
src = {kr_map}
></ReactSVG>
}
}
SVG xml코드를 통째로 가져오는 방법도 존재한다고 한다.
그 외에도 여러가지 모듈이 있는데,
이 중에서는 SVG 엘리먼트를 각기 다른 컴포넌트로 취급할 수 있는 패키지도 있다고 한다.