前提
vanillaJS(ES6)を利用してサッカーボードのようなアプリを作成しているのですが、canvasへのペン描画と要素の追加および操作を分離することができません。
実現したいこと
動作イメージとしては、フラグがオンの場合は要素追加および操作のみ、
フラグがオフの場合はペン描画のみといったものです。]
現状偶数/奇数でフラグを分類しておりますが、フラグそのものは何でもよく、個々の処理を別々で動かしたいというのが本旨でございます。
発生している問題
現状、画像をクリックするとイベント発火し、変数yが偶数の場合は要素追加メソッドを呼び出し、奇数の場合はペン描画メソッドを呼び出しで動作を分離しようとしています。
ただ、この場合呼び出し先のイベントが残ったままとなるので、
y=<2で要素追加とペン描画のイベントが重なり、
下記のようにペン描画後に要素追加が重なってしまいます。
そこで、コールバック関数listnenerのclickを処理するbreakの直前にremoveEventListener("click", listener);を入れてみましたが、
そうすると、要素追加が1度きりになってしまいます。(当然と言えば当然だとは思いますが)
該当のソースコード
index.htmlでmain.jsを呼び出し、ペン描画処理のDrawPen.jsと要素操作のElement.jsはクラス化しており、モジュールとしてmain.jsにインポートしています。
html:index.html
1<body> 2 <div class="container"> 3 <main> 4 <canvas id="draw_area" width="500px" height="500px" style="border: 1px solid #000000;"> 5 </canvas> 6 </main> 7 <div class="playerElem" id="player" data-elemid="0" style="top: 220px; left: 267px;">たいとる</div> 8 </div> 9 10 <!-- ペンの設定を変更する要素 --> 11 <div id="change_pen"> 12 <img src="img/pen.png" alt=""> 13 <div class="select_color"> 14 <ul> 15 <li data-color="black"> 16 <p>ペンの色:黒</p> 17 </li> 18 <li data-color="red"> 19 <p>ペンの色:赤</p> 20 </li> 21 <li data-color="blue"> 22 <p>ペンの色:青</p> 23 </li> 24 <li data-color="white"> 25 <p>消しゴム</p> 26 </li> 27 </ul> 28 </div> 29 </div> 30 <script src="js/main.js" type="module"></script> 31 <!-- テスト用スクリプト --> 32 <script> 33 </script> 34</body>
js:main.js
1"use strict"; 2import { DrawPen } from './DrawPen.js'; 3import { Element } from './Element.js'; 4 5const draw = new DrawPen(); 6draw.setCanvasSize(); 7// draw.drawPen(); 8// draw.changePenColor(); 9 10const elem = new Element(); 11// elem.moveElement(1); 12// elem.moveElement(2); 13 14// switch_btn押下で要素追加とペン描画を切り替える 15const switch_btn = document.querySelector("#change_pen > img"); 16let y = 0; 17switch_btn.addEventListener("click", () => { 18 y++; 19 if (y % 2 === 0) { 20 console.log(true); 21 elem.moveElement(); 22 } else if (y % 2 !== 0) { 23 console.log(false); 24 draw.drawPen(); 25 draw.changePenColor(); 26 } 27});
js:DrawPen.js
1"use strict"; 2export class DrawPen { 3 4 canvas = document.getElementById("draw_area"); 5 context = this.canvas.getContext("2d"); 6 7 // this減らしてもっと簡潔に書けないだろうか? 8 drawPen() { 9 this.canvas.addEventListener("mousemove", event => draw(event.layerX, event.layerY)); 10 this.canvas.addEventListener("touchmove", event => draw(event.layerX, event.layerY)); 11 //パソコンでクリックしてる間だけ描けるようにした機能 12 this.canvas.addEventListener("mousedown", () => { 13 this.context.beginPath(); 14 isDrag = true; 15 }); 16 this.canvas.addEventListener("mouseup", () => { 17 this.context.closePath(); 18 isDrag = false; 19 }); 20 //スマホで描けるようにする機能 21 this.canvas.addEventListener("touchstart", () => { 22 this.context.beginPath(); 23 isDrag = true; 24 }); 25 this.canvas.addEventListener("touchend", () => { 26 this.context.closePath(); 27 isDrag = false; 28 }); 29 30 let isDrag = false; 31 //線をかく機能 32 const draw = (x, y) => { 33 if (!isDrag) return; 34 this.context.lineTo(x, y); 35 this.context.stroke(); 36 } 37 } 38 39 // ペンの色を変えるメソッド 40 changePenColor() { 41 const selectList = document.querySelectorAll(".select_color > ul > li"); 42 const colorList = ["black", "red", "blue", "white"]; 43 for (let i = 0, len = selectList.length; i < len; i++) { 44 selectList[i].addEventListener("click", () => { 45 const color = selectList[i].getAttribute("data-color"); 46 // 下記はもっと簡潔に書く方法はないか…? 47 if (color === "black") { 48 this.context.globalCompositeOperation = "source-over"; 49 this.context.strokeStyle = "black"; 50 this.context.lineWidth =5; 51 } else if (color === "red") { 52 this.context.globalCompositeOperation = "source-over"; 53 this.context.strokeStyle = "red"; 54 this.context.lineWidth =5; 55 } else if (color === "blue") { 56 this.context.globalCompositeOperation = "source-over"; 57 this.context.strokeStyle = "blue"; 58 this.context.lineWidth =5; 59 } else { 60 this.context.globalCompositeOperation = 'destination-out'; 61 this.context.lineWidth =50; 62 } 63 }) 64 } 65 } 66 // canvasのサイズをmain要素に合わせる処理 67 setCanvasSize() { 68 const main = document.querySelector("main"); 69 const mainWidth = main.clientWidth; 70 const mainHeight = main.clientHeight; 71 console.log(mainWidth); 72 console.log(mainHeight); 73 74 this.canvas.setAttribute("width", mainWidth); 75 this.canvas.setAttribute("height", mainHeight); 76 } 77}
js:Element.js
1"use strict"; 2export class Element { 3 moveElement() { 4 const elements = document.getElementsByClassName("playerElem"); 5 const container = document.querySelector(".container"); 6 7 // 要素がクリックされた座標を取得する変数 8 let x; 9 let y; 10 11 const listener = (event) => { 12 console.log("イベント起動") 13 switch (event.type) { 14 case 'mousedown': 15 console.log("mousedown起動"); 16 this.lastMousedownElement = event.target.id; 17 let elem = event.target; 18 elem.classList.add("drag"); 19 20 if (event.type !== "mousedown") { 21 var event = event.changedTouches[0]; 22 } 23 24 x = event.pageX - elem.offsetLeft; 25 y = event.pageY - elem.offsetTop; 26 document.body.addEventListener("mousemove", mmove, false); 27 break; 28 case 'mouseup': 29 console.log("mouseup起動"); 30 this.lastMouseupElement = event.target.id; 31 let mouseup_elem = event.target; 32 mouseup_elem.classList.remove("drag"); 33 break; 34 case 'click': 35 console.log("click起動"); 36 console.log(this.lastMousedownElement); 37 console.log(this.lastMouseupElement); 38 if (this.lastMousedownElement === this.lastMouseupElement) return; 39 console.log("alert:要素を追加しました"); 40 alert("要素を追加しました"); 41 42 // 追加する要素を定義 43 const playerElem = document.createElement("div"); 44 playerElem.className = "playerElem"; 45 const text = document.createTextNode("たいとる"); 46 playerElem.setAttribute("id", "player"); 47 playerElem.appendChild(text); 48 container.appendChild(playerElem); 49 50 // クリックした座標位置に要素を配置 51 const drag = document.querySelectorAll(".playerElem"); 52 const elemId = drag.length - 1; 53 drag[elemId].setAttribute("data-elemId", elemId); 54 55 // 下記の20はマジックナンバーなので、他に算出方法あるかも 56 drag[elemId].style.top = event.pageY - 20 + "px"; 57 drag[elemId].style.left = event.pageX - 20 + "px"; 58 59 container.removeEventListener("click", listener); 60 break; 61 } 62 63 for (let dragElm of document.getElementsByClassName("playerElem")) { 64 dragElm.addEventListener('mousedown', listener, false); 65 document.addEventListener('mouseup', listener, false); 66 } 67 } 68 69 function mmove(event) { 70 const drag = document.getElementsByClassName("drag")[0]; 71 if (event.type !== "mousemove") { 72 let event = event.changedTouches[0]; 73 } 74 event.preventDefault(); 75 76 if (drag) { 77 drag.style.top = event.pageY - y + "px"; 78 drag.style.left = event.pageX - x + "px"; 79 } 80 } 81 container.addEventListener('click', listener, false); 82 container.addEventListener('mouseup', listener, false); 83 } 84}
かなり長文となってしまい申し訳ございません。
情報が不足しているあるいは、あいまいな表現で伝わらない部分がございましたら、ご指摘いただけますと幸いです。
何卒宜しくお願い致します。
追記になります。
※すみません。。②はmousedownではなくmouseupです。
回答2件
あなたの回答
tips
プレビュー