iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Modern Web

從新開始學習p5.js畫出一片天系列 第 26

D26_物件點擊拖拉事件操作

  • 分享至 

  • xImage
  •  

物件點擊拖拉事件操作

今天來整理物件點擊拖拉的事件操作

在網頁的操作中,物件點擊拖拉事件,也就是「點,拖,放」的操作,
主要的操作是移動網頁內的元件位置,甚至可以說是元件的「平移,旋轉,縮放」的操作。
邏輯步驟如下

  1. 利用 const pv1 = Object.assign({}, img1.position()); 的話法,複製img1的原本的起始座標的獨立物件,pv1 不會受img1.position()的影響。若使用 pv1 = img1.position(); 的方法會造成 pv1的資料仍會受img1.position()的影響。
  2. 使用 img1.position(pv1.x, pv1.y); 重新設定img1的座標,可以將img1的座標模式從堆疊式座標改成是浮動式座標。堆疊式座標是根據元件標籤在body中的排列順序呈現,浮動式座標是可以自由設定在body中的座標,當堆疊式座標改成浮動式座標時,先前在其後的堆疊式座標元件就會向前移動。
  3. 記錄點下時的起始座標 px0, py0,起始的z-index高度 zIndex,拖動的與起始座標差距值 dx, dy,新的img1的座標 nx, ny,調整img1的z-index的高度到10。
  4. 使用 e.target.id 讀取點擊的物件id,判斷條件為當點擊的物件id為img1, 點擊狀態st為1時,img1物件就會被移動。
<body>
	<div>
	<button id="pan1">Translate</button>
	<button id="rotate1">Rotate</button>
	<button id="zoom1">Scale</button>
	<span id="sp">Action</span>
    </div>
	<img id="img1" src="assets/multicore_logo_300.png">
</body>
let img1;
let st = 0;  //-- 點擊狀態 0:未點擊狀態,1:點下狀態
let zIndex = 0; //-- img1的z-index的高度

let px1 = 0;
let py1 = 0;

function setup() {
	img1 = select("#img1");
	const pv1 = Object.assign({}, img1.position()); //-- 複製img1的原本的起始座標的獨立物件
	console.log(pv1);
	img1.position(pv1.x, pv1.y);
    
    px1 = pv1.x; 
	py1 = pv1.y;
}

let px0 = 0; //-- 點下時的起始座標
let py0 = 0;
let dx = 0; //-- 拖動的與起始座標差距值
let dy = 0;
let nx = 0; //-- 新的img1的座標
let ny = 0;
function mousePressed(e) {
	if (e.target.id === 'img1') {
		px0 = mouseX;
		py0 = mouseY;
		zIndex = img1.style("z-index"); //-- 起始的z-index高度
		img1.style("z-index", "10"); //-- 調整img1的z-index的高度
		st = 1;
	}
	return false;
}

function mouseDragged(e) {
	console.log(e.target.id);
	if (e.target.id === 'img1' && st == 1) {
		dx = mouseX - px0;
		dy = mouseY - py0;
		px0 = mouseX;
		py0 = mouseY;
		nx = img1.position().x + dx;
		ny = img1.position().y + dy;
        img1.position(nx, ny);  //-- 以點擊時的座標為基準
		//img1.position(mouseX-150+px1, mouseY-150+py1); //-- 會移到圖像元件的中心
	}
	return false;
}


function mouseReleased(e) {
	img1.style("z-index", zIndex); //-- 設定回原本的z-index高度
	st  0;
	return false;
}

以上的方法是將img1當作是DOM的元件來操作,平移的部份可以用 img1.position().x 及 img1.position().y來處理,但是DOM元件的旋轉,縮放操作,就沒有那麼直覺了,變的有點複雜,因此,接下來會以將img1畫在canvas的方法來處理。

不過這裡又遇到一個問題,除了img元件可以畫在canvas中,其他的DOM元件也能畫在canvas中嗎,
看起來,似乎要徹底了解在DOM元件中的「平移 Translate,旋轉 Rotate,縮放 Scale」操作的方法。

Transform 的操作

接下來是在body中,放入3個按鈕,分別是「平移 Translate,旋轉 Rotate,縮放 Scale」,根據按下不同的按鍵執行不同的操作。

先來了解一下transform的原理,設定的語法如下

object.style.transform = "translate(tx, ty)"; //-- tx, ty: 要加上單位: 100px
object.style.transform = "rotate(sd)";   //-- sd: 要加上單位: 100deg
object.style.transform = "scale(rx, ry)";  //-- rx, ry: 1.2: 不用加上單位

在設定上,translate(), rotate(), scale() 若是要同時呼叫的話,如下設定,用空白字隔開。
object.style.transform = "translate(tx, ty) rotate(sd) scale(rx, ry)";

如果要同時執行的話,也可以改用matrix()的方法
object.style.transform = "matrix(a, b, c, d, e, f)";

a, b, c, d的參數用來設定旋轉及縮放
sz: 縮放比例,1.0是原大小
sd: 旋轉角度,單位是弳度,可以用p5的指令 radians(deg) 將角度轉換成弳度
角度正值為順時針,角度負值為逆時針,0度的方向在正的X軸
tx, ty: 是指以元件的中心點為基準,進行元件內部的偏移,並不是像
select("#img1").position(mouseX, mouseY); 是移動整個元件的座標。

因此,若tx, ty設定為0, 0 圖像就會以左上角會基準點。
若tx, ty設定為-150, -150 圖像就會以中心點會基準點。

a, b, c, d, tx, ty: 不用加上單位

let a = sz * cos(sd);
let b = sz * sin(sd);
let c = sz * -sin(sd);
let d = sz * cos(sd);
let tx = -150;
let ty = -150;
let mx = `matrix( ${a}, ${b}, ${c}, ${d}, ${tx}, ${ty} )`; //-- 使用樣板字串的寫法比較精簡
//-- DOM 的的語法
document.querySelector("#img1").style.transform = mx;
//-- p5的語法
select("#img1").style("transform", mx);

以上整理如下
tx = -select("#img1").width/2;
ty = -select("#img1").height/2;

若是要移動元件的話,要使用
select("#img1").position(mouseX, mouseY);

或是加上繞圈圈的語法
select("#img1").position(mouseX+250cos(sd), mouseY+250sin(sd));

另外還有一個style屬性為 transform-origin 用來設定transform的原點座標,一般來說,預設座標是元件的中心點位置,例如:img的width及height分別為 300 x 300, transform-origin的預設值是 150px 150px,基本上可以不用處理,可以console.log()出來查看一下
設定如下:

object.style.transformOrigin = "150px 150px";
object.style.transformOrigin = "center center";

要查看的話,要用p5.js的元件呼叫才查得到實際的座標數值,如下

console.log(select("#img1").style("transform-origin"));

transform-origin 要在 transfrom 指令的後面,才會有作用,等於是在設定要以什麼transform-origin的位置來呈現transform的結果。

這個是p5的Element元件,有提供的指令,很方便使用。
這也是如果可以的話,要多多使用p5的DOM的功能,可以減少很多程式碼。
p5的DOM

以下是完整的程式碼

let imgw = 0;
let imgh = 0;

let sd = 0;
let sz = 1;

let px0 = 0;
let py0 = 0;
let img1;

function setup() {
	img1 = select("#img1");
	console.log(select("#img1"));

	imgw = img1.width;
	imgh = img1.height;
	console.log(imgw+", "+imgh);

	const pv1 = Object.assign({}, img1.position()); //-- 複製img1的原本的起始座標的獨立物件
	console.log(pv1);
	img1.position(pv1.x, pv1.y);

	px0 = pv1.x;
	py0 = pv1.y;

	//console.log(document.querySelector("#img1").style.transform);
	//document.getElementById("img1").style.transformOrigin = "center center";
	//console.log(select("#img1").style("transform-origin"));

}

function draw() {
	if (mouseIsPressed) {

		//img1.position(mouseX+px0+250*cos(sd), mouseY+py0+250*sin(sd));
		img1.position(mouseX+px0, mouseY+py0);

		sz = 1.0+0.5*sin(sd);
		sd += 0.1;

		//sz = 1;
		//sd = 0;

		let a = sz * cos(sd);
		let b = sz * sin(sd);
		let c = sz * -sin(sd);
		let d = sz * cos(sd);
		let tx = -imgw / 2.0;
		let ty = -imgh / 2.0;
		console.log(tx+", "+ty);
		let mx = `matrix( ${a}, ${b}, ${c}, ${d}, ${tx}, ${ty} )`;
		img1.style("transform", mx);
        
        //-- 3個transform的指令同時操作,中間以空白字隔開即可
        let mx0 = `translate(-150px, -150px) rotate(${sd*10}deg) scale(${sz})`;
        img1.style("transform", mx0);
        
        //-- 設定transform 的基準點, p5的語法, 可以得到實際得座標數值
        img1.style("transform-origin", "center center"); 
        
        //-- p5的語法, 可以得到實際得座標數值
        console.log(img1.style("transform-origin"));
        
        //-- 設定transform 的基準點, DOM的語法
        //img1.elt.style.transformOrigin = "center center";
		//document.getElementById("#img1").style.transformOrigin = "center center";
		return false;
	}

}

function mouseDragged(e) {
	return false;
}

參考資料
CSS transform Property
https://www.w3schools.com/cssref/css3_pr_transform.asp
transform-origin
https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin
Style transformOrigin Property
https://www.w3schools.com/jsref/prop_style_transformorigin.asp


上一篇
D25_手機事件操作[螢幕多點觸擊]
下一篇
D27_Canvas內容的座標與向量操作
系列文
從新開始學習p5.js畫出一片天40
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言