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

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

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

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Nuxt.js

Nuxt.jsは、ユニバーサルなSPAが開発可能なVue.jsベースのフレームワーク。UIの描画サポートに特化しており、SSRにおけるサーバーサイドとクライアントサイドのUIレンダリングなどさまざまな機能を持ちます。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

2771閲覧

canvasでローカルファイル(画像)を表示したい。

tokuwgawa

総合スコア45

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Nuxt.js

Nuxt.jsは、ユニバーサルなSPAが開発可能なVue.jsベースのフレームワーク。UIの描画サポートに特化しており、SSRにおけるサーバーサイドとクライアントサイドのUIレンダリングなどさまざまな機能を持ちます。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2019/01/17 09:48

編集2019/01/18 00:50
//image.vue <template> <div> <div v-for="image in layer"> <img v-show="uploadedImage" :src="uploadedImage" /> <input type="file" ref="file" @change="onFileChange"/> <el-button @click="setImage(image)">反映</el-button> </div> </div> </template> <script> export default { props: ['tmp_template'], data() { return { uploadedImage: "" } }, computed: { layer() { return this.tmp_template.layers.filter(function(layer) { if (layer.type === 'image') { return layer } }) }, }, methods: { viewValue() { //Preview.vueの関数 this.$emit('viewValue') }, onFileChange(file) { const elFile = this.$refs.file const files = elFile[0].files[0] this.uploadedImage = files }, setImage(image) { image.value = this.uploadedImage this.viewValue() } }, } </script>
//preview.vue <template> <div> <div style="width:1360px;height:250px;padding:50px;border:solid 1px #DDD;background-color:#FFFFFF;overflow:scroll"> <canvas id="preview" :style="{ border: 'solid 1px #000', 'background-color': '#FFFFFF', }"> </canvas> </div> </div> </template> <script> export default { data() { return {} }, props: ['tmp_template'], mounted() { this.ctx = this.$el.firstChild.firstElementChild.getContext('2d') this.drawCreative() }, methods: { //Canvas生成 drawCreative() { this.ctx.canvas.width = this.tmp_template.width this.ctx.canvas.height = this.tmp_template.height this.ctx.beginPath() this.ctx.clearRect(0, 0, this.tmp_template.width, this.tmp_template.height) this.tmp_template.layers.forEach(layer => { this.ctx.strokeStyle = this.setTypeColor(layer.type) if(layer.type === 'text' && layer.value) { this.ctx.fillText(layer.value, layer.x_position, layer.y_position - -10) } else if(layer.type === 'image' && layer.value) {       //画像表示処理 let image1 = new Image() let reader = new FileReader() image1.src = layer.value.name reader.onload = (e) => { this.ctx.drawImage(image1, 0, 0) }; reader.readAsDataURL(layer.value); } this.ctx.strokeRect(layer.x_position, layer.y_position, layer.width, layer.height) }) this.ctx.fill() }, }, } </script>

必要ないと思ったコードは割愛しています

このように処理で作っているのですが、画像が表示されません。
参考にしたサイトは下記サイトです。
エラーは出ないのですが、画像が表示されません。

リンク内容
リンク内容
リンク内容
リンク内容

追記

yhgさんの通りコードを書きましたが、エラーが表示されるようになりました。

Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
//image.vue <template> <div> <div v-for="image in layer"> <img v-show="uploadedImage" :src="uploadedImage" /> <input type="file" ref="file" @change="onFileChange"/> <el-button @click="setImage(image)">反映</el-button> </div> </div> </template> <script> export default { props: ['tmp_template'], data() { return { uploadedImage: "" } }, computed: { layer() { return this.tmp_template.layers.filter(function(layer) { if (layer.type === 'image') { return layer } }) }, }, methods: { //今回追加文 getDataURI(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file) reader.onload = () => resolve(reader, result) reader.onerror = error => reject(error) }) }, viewValue() { //previe.vueの関数 this.$emit('viewValue') }, onFileChange(file) { const elFile = this.$refs.file const files = elFile[0].files[0]    //関数代入 this.uploadedImage = this.getDataURI(files) }, setImage(image) { image.value = this.uploadedImage this.viewValue() } }, } </script>
//preview.vue <template> <div> <div style="width:1360px;height:250px;padding:50px;border:solid 1px #DDD;background-color:#FFFFFF;overflow:scroll"> <canvas id="preview" :style="{ border: 'solid 1px #000', 'background-color': '#FFFFFF', }"> </canvas> </div> </div> </template> <script> export default { data() { return {} }, props: ['tmp_template'], mounted() { this.ctx = this.$el.firstChild.firstElementChild.getContext('2d') this.drawCreative() }, methods: { //Canvas生成 drawCreative() { this.ctx.canvas.width = this.tmp_template.width this.ctx.canvas.height = this.tmp_template.height this.ctx.beginPath() this.ctx.clearRect(0, 0, this.tmp_template.width, this.tmp_template.height) this.tmp_template.layers.forEach(layer => { this.ctx.strokeStyle = this.setTypeColor(layer.type) if(layer.type === 'text' && layer.value) { this.ctx.fillText(layer.value, layer.x_position, layer.y_position - -10) } else if(layer.type === 'image' && layer.value) {       //画像表示処理 let image1 = new Image() let reader = new FileReader() image1.src = layer.value.name reader.onload = (e) => { this.ctx.drawImage(image1, 0, 0) }; reader.readAsDataURL(layer.value); } this.ctx.strokeRect(layer.x_position, layer.y_position, layer.width, layer.height) }) this.ctx.fill() }, }, } </script>

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

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

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

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

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

guest

回答1

0

ベストアンサー

File オブジェクトをそのまま <img>src 属性に入れても画像は表示されません。
File オブジェクトを元に DataURI を生成し、それを src 属性に入れる必要があります。

javascript

1function getDataURI(file) { 2 return new Promise((resolve, reject) => { 3 const reader = new FileReader(); 4 reader.readAsDataURL(file); 5 reader.onload = () => resolve(reader.result); 6 reader.onerror = error => reject(error); 7 }); 8}

javascript

1 async onFileChange(file) { 2 const elFile = this.$refs.file 3 const files = elFile[0].files[0] 4 this.uploadedImage = await getDataURI(files) 5 },

追記

  1. v-for の内側で ref を使うとややこしいことになるので、単純に event.target を参照したほうが良いです。

  2. uploadedImage はレイヤーと同じ数だけ保存しないと、反映した途端に全レイヤー同じ画像になります。

下記のサンプルコードでは配列の添字を使っているため、レイヤー配列が並び替わったり、間にレイヤーが追加されたりすると uploadedImages とレイヤーの対応付けが崩れますが、レイヤーごとにユニークIDを割り振っている場合は、uploadedImagesを配列ではなくオブジェクトに変更し、IDで対応付けする形にすることで対応付けが崩れなくなります。

  1. getDataURI は非同期関数なので、 async/await を使わないと、 uploadedImage に文字列ではなく Promise インスタンスが代入されてしまいます。

それと今回の getDataURI のように使い回しの効く関数はなるべく別ファイルに分離したほうが良いです。

以上3点をふまえると下記のような感じでしょうか。

js

1// utils/getDataURI 2export function getDataURI(file) { 3 return new Promise((resolve, reject) => { 4 const reader = new FileReader() 5 reader.readAsDataURL(file) 6 reader.onload = () => resolve(reader.result) 7 reader.onerror = error => reject(error) 8 }) 9}

vue

1//image.vue 2<template> 3 <div> 4 <div v-for="(image, index) in layer"> 5 <img v-show="index in uploadedImages && uploadedImages[index]" :src="uploadedImages[index]" /> 6 <input type="file" @change="event => onFileChange(event, index)" /> 7 <el-button @click="setImage(index)">反映</el-button> 8 </div> 9 </div> 10</template> 11 12<script> 13import { getDataURI } from '@/utils/getDataURI' 14 15export default { 16 props: ['tmp_template'], 17 data() { 18 return { 19 uploadedImages: [] 20 } 21 }, 22 computed: { 23 layer() { 24 return this.tmp_template.layers.filter(function(layer) { 25 if (layer.type === 'image') { 26 return layer 27 } 28 }) 29 }, 30 }, 31 methods: { 32 viewValue() { 33 //previe.vueの関数 34 this.$emit('viewValue') 35 }, 36 async onFileChange(event, index) { 37 const { files } = event.target 38 const file = files.item(0) 39 if (file) { 40 this.uploadedImages[index] = await getDataURI(file) 41 } 42 }, 43 setImage(index) { 44 this.layer[index].value = this.uploadedImages[index] 45 this.viewValue() 46 } 47 }, 48} 49</script>

js

1// preview.vue の一部 2 else if(layer.type === 'image' && layer.value) 3 { 4      //画像表示処理 5 let image1 = new Image() 6 image1.src = layer.value 7 // もしかしたら 画像の load イベント待たないと drawImage 失敗するかも?要検証 8 this.ctx.drawImage(image1, 0, 0) 9 }

投稿2019/01/17 15:18

編集2019/01/18 03:01
yhg

総合スコア2161

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

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

tokuwgawa

2019/01/18 00:50

Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'. こちらのエラーが出るようになり、表示まではまだ行ってません。 コード追記しましたのでお手隙の際にご覧いただけると幸いです。
tokuwgawa

2019/01/18 03:42

無事表示ができました!ありがとうございます! しかし反映ボタン2度押ししないとCanvas描画されないのはやはりonloadを設定していないからでしょうか?
yhg

2019/01/18 05:25 編集

image1.addEventListener('load', () => this.ctx.drawImage(image1, 0, 0), false) に挿し替えてみてください。それでもダメなら別の箇所の問題ですね。
tokuwgawa

2019/01/21 00:23

load処理でうまく行ってなかったので、これでうまくいきました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問