速報

X.Orgのクライアントライブラリーで17件を修正!Linux端末と画像処理の利用範囲を点検

CATEGORY

【GSAP】MorphSVGで図形を滑らかに変える|パスの対応と破綻を防ぐ設計

※本ページのリンクにはプロモーションが含まれています。

濃い背景に配置したGSAP公式ブランドロゴ

目次

情報確認日:2026年10月16日。GSAP公式資料を参照した、本サイト独自の実装例です。

四角形からひし形へ変わる小さな例を通じて、MorphSVGのパス補間とshapeIndexの役割を整理します。座標系の合わせ方、切り替え連打、復元、形だけに意味を預けない設計まで扱います。

スポンサーリンク

移動ではなく輪郭そのものを変える

transformで回転すれば四角形をひし形に見せられます。しかし、別の輪郭へ連続して変える表現では、SVGのd属性が表す形そのものを補間する必要があります。MorphSVGはこの用途のためのプラグインです。このサンプルは仕組みを追いやすくするため、どちらも閉じた四頂点の図形を使います。

ここでの目的は装飾です。実際の商品の形や面積、測定値の変化を正確に示す図ではありません。グラフや地図に同じ手法を使うなら、途中形状の意味まで検討する必要があります。滑らかに動くことと、情報が正確であることは別の評価軸です。

最初にviewBoxと位置を揃える

SVGを別々のデザインファイルから書き出すと、同じ見た目の大きさでも座標の原点や余白が異なることがあります。その状態でパス文字列だけを渡すと、変形と一緒に位置やサイズも変わり、意図せず飛び跳ねたように見えます。素材を同じviewBoxへ揃える工程を先に設けます。

この例は200四方の座標に二つの輪郭を置いています。CSS上の幅を変えても、両方が同じ座標系にあるという前提は保たれます。パスを別のSVGから持ち込むときは、見た目だけでなく、transform属性による変換が残っていないかも確認してください。

スポンサーリンク

shapeIndexは点の対応を調整する

輪郭の補間では、出発点と到着点をどの順番で対応させるかが重要です。対応がずれると途中で輪郭が交差したり、必要以上にねじれたりします。公式資料のshapeIndexは、この対応を調整するための指定です。まずautoで確認し、必要な素材だけ調整すると扱いやすくなります。

shapeIndexは閉じたパスで使う設定です。開いた線を同じ感覚で直せるとは考えません。また、一つの輪郭から穴のある複雑な図形へ変える場合は、対応を変えるだけで見栄えが解決するとは限りません。素材を分割するか、フェードで切り替える方が明快なこともあります。

連打時の方針を明確にする

この例では、クリックを受けたら直前のTweenを終点まで進め、止めてから次の状態へ切り替えます。これにより、途中の不定形を新しい出発点として積み重ねません。一方、動作中のクリックでは小さく跳ぶ可能性があります。連続した見た目を最優先する実装では、この方針を変更する必要があります。

インターフェースの状態はdiamondという変数で管理し、aria-pressedと文章へ反映しています。形の補間が終わるまで状態の確定を待つ設計にはしていません。決済や保存の完了を示す場合は、アニメーションではなく実際の処理結果から状態を更新してください。

スポンサーリンク

復元は元のパスデータを基準にする

初期化時に元のd属性を取得し、リセット時は進行中のTweenを止めてから戻します。補間後の値を初期値として再取得すると、繰り返し操作で基準が変わってしまいます。元の値と現在の状態を分けて保持することが、追いやすい実装につながります。

今回はpathから始めています。rectやcircleなどを公式のconvertToPathで変換する構成では、元のDOM要素がパスへ置き換わります。変換前に保存した参照を使い続けず、返された要素や変換後の要素を対象にします。イベントや別のライブラリが元要素を参照していないかも確認します。

複雑な素材は初期化と描画を別々に調べる

パスの解析や点の対応には開始時の計算があり、その後には輪郭を毎フレーム描く処理があります。初期化を軽くする工夫が、そのまま描画全体の改善になるとは限りません。多数のアンカー、影、フィルターを含む素材は、小さい表示でも実機で測定します。

最初に二つの単純な輪郭で成立するか確認し、素材の精度を必要な範囲へ絞ります。複数の要素を同時に変形させる場合は、画面に入っていない要素まで常時動かさない設計も検討します。見た目が同じなら、より単純な素材の方が保守しやすい場合があります。

動きを減らしても意味が残るか確認する

prefers-reduced-motionでは所要時間を0にし、形と文章をすぐに更新します。SVG自体は装飾として読み上げ対象から外し、現在の状態は別の文章で伝えます。色の違いだけ、輪郭の違いだけで意味が決まらない構成にしています。

確認では、初期表示、往復、連打、途中リセット、狭い画面、動きを減らす設定を試します。変形途中に意図しない交差がないかは実ブラウザーで目視します。公開時点で素材や座標系が変わった場合も、完成形だけでなく途中形状を再確認してください。

実装例と配置するファイル

npmパッケージを解決できる既存のViteなどの環境で npm install gsap を実行してください。HTMLはbody内、CSSはスタイルシート、JavaScriptはmain.jsへ置き、body末尾からtype="module"でmain.jsを読み込みます。WordPress本文でコードを実行する例ではなく、開発環境で動かすためのサンプルです。

<section class="morph-demo">
  <svg viewBox="0 0 200 200" aria-hidden="true"><path id="shape" d="M40,40 L160,40 L160,160 L40,160 Z" /></svg>
  <button id="toggle" type="button" aria-pressed="false">形を切り替え</button>
  <button id="reset" type="button">初期状態へ戻す</button>
  <p id="state" role="status">現在の形:四角形</p>
</section>
.morph-demo { max-width:30rem; margin:2rem auto; padding:1rem; }
.morph-demo svg { display:block; width:100%; max-width:20rem; }
#shape { fill:#7950c8; }
.morph-demo button { padding:.8rem; margin:.3rem; }
.morph-demo button:focus-visible { outline:3px solid #253b91; }
import { gsap } from "gsap";
import { MorphSVGPlugin } from "gsap/MorphSVGPlugin";
gsap.registerPlugin(MorphSVGPlugin);
const shape = document.querySelector("#shape");
const button = document.querySelector("#toggle");
const status = document.querySelector("#state");
const squareD = shape.getAttribute("d");
const diamondD = "M100,20 L180,100 L100,180 L20,100 Z";
let diamond = false, current;
function describe() {
  button.setAttribute("aria-pressed", String(diamond));
  status.textContent = `現在の形:${diamond ? "ひし形" : "四角形"}`;
}
button.addEventListener("click", () => {
  current?.progress(1);
  current?.kill();
  diamond = !diamond;
  current = gsap.to(shape, {
    morphSVG: { shape: diamond ? diamondD : squareD, shapeIndex: "auto" },
    fill: diamond ? "#147d7c" : "#7950c8",
    duration: matchMedia("(prefers-reduced-motion: reduce)").matches ? 0 : 0.8,
    ease: "power2.inOut", overwrite: "auto"
  });
  describe();
});
document.querySelector("#reset").addEventListener("click", () => {
  current?.kill();
  gsap.set(shape, { attr: { d: squareD }, fill: "#7950c8" });
  diamond = false;
  describe();
});

スポンサーリンク

公開前の確認

掲載コードはGSAP 3.15.0を用いたDOM模擬環境で初期化と主要操作を確認しています。実ブラウザーの描画、フォントの改行、タッチの挙動、支援技術による読み上げは別途確認が必要です。開発用の環境だけでなく、対象端末と本番用ビルドで、初期表示・連打・停止・画面の再表示を確認してください。

参考資料

この記事を書いた人

Ryohei

Webエンジニア / アプリ開発者 / 技術ブログ運営者

福岡のWeb制作会社に勤務するWebエンジニアです。10年以上にわたりWeb制作・開発に携わり、これまでに100以上のWordPressサイトの構築・保守を担当してきました。Webサイト制作に加え、アプリ開発やAIを活用した開発にも取り組み、近年はWebセキュリティにも注力しています。

2015年から技術メディア「Into the Program」を運営し、実務や開発で得た知識をもとに、プログラミングの実装方法やWebサイトの運用・セキュリティ情報を発信しています。

主な分野
WordPress / PHP / JavaScript / アプリ開発 / Webサイトの運用・セキュリティ対策
資格・試験合格
情報セキュリティマネジメント試験
基本情報技術者試験
AWS認定ソリューションアーキテクト アソシエイト
メディア運営
2015年〜

記事の作成・更新について

セキュリティ記事は、ベンダーの公式アドバイザリやCVE・JVNなどの一次情報を参照し、出典と情報確認日を記載します。実環境での検証を行った場合は、その環境と確認範囲を明示します。重要な追加情報や誤りを把握した場合は、内容を確認して追記・訂正します。

スポンサーリンク

関連する記事

おすすめの書籍