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

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

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

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

Q&A

解決済

2回答

1982閲覧

javascriptを用いたペースト(コピペ)機能について

SideRiver

総合スコア2

JavaScript

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

0グッド

0クリップ

投稿2021/01/14 10:38

前提・実現したいこと

初学者のため至らない点ばかりですがお手柔らかにお願いします。

html, jsで、パワーポイントのように作業エリア内で文章や画像をペーストすることができ、かつそれらを動かせるというサイトを作成しようとしています。
具体的には、サイトの決められた領域内でペーストを行うと、クリップボード内のデータが画像・テキストに関わらず張り出されるといった感じです。
ctrl+vが押された時にクリップボードからテキスト情報を得てペーストすることは成功したのですが、画像をペーストすることが出来ません。そのため画像をクリップボードから取り出し画像として貼り出す方法を教えていただきたいです。
よろしくお願いします。

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

Uncaught (in promise) TypeError: Cannot read property 'getAsFile' of undefined at var imageFile = e.clipboardData.items[0].getAsFile();

該当のソースコード

html

1<style> 2.abs { 3 position: absolute; 4} 5</style> 6<body> 7<div id="textareas" contenteditable="true"></div> 8</body> 9<script> 10document.addEventListener('paste', function(e){ 11 if(x>220 & y>89){ 12 var area = document.getElementById("textareas"); 13 if (navigator.clipboard) { 14 navigator.clipboard.readText() 15 .then(function (text) { 16 if(text==""){ 17 var imageFile = e.clipboardData.items[0].getAsFile(); 18 var fr = new FileReader(); 19 fr.onload = function(e) { 20 img_count++; 21 var base64 = e.target.result; 22 document.querySelector("#outputImage").src = base64; 23 area.innerHTML = temp + "<div class='abs' id=" + img_count + " style=' top: " + y + "px; left:" + x + "px;'><img src=" + base64 + " id='num" + img_count + "' ></div>" 24 } 25 fr.readAsDataURL(imageFile); 26 } 27 else{ 28 text_count++; 29 area.innerHTML = temp + "<div class='abs' id=" + text_count + " style=' top: " + y + "px; left:" + x + "px;'><input textarea value=" + text + " id='num" + text_count + "' ></div>" 30 }}); 31 } 32 temp = area.innerHTML; 33 } 34 }) 35 </script> 36 37 38<!--  試したコードを併記しています 39document.addEventListener('keydown', (event) => { 40 const keyName = event.key; 41 if (event.ctrlKey||event.metaKey) { 42 if (keyName == "v") { 43 if(x>220 & y>89){ 44 var area = document.getElementById("textareas"); 45 if (navigator.clipboard) { 46 navigator.clipboard.readText() 47 .then(function (text) { 48 if(text==""){ 49 img_count++; 50 navigator.clipboard.read() 51 .then(function (img){ 52 // console.log(img); 53 area.innerHTML = temp + "<div class='abs' id=" + img_count + " style=' top: " + y + "px; left:" + x + "px;'><input type='image' src="+ img +" value=" + img + " id='num" + img_count + "' ></div>" 54 }) 55 } 56 else{ 57 text_count++; 58 area.innerHTML = temp + "<div class='abs' id=" + text_count + " style=' top: " + y + "px; left:" + x + "px;'><input textarea value=" + text + " id='num" + text_count + "' ></div>" 59 }}); 60 } 61 temp = area.innerHTML; 62 } 63 } 64 } 65}, false); --> 66 67

試したこと

画像とテキストを別の関数として分けて実行してみたのですが、画像の生成はうまく行きませんでした。

上記コメントアウト内の関数の場合、出力はされるものの画像の表示にエラーが起きているようでした。
GET (url)[object 404 (Not Found)というエラーコードが表示されてしまいました

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

こちらの記事を参考にさせていただきました。
https://qiita.com/tatesuke/items/00de1c6be89bad2a6a72
xとyはmouse座標になっています。
ブラウザはchromeです

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

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

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

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

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

guest

回答2

0

ベストアンサー

エラーの内容は「Cannot read property 'getAsFile' of undefined」なので、

e.clipboardData.items[0]

がundefined、つまりクリップボードにitemが入ってないと言っているように見えます。

ここで言われている「クリップボードの画像」というのは、画像ファイルですか?

補足に書かれているQiita記事のコードを試してみましたが、普通に動きました。
ただし、PrintScreenキーを押して取得した「画面キャプチャ」をそのままクリップボードに入れた状態での貼り付けです。適当な「保存された画像ファイル(png)」をファイルとしてコピーして貼り付けてみたら、itemは空でした。

もし目的が「画像ファイル」であるなら、それを取り出す方法があるのかどうかは、すみませんが分からないです。itemに入ってこないという事は、何か制限があって不可能という可能性もある気がします。

キャプチャ画像そのものであるなら、itemsが0になる事はないはず。
(追記参照)

参考にされている記事では、

javascript

1 // 画像の場合 2 // e.clipboardData.types.length == 0 3 // かつ 4 // e.clipboardData.types[0] == "Files" 5 // となっているので、それ以外を弾く 6 if (!e.clipboardData 7 || !e.clipboardData.types 8 || (e.clipboardData.types.length != 1) 9 || (e.clipboardData.types[0] != "Files")) { 10 return true; 11 } 12

という処理が入っていますよね。この分岐を使えば、画像とそれ以外を切り分けて作る事ができるんじゃないでしょうか。

(追記)

非同期のClipboardAPIを使用されていて、Promiseの実行時にEventListner内のclipboadが持ってるDataTransferの中身が消えてしまっているのがエラーの原因ぽいです。

非同期APIを使用するなら、その後の読み込みも全部、非同期でやらないと駄目みたいです。
(EventListner実行時に渡される e.clipboardData.items の中身は、Promiseのthen によってコールバックが実行されるタイミングにおいては残っていない。)

javascript

1 document.addEventListener('paste', async e => { 2 if (!e.clipboardData 3 || !e.clipboardData.types 4 || (e.clipboardData.types.length != 1) 5 || (e.clipboardData.types[0] != "Files")) { 6 return true; 7 } 8 9 const items = await navigator.clipboard.read(); 10 const txtBlob = await items[0].getType("image/png"); 11 12 const img = document.createElement("img") 13 img.src = URL.createObjectURL(txtBlob); 14 document.body.appendChild(img); 15 })

(参考)W3C - ClipboardAPI

投稿2021/01/14 12:00

編集2021/01/15 05:23
umau

総合スコア805

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

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

SideRiver

2021/01/14 12:10

ご回答ありがとうございます おっしゃる通りファイルではなく、画像キャプチャの認識で正しいです。画像キャプチャにおいて、質問痔のようなエラーが出てしまいます。 参考にしている記事のコードでは、div内にカーソルを合わせたのちにペーストすることで、もともと用意してあったimgタグにsrcを代入している、というコードだと認識しています。 これを、ctrl+vが押された時、どこであってもクリップボード内の情報を取り出し、新たにimgタグを作成したい、という要望です。 画像とそれ以外の識別はおそらく私のコードでも(非常に稚拙ですが)出来ていると考えています、、、
umau

2021/01/14 12:29

FileReader内で、imgタグをcreateElementしてあげたらどうでしょう。 ``` fr.onload = function(e) { var base64 = e.target.result; var img = document.createElement("img") img.src = base64; document.body.appendChild(img); } ``` あと、ペースト用のdivを削除して、bodyタグに、 <body contenteditable="true"> としたらどうでしょうか?
umau

2021/01/14 13:27

いや、エラーの解決になってないから、この答えが欲しいわけではないですね、、 navigator.clipboard.readText() を使って非同期で読み取りされているので、EventListnerから受け取ったclipboadData内のDataTransferの中身は、Promise実行時には削除されてしまう、というのが根本的な原因ぽいです。 対応ソース追記します。
SideRiver

2021/01/14 14:58

ご丁寧にありがとうございます 追記してくださったコードの場合も残念ながら手元で再現ができず画像は描画できなかったのですが、非同期である処理を行えば上手くいくとのことなのでもう少し試行錯誤してみます! 親身にありがとうございました
umau

2021/01/15 05:25

そうですか、、一応こちらでは追記のコードで貼り付けまで動作してるんですが、お力になれず残念です。頑張ってください。 (本文を少し修正しました)
guest

0

https://qiita.com/tatesuke/items/00de1c6be89bad2a6a72
https://jsfiddle.net/2tkc99n2/1/
https://qiita.com/majime9n/items/e51c66c3ed89d52bebf4
こちらが参考になるかもしれません。

また、divタグに直接画像を貼るというよりかは、imgタグとかcanvasタグを使って表示することになるのかなと思いました。

投稿2021/01/14 11:33

編集2021/01/14 11:35
eneko0513

総合スコア349

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問