SVG SVGエディタにドラッグ&ドロップと
ファイル読み込み機能を追加した

前回、ブラウザで動くSVGエディタを作りました。
コードを書くとリアルタイムでプレビューが更新され、プレビュー側からも編集できる便利なツールです。

しかし実際に使ってみると、既存のSVGファイルを編集したいときに不便さを感じました。
いったんエディタで表示してからコードをコピー&ペーストするのは手間がかかります。

そこで今回は、SVGファイルを直接読み込める機能を2つ追加しました。
ドラッグ&ドロップとファイル選択ボタンです。

<svg class="eyecatch-svg" viewBox="0 0 192 192" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!-- ファイルアイコン -->
    <symbol id="icon-file" viewBox="0 0 64 80">
      <path d="M 4,0 L 44,0 L 60,16 L 60,76 C 60,78 58,80 56,80 L 8,80 C 6,80 4,78 4,76 Z" 
            fill="white" stroke="#2196F3" stroke-width="3" stroke-linejoin="round"/>
      <path d="M 44,0 L 44,16 L 60,16" 
            fill="none" stroke="#2196F3" stroke-width="3" stroke-linejoin="round"/>
      <!-- SVG文字 -->
      <text x="32" y="48" font-family="Arial, sans-serif" font-size="16" font-weight="bold" 
            fill="#2196F3" text-anchor="middle">SVG</text>
    </symbol>
    
    <!-- ドラッグ矢印 -->
    <symbol id="icon-arrow" viewBox="0 0 60 60">
      <path d="M 10,30 L 45,30 M 35,20 L 45,30 L 35,40" 
            fill="none" stroke="#FF9800" stroke-width="4" 
            stroke-linecap="round" stroke-linejoin="round"/>
      <circle cx="5" cy="30" r="4" fill="#FF9800"/>
    </symbol>
    
    <!-- フォルダアイコン -->
    <symbol id="icon-folder" viewBox="0 0 80 64">
      <path d="M 4,8 L 28,8 L 36,16 L 72,16 C 74,16 76,18 76,20 L 76,56 C 76,58 74,60 72,60 L 8,60 C 6,60 4,58 4,56 Z" 
            fill="#4CAF50" stroke="#2E7D32" stroke-width="3" stroke-linejoin="round"/>
    </symbol>
  </defs>
  
  <!-- 背景 -->
  <rect width="192" height="192" fill="white" rx="32" ry="32"/>
  
  <!-- フォルダ(左側) -->
  <g transform="translate(20, 90)">
    <use href="#icon-folder" width="60" height="48"/>
  </g>
  
  <!-- ドラッグ矢印(中央) -->
  <g transform="translate(66, 80)">
    <use href="#icon-arrow" width="60" height="60"/>
  </g>
  
  <!-- SVGファイル(右側) -->
  <g transform="translate(108, 70)">
    <use href="#icon-file" width="64" height="80"/>
  </g>
  
  <!-- アクセント:点線の軌跡 -->
  <path d="M 50,114 Q 96,100 132,110" 
        fill="none" stroke="#E0E0E0" stroke-width="2" 
        stroke-dasharray="4,4" opacity="0.5"/>
</svg>SVGエディタにドラッグ&ドロップと<br class="chiilabo-br is-on">ファイル読み込み機能を追加した

関連記事

1. なぜファイル読み込み機能が必要だったのか

エディタを実際に使い始めると、すぐに課題が見えてきました。
既存のSVGファイルを編集するとき、まずファイルをテキストエディタで開き、内容を全選択してコピーし、ブラウザに戻ってペーストする必要があります。
この作業を何度も繰り返すうちに、もっと直接的な方法がほしくなりました。

理想は、ファイルをエディタに渡すだけで読み込みが完了することです。
現代のWebアプリケーションでは、ドラッグ&ドロップが標準的なUIになっています。
ファイルをブラウザにドロップすれば開ける。この体験を実現したいと考えました。

2. ドラッグ&ドロップ機能の実装

ブラウザでドラッグ&ドロップを実装するには、3つのイベントを扱います。

  • dragoverはファイルがエリア上にある状態、
  • dragleaveはエリアから離れた状態、
  • そしてdropが実際にファイルをドロップした瞬間です。

最初に気をつけたのは、ブラウザのデフォルト動作を止めることでした。
通常、SVGファイルをブラウザにドロップすると、そのファイルを新しいタブで開いてしまいます。
これを防ぐため、各イベントでpreventDefault()を呼びます。

function handleDragOver(e) {
  e.preventDefault();
  e.stopPropagation();
  // 視覚的フィードバック
  DOM.codeInput.style.background = '#1a1a1a';
  DOM.codeInput.style.opacity = '0.8';
}Code language: JavaScript (javascript)

2.1. 視覚的なフィードバック

ドラッグ中は、コードエリアの背景色を少し明るくしました。
ユーザーは「ここにドロップできる」と視覚的に理解できます。
ファイルがエリアから離れると、元の暗い背景に戻ります。この変化があるだけで、操作の手応えが大きく変わりました。

CSSにはtransitionプロパティを追加し、色の変化を滑らかにしています。

2.2. ファイルの読み込み処理

ドロップされたファイルはe.dataTransfer.filesで取得できます。
まずファイルが本当にSVGかどうかを確認しました。
拡張子が.svgであるか、MIMEタイプがimage/svg+xmlであることをチェックします。

if (!file.name.endsWith('.svg') && file.type !== 'image/svg+xml') {
  DOM.errorMessage.textContent = 'SVGファイルのみ対応しています';
  DOM.errorMessage.style.display = 'block';
  return;
}Code language: JavaScript (javascript)

ファイルの内容を読むにはFileReaderを使います。
readAsText()メソッドでファイルをテキストとして読み込み、onloadイベントで結果を受け取ります。
ここで前回実装したupdateSVG()関数を呼ぶと、プレビューが自動的に更新されます。

2.3. SVG2への対応

読み込んだSVGコードには、古い記法が含まれている場合があります。
特にxlink:href属性は、SVG2では単なるhrefに置き換えられました。
互換性を保つため、正規表現で自動的に変換します。

text = text.replace(/xlink:href\s*=/g, 'href=');
text = text.replace(/\s+xmlns:xlink="http:\/\/www\.w3\.org\/1999\/xlink"/g, '');Code language: JavaScript (javascript)

この処理により、古いSVGファイルでもエラーなく読み込めるようになりました。

3. ファイル選択ボタンの追加

ドラッグ&ドロップは直感的ですが、すべてのユーザーがこの操作に慣れているわけではありません。
特にファイルマネージャーを開いていない状態では、ドラッグ&ドロップは使いにくいものです。

そこで従来型のファイル選択ボタンも追加することにしました。

3.1. hidden inputの活用

HTML5の<input type="file">要素は、標準のファイル選択機能を提供します。
しかしデフォルトのデザインは、エディタの見た目と合いません。
そこで、input要素自体はdisplay: noneで隠し、代わりにスタイルを整えたボタンを配置しました。

<input type="file" id="file-input" accept=".svg,image/svg+xml" style="display: none;">
<button class="copy-btn" id="load-file-btn">📁 Load SVG File</button>Code language: HTML, XML (xml)

ボタンをクリックすると、JavaScriptで隠しているinput要素のclick()メソッドを呼びます。
これによりファイル選択ダイアログが開きます。
デザインの自由度を保ちながら、標準機能を活用できる方法です。

3.2. ファイル選択後の処理

input要素のchangeイベントで、選択されたファイルを受け取ります。
処理内容はドラッグ&ドロップと同じです。
SVGファイルかチェックし、FileReaderで読み込み、コードを置き換えてプレビューを更新します。

一つ工夫したのは、処理が終わった後にinput要素の値をリセットすることです。
e.target.value = ''を実行すると、同じファイルを再度選択できるようになります。
これがないと、一度選んだファイルをもう一度選ぼうとしてもchangeイベントが発火しません。

3.3. ボタンの配置とフィードバック

新しいボタンは、「Paste & Replace」の左側に配置しました。
左から順に「Load SVG File」「Paste & Replace」「Copy All」と並びます。

ファイル読み込みに成功すると、ボタンのテキストが「✓ Loaded: ファイル名」に変わります。
2秒後に元の表示に戻ります。この一時的な変化により、ユーザーは操作が成功したことを確認できます。

4. 実装して気づいたこと

ファイル操作では、予期しない問題が起きやすいものです。ファイルが壊れている、形式が違う、読み込み権限がない。
さまざまなケースを想定する必要がありました。

エラーメッセージは、画面上部に赤い背景で表示されます。
3秒後に自動的に消えるため、ユーザーの操作を妨げません。
エラーの内容も具体的に伝えるよう心がけました。
「ファイルの読み込みに失敗しました」だけでなく、「SVGファイルのみ対応しています」と書くことで、ユーザーは何が問題だったのかを理解できます。

5. まとめ

既存のSVGエディタに、ファイル読み込み機能を追加しました。ドラッグ&ドロップで直感的に、ボタンで確実に。どちらの方法でもSVGファイルを開けるようになり、実用性が大きく向上しました。

実装自体はシンプルでしたが、細部の配慮が使いやすさを左右することを実感しています。視覚的なフィードバック、エラーメッセージの内容、ボタンの配置。小さな積み重ねが、ツール全体の完成度を高めていきます。

このエディタは、まだまだ改善の余地があります。次は何を追加しようか。使いながら考えるのが楽しみです。