上一篇Canvas的博文寫完后,有位朋友希望能對Canvas繪制出來的圖像進行點擊、拖拽等操作,因為Canvas繪制出的圖像能很好的美化。好像是想做爐石什么的游戲,我也沒玩過。
Canvas在我的理解中就好像在一張畫布上繪制圖像,它只能看到卻“摸”不到,那要如何進行操作呢。我不知道網上是怎么做的,這里用自己的想法做了個DEMO分享給大家。
思路:
雖然Canvas不能拖拽,但div可以拖拽,那怎么把二者結合起來呢。初步想法是將一個與Canvas圖像大小差不多的div覆蓋在其上,在拖拽div時將獲取的光標坐標修正后傳給Canvas繪制函數並刷新圖像的位置。
既然要覆蓋,先做些准備工作:
1.將div與Canvas畫布均position:absolute,否則無法重疊。
2.將div的z-index值設置大點,保證其在Canvas畫面之上。
准備工作完成后,我們先來看div的拖拽:
var divObj=document.getElementById("cover"); var moveFlag=false; divObj.onmousedown=function(e){ moveFlag=true; var clickEvent=window.event||e; var mwidth=clickEvent.clientX-divObj.offsetLeft; var mheight=clickEvent.clientY-divObj.offsetTop; document.onmousemove=function(e){ var moveEvent=window.event||e; if(moveFlag){ divObj.style.left=moveEvent.clientX-mwidth+"px"; divObj.style.top=moveEvent.clientY-mheight+"px"; divObj.onmouseup=function(){ moveFlag=false; } } } };
來解讀下這段代碼:首先獲取div對象,設置拖拽標志moveFlage,當onmousedown時為true表示可以拖動,當onmouseup時為false表示不能拖動了。
var clickEvent=window.event||e; var mwidth=clickEvent.clientX-divObj.offsetLeft; var mheight=clickEvent.clientY-divObj.offsetTop;
這三行代碼是為了修正光標位置。當點擊時,記錄下光標在div上的位置。mwidth和mheight表示光標落點相對於div左邊和上邊的距離。如果不加修正:
這就是不加修正的結果,當光標點下時,div的坐標即左上角會與光標坐標一致。
修正后:
點擊時光標總會“粘”在div某點上。
接下來繪制圖片:
首先定義全局變量X和Y,它們是為了實時更新圖像的繪制坐標。
var ctx=document.getElementById("myCanvas").getContext("2d"); var img=document.getElementById("myImg"); function drawImg(){ ctx.clearRect(0,0,1000,500); ctx.beginPath(); ctx.drawImage(img,X,Y); ctx.closePath(); ctx.stroke(); } window.onload=function(){ setInterval(drawImg,1); }
獲取“畫筆”,獲取圖片對象。這里setInterval循環執行繪制圖片的函數,以刷新圖片的位置,setInterval的間隔值越小,拖拽起來越“流暢”。
同時別忘了clearRect,當圖片移動到下一個位置時,清除上一個位置的圖片,參數為Canvas畫布的坐標和尺寸。
在拖拽時將修正后的光標坐標傳給X、Y:
X=moveEvent.clientX-mwidth;
Y=moveEvent.clientY-mheight;
最后加上div和圖像的活動范圍:
if(moveEvent.clientX<=mwidth){ divObj.style.left=0+"px"; X=0; } if(parseInt(divObj.style.left)+divObj.offsetWidth >=1000){ divObj.style.left=1000 - divObj.offsetWidth+"px"; X=1000 - divObj.offsetWidth; } if(moveEvent.clientY<=mheight){ divObj.style.top=0+"px"; Y=0; } if(parseInt(divObj.style.top)+divObj.offsetHeight>=500){ divObj.style.top=500-divObj.offsetHeight+"px"; Y=500-divObj.offsetHeight; }
這個就看個人的要求了,注意是要同時限定div和圖片的活動范圍。1000與500為本例的畫布大小,如果是在整個頁面里活動就換成innerWidth或innerHeight。
徹底隱藏div看看效果:
最后說下點擊事件,這里要注意的是在拖拽的過程中onmousedown與onmouseup二者就構成了一個click過程,但我們不希望在拖拽結束后觸發點擊事件。
這里有個比較簡單的辦法,定義一個clickFlag默認為false,當onmousedown時設為true,若進行了onmousemove事件時設為false。
在最后onmouseup時判斷clickFlag的值,為true時才觸發點擊事件。也就是說當你按下鼠標時,只有不發現移動,松開鼠標時才會觸發點擊事件。
整理后的JS代碼:
// 繪制圖片坐標 var X=0; var Y=0; // js部分 var divObj=document.getElementById("cover"); var moveFlag=false; //區別moueseup與click的標志 var clickFlag=false; // 拖拽函數 divObj.onmousedown=function(e){ moveFlag=true; clickFlag=true; var clickEvent=window.event||e; var mwidth=clickEvent.clientX-divObj.offsetLeft; var mheight=clickEvent.clientY-divObj.offsetTop; document.onmousemove=function(e){ clickFlag=false; var moveEvent=window.event||e; if(moveFlag){ divObj.style.left=moveEvent.clientX-mwidth+"px"; divObj.style.top=moveEvent.clientY-mheight+"px"; //// 將鼠標坐標傳給Canvas中的圖像 X=moveEvent.clientX-mwidth; Y=moveEvent.clientY-mheight; //// 下面四個條件為限制div以及圖像的活動邊界 if(moveEvent.clientX<=mwidth){ divObj.style.left=0+"px"; X=0; } if(parseInt(divObj.style.left)+divObj.offsetWidth >=1000){ divObj.style.left=1000 - divObj.offsetWidth+"px"; X=1000 - divObj.offsetWidth; } if(moveEvent.clientY<=mheight){ divObj.style.top=0+"px"; Y=0; } if(parseInt(divObj.style.top)+divObj.offsetHeight>=500){ divObj.style.top=500-divObj.offsetHeight+"px"; Y=500-divObj.offsetHeight; } divObj.onmouseup=function(){ moveFlag=false; if(clickFlag){ alert("點擊生效"); } } } } };
本例到此結束,更多功能大家有興趣可以自己開發,感謝您的瀏覽,也感謝每個對我這菜鳥提意見的人。