質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

1738閲覧

[HTML5]Canvasで画像をズームイン・アウト、ドラッグで移動させる方法をローカルファイルで行いたい

taroj

総合スコア1

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2021/01/25 07:57

編集2021/01/25 20:53

前提・実現したいこと

[HTML5]Canvasで画像をズームイン・アウト、ドラッグで移動させる方法
という記事を参考にJavaScriptを学習しています。

発生している問題・エラーメッセージ

画像URLの代わりにローカルファイルから画像を読み込んで、
画像をズームイン・アウト、ドラッグできないかと思い3日ほど試しているのですが、

画像URLをローカルファイルにすることができずにいます。

該当のソースコード

<form class="container"> <h2>Input</h2> <input type="text" id="image-url" value="https://ja.wikipedia.org/static/images/project-logos/jawiki.png"> <button type="button" id="load">load</button> <h2>How to use</h2> <ol> <li>画像URLを入力し、loadボタンで画像を読み込む(※ CORSが許可されている画像のみ)</li> <li>zoom-in, zoom-out, ドラッグ&ドロップで画像を編集する</li> <li>exportボタンで画像を出力する</li> </ol> </form> <div class="container"> <h2>Editor</h2> <div class="form"> <button type="button" id="export">export</button> </div> <div id="edit-image"></div> </div> <div class="container"> <h2>Output</h2> <div id="output-image"></div> </div> <div class="upload"><input type="file" name="file" id="file"></div> <div id="result"></div> <script type="text/javascript"> var file = document.getElementById('file'); var result = document.getElementById('result'); function loadLocalImage(e) { // ファイル情報を取得 var fileData = e.target.files[0]; // 画像ファイル以外は処理を止める if(!fileData.type.match('image.*')) { alert('画像を選択してください'); return; } // FileReaderオブジェクトを使ってファイル読み込み var reader = new FileReader(); // ファイル読み込みに成功したときの処理 reader.onload = function() { // ブラウザ上に画像を表示する var img = document.createElement('img'); img.src = reader.result; result.appendChild(img); } // ファイル読み込みを実行 reader.readAsDataURL(fileData); } // ファイルが指定された時にloadLocalImage()を実行 file.addEventListener('change', loadLocalImage, false); class ImageEditor { /** * Canvas操作 * @param {Object} opt * @param {string} opt.imageSrc イメージのURL * @param {string} opt.canvasId canvasタグのid(デフォルト: image-for-edit) * @param {Number} opt.canvasSize canvasのサイズ(デフォルト: 128px) * @param {Number} opt.scaleStep 拡大縮小の倍率(デフォルト: 0.25) */ constructor(opt = {}) { this.src = opt.imageSrc || 'https://ja.wikipedia.org/static/images/project-logos/jawiki.png'; this.id = opt.canvasId || 'image-for-edit'; this.size = opt.canvasSize || 128; this.scaleStep = opt.scaleStep || 0.25; this.scale = 1; this.dragInfo = { isDragging: false, startX: 0, startY: 0, diffX: 0, diffY: 0, canvasX: 0, canvasY: 0 }; } /** * canvasを挿入する * @param {HTMLElement} el canvasを挿入する親要素 * @return {void} */ insertTo(el) { const container = document.createElement('div'); el.appendChild(container); // slider const zoomSlider = document.createElement('input'); zoomSlider.type = 'range'; zoomSlider.min = 0.01; zoomSlider.max = 2; zoomSlider.value = 1; zoomSlider.step = 'any'; zoomSlider.addEventListener('input', this.zoom.bind(this)); container.appendChild(zoomSlider); // canvas this.canvas = document.createElement('canvas'); this.ctx = this.canvas.getContext('2d'); this.canvas.id = this.id; this.canvas.width = this.canvas.height = this.size; this.img = new Image(); this.img.crossOrigin = 'anonymous'; // 「Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.」というエラーになるため this.img.src = this.src; this.img.onload = () => { this.ctx.drawImage(this.img, 0, 0); }; this.img.onerror = e => { [...el.children].forEach(a => a.remove()); alert('画像読み込み失敗'); }; // mouse event this.canvas.addEventListener('mousedown', this.dragStart.bind(this)); this.canvas.addEventListener('mousemove', this.drag.bind(this)); this.canvas.addEventListener('mouseup', this.dragEnd.bind(this)); el.appendChild(this.canvas); } /** * 再描画する * @private * @return {void} */ _redraw() { // canvasをクリア this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // リサイズ this.ctx.scale(this.scale, this.scale); // 再描画 this.ctx.drawImage(this.img, this.dragInfo.diffX, this.dragInfo.diffY); // 変形マトリクスを元に戻す this.ctx.scale(1 / this.scale, 1 / this.scale); } /** * 拡大/縮小する * @param {Event} event イベント * @return {void} */ zoom(event) { this.scale = event.target.value; this._redraw(); } /** * 拡大(ズームイン)する * @return {void} */ zoomIn() { this.scale += this.scaleStep; this._redraw(); } /** * 縮小(ズームアウト)する * @return {void} */ zoomOut() { this.scale -= this.scaleStep; this._redraw(); } /** * ドラッグ開始 * @param {MouseEvent} event マウスイベント * @return {void} */ dragStart(event) { this.dragInfo.isDragging = true; this.dragInfo.startX = event.clientX; this.dragInfo.startY = event.clientY; } /** * ドラッグで画像を移動する * @param {MouseEvent} event マウスイベント * @return {void} */ drag(event) { if (this.dragInfo.isDragging) { // 開始位置 + 差分 / スケール (画像の大きさによる移動距離の補正のためスケールで割る) this.dragInfo.diffX = this.dragInfo.canvasX + (event.clientX - this.dragInfo.startX) / this.scale; this.dragInfo.diffY = this.dragInfo.canvasY + (event.clientY - this.dragInfo.startY) / this.scale; this._redraw(); } } /** * ドラッグ終了 * @param {MouseEvent} event マウスイベント * @return {void} */ dragEnd(event) { this.dragInfo.isDragging = false; // mousedown時のカクつきをなくすため this.dragInfo.canvasX = this.dragInfo.diffX; this.dragInfo.canvasY = this.dragInfo.diffY; } /** * canvasを出力する * @return {Canvas} */ getCanvas() { return this.canvas; } /** * imgを出力する * @return {Image} */ getImage() { const img = new Image(); const data = this.canvas.toDataURL('image/png'); img.src = data; return img; } } function createImageEditor() { const input = document.getElementById('image-url'); const editImage = document.getElementById('edit-image'); if (editImage.hasChildNodes()) { // clear [...editImage.children].forEach(a => a.remove()); } const imageEditor = new ImageEditor({ imageSrc: input.value, canvasSize: 128 }); imageEditor.insertTo(editImage); // イベントを上書きする document.getElementById('export').onclick = () => { document.getElementById('output-image').appendChild(imageEditor.getImage()); }; } // ファイルが指定された時にloadLocalImage()を実行 file.addEventListener('change', createImageEditor, false); </script>

試したこと

input.valueの値をFileAPIの値に変更することが出来ません。

補足情報(FW/ツールのバージョンなど)

https://kuroeveryday.blogspot.com/2017/09/zoom-in-out-and-drag-to-move-on-canvas.html
の【完成!!】を参考に行っていました。

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

int32_t

2021/01/25 08:09

> input.valueの値をFileAPIの値に変更することが出来ません。 具体的に、どういうコードを書いて何が起きましたか?
taroj

2021/01/25 10:34

int32tさんありがとうございます。 学習中で悩んでいるのですが、 htmlのinputタグでファイルを読み込んで、 下のような var file = document.getElementById('file'); var canvas = document.getElementById('canvas'); var canvasWidth = 400; var canvasHeight = 300; var uploadImgSrc; // Canvasの準備 canvas.width = canvasWidth; canvas.height = canvasHeight; var ctx = canvas.getContext('2d'); function loadLocalImage(e) { // ファイル情報を取得 var fileData = e.target.files[0]; // 画像ファイル以外は処理を止める if(!fileData.type.match('image.*')) { alert('画像を選択してください'); return; } // FileReaderオブジェクトを使ってファイル読み込み var reader = new FileReader(); // ファイル読み込みに成功したときの処理 reader.onload = function() { // Canvas上に表示する uploadImgSrc = reader.result; canvasDraw(); } // ファイル読み込みを実行 reader.readAsDataURL(fileData); } // ファイルが指定された時にloadLocalImage()を実行 file.addEventListener('change', loadLocalImage, false); // Canvas上に画像を表示する function canvasDraw() { // canvas内の要素をクリアする ctx.clearRect(0, 0, canvasWidth, canvasHeight); // Canvas上に画像を表示 var img = new Image(); img.src = uploadImgSrc; img.onload = function() { ctx.drawImage(img, 0, 0, canvasWidth, this.height * (canvasWidth / this.width)); } } のようなコードで画像を読み込んで、input.valueに画像を読み込めばできるかなーと いう感じで考えていましたが、 jsの知識が少なすぎて悩んでおりました。 お手数おかけいたします。
int32_t

2021/01/25 15:47

質問文をご自身が書いてみたコードに更新してください。 質問文中のコードをこのサイトの「<code>」の機能を使って載せてください。 ご自身が書いてみたコードを動かしてみて、何が不都合なのか具体的に書いてください。
taroj

2021/01/25 21:08

int32_tさん ありがとうございます。 初めての質問で<code>機能があるのがわからず失礼いたしました。 編集させていただいて 該当のソースコードにコードを記載しました。 コードを実行すると input uploadに画像を添付すると 「wikipediaのロゴ」と「アップロードした画像」の2つの画像が表示されます。 wikipediaのロゴのところに【URL スキーム】の画像を表示する方法がわからずにいました。 お手数おかけいたします。よろしくお願いいたします。
guest

回答1

0

ベストアンサー

<input type=file>で指定されるローカルの画像ファイルを ImageEditorの入力にしたい、ということですよね。最小限の変更ですと、

  1. 関数 createImageEditor()event 引数を追加
  2. createImageEditor() 内の ImageEditorコンストラクタ呼び出しの引数のimageSrcを、以下のように変更

javascript

1 imageSrc: URL.createObjectURL(event.target.files[0]),

これで動くと思われます。関数 loadLocalImage() は使いません。

投稿2021/01/26 01:37

編集2021/01/26 01:38
int32_t

総合スコア20867

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taroj

2021/01/26 03:09 編集

int32_tさん ありがとうございます! ``` function createImageEditor(e) { ``` に変更して、コードを入れ替えさせていただいたところ無事、動きました! お忙しいところお付き合いいただきありがとうございました♪
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問