🎯 やりたかったことは?
実務でSVGを扱っていると、画面の状態に応じて、
「特定の図形だけ色を変えたい」
「クリックされた要素へクラスを付けたい」
「JavaScriptからSVG要素を追加したい」
といった処理が必要になることがあります。
インラインSVGであれば通常のHTML要素と同じようにDOM操作できますが、属性・CSS・名前空間など、SVG特有の部分もあります。
よく使う操作を自分用のチートシートとしてまとめます。
🚀 急いでいる人向け
| やりたいこと | 例 |
|---|---|
| IDで取得 | document.getElementById("samplePath") |
| CSSセレクタで取得 | document.querySelector(".shape") |
| 複数取得 | document.querySelectorAll(".shape") |
| 属性を変更 | element.setAttribute("fill", "red") |
| CSSを変更 | element.style.fill = "red" |
| クラス追加 | element.classList.add("is-selected") |
| クラス切り替え | element.classList.toggle("is-selected") |
| クリックイベント | element.addEventListener("click", handler) |
| SVG要素を作成 | document.createElementNS(SVG_NS, "circle") |
| 要素を削除 | element.remove() |
| SVG座標系のサイズ取得 | element.getBBox() |
| ブラウザ上の位置取得 | element.getBoundingClientRect() |
基本形はこれです。
const path =
document.getElementById("samplePath");
path.setAttribute("fill", "#4CAF50");
path.setAttribute("stroke", "#333");
path.setAttribute("stroke-width", "3");
💡 この記事で分かること
- JavaScriptからSVG要素を取得する方法
-
setAttribute/style/classListの使い分け - SVG要素へクリックイベントを付ける方法
- 複数要素をまとめて操作する方法
- JavaScriptから新しいSVG要素を作る方法
- SVG座標とブラウザ座標の違い
-
<object>や<img>で読み込んだSVGとの違い
今回使用するSVG
次のインラインSVGを操作します。
<svg
id="sampleSvg"
width="320"
height="180"
viewBox="0 0 320 180"
xmlns="http://www.w3.org/2000/svg">
<rect
id="statusRect"
class="shape selectable"
x="20"
y="20"
width="100"
height="60"
rx="8"
fill="#e5e7eb"
stroke="#333"
data-status="normal" />
<circle
id="statusCircle"
class="shape selectable"
cx="210"
cy="50"
r="30"
fill="#e5e7eb"
stroke="#333"
data-status="normal" />
<g id="dynamicArea"></g>
</svg>
SVGをHTMLへ直接書いているため、通常のDOM APIで取得できます。
IDでSVG要素を取得する
const statusRect =
document.getElementById("statusRect");
取得した要素は、通常のHTML要素と同じように操作できます。
statusRect.setAttribute("fill", "#4CAF50");
要素が存在しない可能性がある場合は、先に確認します。
const statusRect =
document.getElementById("statusRect");
if (!statusRect) {
return;
}
statusRect.setAttribute("fill", "#4CAF50");
querySelector で取得する
CSSセレクタを使って取得できます。
const firstShape =
document.querySelector("#sampleSvg .shape");
複数の要素を取得する場合は querySelectorAll を使います。
const shapes =
document.querySelectorAll("#sampleSvg .shape");
shapes.forEach((shape) => {
shape.setAttribute("stroke-width", "3");
});
setAttribute() で属性を変更する
SVGの属性を変更する場合は setAttribute() が分かりやすいです。
const rect =
document.getElementById("statusRect");
rect.setAttribute("fill", "#4CAF50");
rect.setAttribute("stroke", "#1B5E20");
rect.setAttribute("stroke-width", "3");
rect.setAttribute("opacity", "0.8");
座標やサイズも変更できます。
rect.setAttribute("x", "40");
rect.setAttribute("y", "30");
rect.setAttribute("width", "140");
rect.setAttribute("height", "80");
setAttribute() の値は文字列で渡します。
属性を取得する
const fill =
rect.getAttribute("fill");
console.log(fill);
属性を削除する場合は removeAttribute() を使います。
rect.removeAttribute("opacity");
style から変更する
CSSプロパティとして変更することもできます。
rect.style.fill = "#4CAF50";
rect.style.stroke = "#333";
rect.style.strokeWidth = "3";
ハイフン付きのCSSプロパティは、JavaScriptではキャメルケースで書きます。
stroke-width
↓
strokeWidth
ただし、直接 style を変更するとインラインスタイルとして設定されます。
画面状態によって複数の見た目を切り替える場合は、次の classList の方が管理しやすいことがあります。
classList で状態を切り替える
CSSへ見た目をまとめておきます。
.selectable {
fill: #e5e7eb;
stroke: #333;
stroke-width: 2;
}
.selectable.is-selected {
fill: #4CAF50;
stroke: #1B5E20;
stroke-width: 4;
}
JavaScriptではクラスだけ切り替えます。
const rect =
document.getElementById("statusRect");
rect.classList.add("is-selected");
削除する場合は、
rect.classList.remove("is-selected");
切り替える場合は、
rect.classList.toggle("is-selected");
です。
見た目の定義をCSS側へ寄せたい場合は、この方法が使いやすいです。
クリックイベントを登録する
const circle =
document.getElementById("statusCircle");
circle.addEventListener("click", () => {
circle.classList.toggle("is-selected");
});
クリックされた要素は、イベントの currentTarget からも取得できます。
function handleShapeClick(event) {
const shape = event.currentTarget;
shape.classList.toggle("is-selected");
}
circle.addEventListener(
"click",
handleShapeClick
);
複数の要素へ同じ処理を付ける場合に使いやすいです。
document
.querySelectorAll(".selectable")
.forEach((shape) => {
shape.addEventListener(
"click",
handleShapeClick
);
});
SVG全体でイベントを受け取る
要素が多い場合は、SVG全体へイベントを登録する方法もあります。
const svg =
document.getElementById("sampleSvg");
svg.addEventListener("click", (event) => {
if (!(event.target instanceof Element)) {
return;
}
const shape =
event.target.closest(".selectable");
if (!shape || !svg.contains(shape)) {
return;
}
shape.classList.toggle("is-selected");
});
子要素が後から追加された場合でも、親SVG側でイベントを受け取れます。
data-* 属性を使う
SVG要素にも data-* 属性を付けられます。
<rect
id="statusRect"
data-status="normal"
data-item-id="101" />
JavaScriptからは dataset で取得できます。
const rect =
document.getElementById("statusRect");
console.log(rect.dataset.status);
console.log(rect.dataset.itemId);
値を変更する場合は、
rect.dataset.status = "selected";
です。
要素と業務データのIDなどを紐づけたい場合に使えます。
JavaScriptからSVG要素を作成する
SVG要素を作成するときは、SVG用の名前空間を指定します。
const SVG_NS =
"http://www.w3.org/2000/svg";
円を作成する例です。
const circle =
document.createElementNS(
SVG_NS,
"circle"
);
circle.setAttribute("cx", "160");
circle.setAttribute("cy", "120");
circle.setAttribute("r", "20");
circle.setAttribute("fill", "#2196F3");
circle.setAttribute("stroke", "#333");
作成した要素をSVGへ追加します。
const dynamicArea =
document.getElementById("dynamicArea");
dynamicArea.appendChild(circle);
document.createElement("circle") ではなく、
document.createElementNS(
SVG_NS,
"circle"
);
を使うのがポイントです。
作成した要素へイベントを付ける
circle.addEventListener("click", () => {
circle.remove();
});
追加した円をクリックすると、その要素を削除します。
SVG要素を削除する
const rect =
document.getElementById("statusRect");
rect.remove();
親要素から削除する場合は、
rect.parentNode.removeChild(rect);
でも削除できますが、通常は remove() の方が簡単です。
テキストを変更する
<text
id="statusText"
x="20"
y="160">
未選択
</text>
const statusText =
document.getElementById("statusText");
statusText.textContent = "選択済み";
文字色も変更できます。
statusText.setAttribute(
"fill",
"#4CAF50"
);
getBBox() でSVG座標系のサイズを取得する
const rect =
document.getElementById("statusRect");
const box =
rect.getBBox();
console.log(box.x);
console.log(box.y);
console.log(box.width);
console.log(box.height);
getBBox() は、SVG内部の座標系を基準にした境界情報を取得するときに使います。
x
y
width
height
を取得できます。
getBoundingClientRect() でブラウザ上の位置を取得する
const clientRect =
rect.getBoundingClientRect();
console.log(clientRect.left);
console.log(clientRect.top);
console.log(clientRect.width);
console.log(clientRect.height);
こちらはブラウザの表示領域を基準にした座標です。
整理すると、
| メソッド | 主な基準 |
|---|---|
getBBox() |
SVG内部の座標系 |
getBoundingClientRect() |
ブラウザの表示領域 |
マウス座標との比較や画面上の位置取得では、getBoundingClientRect() を使うことが多いです。
属性・style・classの使い分け
自分の場合は、だいたい次のように分けています。
| 方法 | 向いている用途 |
|---|---|
setAttribute() |
座標・サイズ・個別属性の変更 |
element.style |
一時的なインラインCSS変更 |
classList |
状態ごとの見た目切り替え |
dataset |
要素に補助情報を持たせる |
例えば、選択状態の見た目なら classList。
shape.classList.add("is-selected");
座標を変更するなら setAttribute()。
shape.setAttribute("x", "100");
という形にすると整理しやすいです。
⚠️ インラインSVG以外は取得方法が違う
この記事の例は、HTMLへ直接書いたインラインSVGです。
<svg>
...
</svg>
この場合は、
document.querySelector(...)
で直接取得できます。
一方、次のような読み込み方では扱いが変わります。
img要素
<img src="sample.svg" alt="">
img 要素として読み込んだSVGの内部要素は、親ページのJavaScriptから直接取得できません。
object要素
<object
id="svgObject"
type="image/svg+xml"
data="sample.svg">
</object>
object の場合は、読み込み完了後に contentDocument などを経由して内部SVGへアクセスします。
この方法は別の記事で整理します。
⚠️ CSSに上書きされていないか確認する
JavaScriptから、
element.setAttribute("fill", "red");
としても、CSS側の指定によって想定した色にならないことがあります。
特に、
.shape {
fill: blue;
}
のような指定がある場合は、DevToolsで最終的にどのスタイルが適用されているか確認します。
状態切り替えが目的なら、JavaScriptから値を直接書くより、クラスを切り替える方が追いやすいことがあります。
📝 まとめ
JavaScriptからSVGを操作するときは、まず次を覚えておけば大体対応できます。
要素取得
→ querySelector / getElementById
属性変更
→ setAttribute
見た目の切り替え
→ classList
イベント
→ addEventListener
要素作成
→ createElementNS
SVGもDOMとして操作できるため、基本的な考え方はHTML要素と同じです。
ただし、新しいSVG要素を作るときの名前空間や、object / img で読み込んだ場合の違いは忘れやすいところでした。
自分も実装時にすぐ確認できるよう、よく使う操作をまとめておきます。