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

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

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

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

JavaScript

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

Q&A

解決済

3回答

1142閲覧

touchイベントで座標を獲得できない

kihokutarou

総合スコア59

canvas

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

JavaScript

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

0グッド

0クリップ

投稿2018/03/06 00:09

編集2018/03/06 10:08

mauseイベントでは座標を獲得しトリミングができているスクリプトがあります。これにtouchイベントを追加させたくて悪戦苦闘しております。ブラウザはchrome、ローカルで完結させるプログラムです。
具体的な動作としてはupload_canvasという要素上で座標をとり、裏にあるlayer2というcanvasで四角形を(トリミング範囲)を取得し、それをbaseというcanvasから原寸大で書き出す、という動作です。

別の質問にてイベント処理をjQueryかaddEventListenerのどちらかに統一させたほうが良いとのアドバイスをいただきましたが、とりあえず現状のままで動かして、ゆくゆくはアドバイスを受け勉強をすすめたいと思っています。
//ここからタッチ試行
//ここまでタッチ試行
が今回追記した部分になります。
このとき、マウスイベントすら動かなくなってしまいますが、上記部分を削除すると普通に動作します。
どなたかおかしな点、改善点、ずばりここをこう!など教えていただけるととてもうれしいです。

字数の関係で以下はhtmlの要素タグ

<div id="draw_area"> <canvas id="upload_canvas" width="0" height="0"></canvas> <canvas id="base" width="0" height="0" style="position: absolute; z-index: 0; display:none;"></canvas> <canvas id="layer1" width="0" height="0" style="position: absolute; z-index: 0; display:none;"></canvas> <canvas id="layer2" width="0" height="0" style="position: absolute; z-index: 1; display:none;"></canvas> </div> <!-- set this render canvas hidden --> <canvas id="render" width="0" height="0"style="display:none;"></canvas> <br> <!-- <img src="#" id="i1"><br> -->

--追記--
お二人のアドバイスをいただきながらエラーが出ないように修正をしました。エラーは出なくなりましたし、穴が開くほど記述を見返しているのですが、マウス操作ではトリミングできるのにタッチ操作ではトリミングというか矩形生成ができません。解決へのヒントをいただけるとありがたいです。
以下修正済み記述

javascript

1var layer1 = document.getElementById("layer1"); 2var layer1Ctx = layer1.getContext("2d"); 3 4var layer2 = document.getElementById("layer2"); 5var layer2Ctx = layer2.getContext("2d"); 6 7var display = document.getElementById("upload_canvas"); 8var displayCtx = display.getContext("2d"); 9 10var base = document.getElementById("base"); 11var baseCtx = base.getContext("2d"); 12 13var render = document.getElementById("render"); 14var renderCtx = render.getContext("2d"); 15 16var layers = [layer1, layer2]; 17 18var is_down = false; 19var trimming_begin_pos = { x: null, y: null }; 20var trimming_end_pos = { x: null, y: null }; 21 22var loaded_file = null; 23var max_canvas_size = { width: 900, height: 600 }; 24 25$(function() { 26 // load image file 27 $("#upload_file").change(function() { 28 29 var file = this.files[0]; 30 if (!file.type.match(/^image/(png|jpeg|gif)$/)) return; 31 32 var image = new Image(); 33 var reader = new FileReader(); 34 35 reader.onload = function(e) { 36 image.onload = function() { 37 38 var min_width = Math.min(this.width, max_canvas_size.width); 39 var min_height = Math.min(this.height, max_canvas_size.height); 40 var scale = Math.min(min_width / this.width, min_height / this.height); 41 var size = {width: this.width * scale, height: this.height * scale}; 42 43 resizeCanvas(size.width, size.height); 44 layer1Ctx.drawImage(image, 0, 0, size.width, size.height); 45 updateCanvas(); 46 47 $("#upload_button").attr('filename', file.name); 48 $("#upload_button").show(); 49 50 // load file on base buffer 51 base.width = this.width/3; 52 base.height = this.height/3; 53 baseCtx.drawImage(image, 0, 0,this.width/3,this.height/3); 54 } 55 image.src = e.target.result; 56 } 57 58 reader.readAsDataURL(file); 59 }); 60 61 // upload image 62 $("#upload_button").click(function(){ 63 64 // get blob data from canvas 65 var canvas = $('#render'); 66 var type = 'image/jpeg'; 67 var dataurl = canvas[0].toDataURL(type); 68 var bin = atob(dataurl.split(',')[1]); 69 var buffer = new Uint8Array(bin.length); 70 for (var i = 0; i < bin.length; i++) { 71 buffer[i] = bin.charCodeAt(i); 72 } 73 var blob = new Blob([buffer.buffer], {type: type}); 74 75 // upload 76 var fd = new FormData(); 77 fd.append('filename', $(this).attr('filename')); 78 fd.append('data', blob); 79 $.ajax({ 80 type: 'POST', 81 url: 'http://yoursite', 82 data: fd, 83 processData: false, 84 contentType: false 85 }).done(function(data) { 86 // done 87 }); 88 }); 89 90 // canvas controll 91 function resizeCanvas(width, height) { 92 for(var i = 0; i < layers.length; i++) { 93 layers[i].width = width; 94 layers[i].height = height; 95 } 96 display.width = width; 97 display.height = height; 98 } 99 100 function updateCanvas() { 101 displayCtx.drawImage(layer1, 0, 0, display.width, display.height); 102 displayCtx.drawImage(layer2, 0, 0, display.width, display.height); 103 } 104 105 106 display.addEventListener("mousemove", function(e){}, false); 107 display.addEventListener("mouseout", function(e){}, false); 108 $('#upload_canvas').on("mousemove", function(e) { 109 if (is_down) { 110 var mouse_pos = getMousePos(e); 111 updateSelectArea(mouse_pos); 112 } 113 }); 114 $('#upload_canvas').on("mouseout", function(e) { 115 }); 116 $('#upload_canvas').on("mousedown", function(e) { 117 if (is_down == true) return; 118 is_down = true; 119 trimming_begin_pos = getMousePos(e); 120 }); 121 $('#upload_canvas').on("mouseup", function(e) { 122 is_down = false; 123 trimming_end_pos = getMousePos(e); 124 125 var begin_pos = trimming_begin_pos; 126 var end_pos = trimming_end_pos; 127 128 if (begin_pos.x == end_pos.x && begin_pos.y == end_pos.y) return; 129 var begin = {x: 0, y:0}; 130 var end = {x:0, y:0}; 131 begin.x = Math.min(begin_pos.x, end_pos.x); 132 begin.y = Math.min(begin_pos.y, end_pos.y); 133 end.x = Math.max(begin_pos.x, end_pos.x); 134 end.y = Math.max(begin_pos.y, end_pos.y); 135 136 highlightTrimmingArea(begin, end); 137 clip(begin, end); 138 }); 139 140 function getMousePos(e) { 141 var rect = display.getBoundingClientRect(); 142 return { 143 x: e.clientX - rect.left, 144 y: e.clientY - rect.top}; 145 } 146 147 function updateSelectArea(mouse_pos) { 148 clear(layer2); 149 drawRect(layer2, 150 trimming_begin_pos.x, 151 trimming_begin_pos.y, 152 mouse_pos.x - trimming_begin_pos.x, 153 mouse_pos.y - trimming_begin_pos.y, 154 3, 'red'); 155 updateCanvas(); 156 } 157 158 //ここからタッチ試行 159 display.addEventListener("touchmove", function(e){}, false); 160 display.addEventListener("touchend", function(e){}, false); 161 $('#upload_canvas').on("touchmove", function(e) { 162 if (is_down) { 163 var touch_pos = getTouchPos(e); 164 updateSelectArea(touch_pos); 165 } 166 }); 167 $('#upload_canvas').on("touchend", function(e) { 168 }); 169 $('#upload_canvas').on("touchstart", function(e) { 170 if (is_down == true) return; 171 is_down = true; 172 trimming_begin_pos = getTouchPos(e); 173 }); 174 $('#upload_canvas').on("touchend", function(e) { 175 is_down = false; 176 trimming_end_pos = getTouchPos(e); 177 178 var begin_pos = trimming_begin_pos; 179 var end_pos = trimming_end_pos; 180 181 if (begin_pos.x == end_pos.x && begin_pos.y == end_pos.y) return; 182 var begin = {x: 0, y:0}; 183 var end = {x:0, y:0}; 184 begin.x = Math.min(begin_pos.x, end_pos.x); 185 begin.y = Math.min(begin_pos.y, end_pos.y); 186 end.x = Math.max(begin_pos.x, end_pos.x); 187 end.y = Math.max(begin_pos.y, end_pos.y); 188 189 highlightTrimmingArea(begin, end); 190 clip(begin, end); 191 }); 192 193 function getTouchPos(e) { 194 var rect = display.getBoundingClientRect(); 195 return { 196 x : e.clientX - rect.left, 197 y : e.clientY - rect.top}; 198} 199 200 201 202 function updateSelectArea(touch_pos) { 203 clear(layer2); 204 drawRect(layer2, 205 trimming_begin_pos.x, 206 trimming_begin_pos.y, 207 touch_pos.x - trimming_begin_pos.x, 208 touch_pos.y - trimming_begin_pos.y, 209 3, 'red'); 210 updateCanvas(); 211 } 212 213 214 //ここまでタッチ試行 215 216 217 function highlightTrimmingArea(begin, end) { 218 clear(layer2); 219 var fill = "rgba(0, 0, 0, 0.5)"; 220 fillRect(layer2, 0, 0, layer2.width, begin.y, fill); // top 221 fillRect(layer2, 0, begin.y, begin.x, end.y - begin.y, fill); // left 222 fillRect(layer2, end.x, begin.y, layer2.width - begin.x, end.y - begin.y, fill); // right 223 fillRect(layer2, 0, end.y, layer2.width, layer2.height - end.y, fill); // bottom 224 updateCanvas(); 225 } 226 227 function clear(canvas) { 228 var ctx = canvas.getContext("2d"); 229 ctx.clearRect(0, 0, canvas.width, canvas.height); 230 } 231 232 function drawRect(canvas, x, y, width, height, line, style) { 233 var ctx = canvas.getContext("2d"); 234 ctx.beginPath(); 235 ctx.rect(x, y, width, height); 236 ctx.lineWidth = line; 237 ctx.strokeStyle = style; 238 ctx.stroke(); 239 } 240 241 function fillRect(canvas, x, y, width, height, style) { 242 var ctx = canvas.getContext("2d"); 243 ctx.beginPath(); 244 ctx.rect(x, y, width, height); 245 ctx.fillStyle = style; 246 ctx.fill(); 247 } 248 249 function clip(begin, end) { 250 var scale = base.width / display.width; // display scale 251 var x = begin.x * scale; 252 var y = begin.y * scale; 253 var width = (end.x - begin.x) * scale; 254 var height = (end.y - begin.y) * scale; 255 256 render.width = width; 257 render.height = height; 258 renderCtx.drawImage( base, x, y, width, height, 0, 0, width, height); 259 } 260 261 262})

どうかよろしくお願いします。

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

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

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

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

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

defghi1977

2018/03/06 00:30

あなたがまずすべきことはここで質問することではなく, コンソールに文法エラーが表示されていないかを確認することです.
kihokutarou

2018/03/06 00:33

回答ありがとうございます。投稿前に確認したのですが、touch部分を入れると最終行あてにUncaught SyntaxError: Unexpected end of inputエラーが表示され、閉じカッコ等確認したのですが特に問題があるようには見えませんでした。
guest

回答3

0

SyntaxError: Unexpected end of inputエラーが表示され、閉じカッコ等確認したのですが特に問題があるようには見えませんでした。

あなたのコードに問題があるから「SyntaxError」が出力されているのです.

この手の問題を解決する最も効率の良い方法は問題のあるコードブロック全体を漫然と眺めるのではなく, 1メソッドずつコードに追加していきその都度文法エラーが存在しないかをコンソールで確認することです. いかにJavaScriptエンジンの性能が向上したとは言え, 常に問題のある箇所を的確に指摘できるわけではありませんから, 結局は人力で虱潰しに確認する必要があるのです.

NOTE:
この作業は苦痛この上ないので, 古くから「コピペはするな」とか「メソッドは短くしろ」とか「共通部分はまとめろ」とか言われているのです.


コード修正後の回答
NOTE:
筆者はタッチイベントを確認できる環境をもっていないので, 勝手ながらヒントの提示だけに留めさせていただきます.(ググればサンプルがたくさん出てくる筈)

TouchEventオブジェクトはマルチタッチをサポートするためにMouseEventオブジェクトと構成が全く異なります(clientX/clientYプロパティを持たない!)
そのため, 下記の部分でタッチ位置が取得できていないのです.

JavaScript

1 $('#upload_canvas').on("touchend", function(e) { 2 is_down = false; 3 trimming_end_pos = getTouchPos(e);//←---TouchEventオブジェクトを直接渡している! 4 //以下略 5 }); 6 7 function getTouchPos(e) { 8 var rect = display.getBoundingClientRect(); 9 return { 10 x : e.clientX - rect.left,//←--e.clientXはundefined! 11 y : e.clientY - rect.top};//←--e.clientYもundefined! 12 }

ではどうすればよいのか?

TouchEventオブジェクトのtouches/changedTouchesプロパティから一つTouchオブジェクトを取得し, このTouchオブジェクトのclinetX/clientY値から座標を求めればよい(以降はMouseEvent版と同様)のです.

但し, TouchEventから取得されるTouchオブジェクトは一つとは限らないため, 常にTouchオブジェクトの識別子(identifier プロパティ)の値から現在追跡中のタッチ位置を検出するようにします.

※そのためには, touchstart(タッチの記憶), touchmove(タッチの追跡), touchend/touchcancel(タッチの開放)イベントの全てで適切にタッチ位置の選択を行う必要があります.

参考
https://developer.mozilla.org/ja/docs/Web/API/TouchEvent
https://developer.mozilla.org/ja/docs/Web/Guide/DOM/Events/Touch_events#Example

投稿2018/03/06 00:45

編集2018/03/06 11:10
defghi1977

総合スコア4756

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

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

defghi1977

2018/03/06 11:11

と, 理屈では判っていてもいざ実装するとなるとしんどいかもしれんね
kihokutarou

2018/03/06 11:53

回答ありがとうございます。私もそれは何となくわかったのですが、別途 var canvas = document.getElementById("upload_canvas"); canvas.onmousedown = (function(e) { var rect = e.target.getBoundingClientRect(); event.preventDefault(); x = e.clientX - rect.left; y = e.clientY - rect.top; console.log(x); console.log(y); }); を追記し、実際にタッチスクリーンでタッチしてみると座標がコンソールに表示されました。なるほど座標が取れているのか、ということで紆余曲折した結果上記のコードに修正したわけです。受け渡し方法が何となく違う気もするんですよね。。
defghi1977

2018/03/06 12:27

であれば無理にtouchイベントを使う必要は無い気がしますね.Mozillaでも > 注記: 多くのケースで、 (タッチに特化していないコードでもユーザと対話できるようにするため) タッチイベントとマウスイベントの両方が送信されることに注意が必要です。タッチイベントを使用する場合は、マウスイベント送信されないようにするため event.preventDefault() を呼び出すべきです。 としているので, マルチタッチ前提の高度な処理が必要ないのであれば素直にMouseEventで作り込むが筋っぽいです.(つーか混在させたからうまく行かなかったというオチ?)
kihokutarou

2018/03/06 12:45

touch試行前はやはりタッチ操作は全く効きませんでした。 今回コメントいただいた後、 function updateSelectArea(touch_pos) { clear(layer2); event.preventDefault() ; drawRect(layer2, trimming_begin_pos.x, trimming_begin_pos.y, touch_pos.x - trimming_begin_pos.x, touch_pos.y - trimming_begin_pos.y, 3, 'red'); updateCanvas(); console.log(trimming_begin_pos.x); console.log(trimming_begin_pos.y); } と矩形処理時のtouchmoveの座標を追うと、「NaN」の連続なのでやはり受け渡しに難があるような気がします。 これ以上長引かせるのも回答者様にも失礼かと思いますので、しばらく他から反応がなければクローズしようと思います。 長々とありがとうございます。
defghi1977

2018/03/06 13:05

一旦元のコードから離れ, シンプルな内容で動作検証を始められたら如何でしょう? > これ以上長引かせるのも回答者様にも失礼かと思いますので、 むしろ解決してもいないのに質問をクローズするのは絶対におやめ下さい. 反応が無ければ無いなりにほっておけばよいのです. 無理にクローズすることで良い回答の提示を妨げるだけでなく, あなた以外のtouchイベントで苦しんでおられる方がこの記事にたどり着いた際に落胆させてしまう等のマイナスの効能しか残しません. もちろん, 様々なヒントを元にご自身で問題が解決できた暁にはその内容をもってベストアンサーとされれば良いのです.
guest

0

自己解決

https://teratail.com/questions/116557?whotofollow=
に本質問に続いての続報があります。

defghi1977様との会話の中で、touchイベントオブジェクトのご説明がありました。私は「いや現状で普通に座標が取れている」と回答しましたが、全体的にうまくいかず、また重ねて「一度コードから離れてみては」とアドバイスをもらったのでタッチイベントの勉強をしてみました。
display.addEventListener("touchstart", function(e){}, false);
display.addEventListener("touchmove", function(e){}, false);
display.addEventListener("touchend", function(e){}, false);
display.addEventListener("touchcancel", function(e){}, false);
と起こし(最後の行は入電した時のキャンセルイベントだと思うので本当は必要なし)、他のjQueryなどの文法も手直しをして、
function getTouchPos(e) {
var rect = display.getBoundingClientRect();
return {
x : event.touches[0].clientX - rect.left,
y : event.touches[0].clientY - rect.top};
}
でタッチ座標を獲得しようとしました。
本質問で求めた答えはここまでで半分ほど成立、座標を取ることはできしたが続けてエラーが出るはめに。それが文頭の次の質問となります。

結果的に全解決しましたし、逃げていたタッチイベントと一応向かい合えました。次は脱jQueryを目指します。特にdefghi1977様には感謝です。

投稿2018/03/08 05:35

kihokutarou

総合スコア59

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

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

0

閉じかっこを確認されたとのことですが

ぱっと見ですが、
・getTouchPos
・upload_canvasのaddEventListener
部分閉じられていないように見うけられますが。。。。

また、
updateSelectAreaも重複して存在しています。

文法チェックしてくれるエディタなり、ツールなりを活用することも検討された方が良いかと思います。
コピペミスだったらなおさら。。。

投稿2018/03/06 01:20

kogure

総合スコア299

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問