-
[ JS ] rotate3d 값 얻기Javascript/이론 2023. 2. 8. 13:55반응형
JS를 통해 요소의 rotate3d 프로퍼티를 얻기 위해서 만든 클래스입니다.
1. Constructor
constructor에서는 transform property를 얻고자 하는 요소를 parameter로 두었습니다. 따라서 클래스 성성시 요소를 받아 요소의 matrix3d 데이터를 저장합니다.
class Transform { constructor(ele) { this.ele = ele; this.matrix3d = window .getComputedStyle(ele) .getPropertyValue("transform") // column priority .split("(")[1] .split(")")[0] .split(",") .map((ele) => Number(ele)); } }
2. Method
1) show()
요소의 matrix3d 데이터를 행렬꼴로 콘솔창에 출력합니다.
show() { let temp = this.matrix3d.slice().map((ele) => Number(ele.toFixed(2))); if (temp.length === 6) { console.log( ` ${temp[0]} / ${temp[2]} / ${temp[4]} ${temp[1]} / ${temp[3]} / ${temp[5]} 0 / 0 / 1 ` ); } else if (temp.length === 16) { console.log( ` ${temp[0]} / ${temp[4]} / ${temp[8]} / ${temp[12]} ${temp[1]} / ${temp[5]} / ${temp[9]} / ${temp[13]} ${temp[2]} / ${temp[6]} / ${temp[10]} / ${temp[14]} ${temp[3]} / ${temp[7]} / ${temp[11]} / ${temp[15]} ` ); } return; }
2) showAllFactors()
메서드에서는 각 변환 인자를 콘솔창에 출력합니다.
showAllFactors() { let t = this.getTranslateFactors(); let s = this.getScaleFactors(); let r = this.getRotateFactors(); console.log("\n--------------translation--------------\n"); Object.keys(t).forEach((ele) => console.log(`${ele} : ${t[ele]}`)); console.log("\n---------------scaling-----------------\n"); Object.keys(s).forEach((ele) => console.log(`${ele} : ${s[ele]}`)); console.log("\n---------------rotation----------------\n"); Object.keys(r).forEach((ele) => console.log(`${ele} : ${r[ele]}`)); }
3) getTranslateFactors
tx, ty, tz의 키값을 가지는 객체로 translation에 사용된 인자를 반환합니다. 각 key에 대응하는 value의 자료형은 숫자입니다.
getTranslateFactors() { if (this.matrix3d.length === 6) return { tx: this.matrix3d[4].toFixed(2), ty: this.matrix3d[5].toFixed(2), }; if (this.matrix3d.length === 16) return { tx: this.matrix3d[12].toFixed(2), ty: this.matrix3d[13].toFixed(2), tz: this.matrix3d[14].toFixed(2), }; }
4) getScaleFactors
sx, sy, sz의 키값을 가지는 객체로 scalling에 사용된 인자를 반환합니다. 각 key에 대응하는 value의 자료형은 숫자입니다.
getScaleFactors() { if (this.matrix3d.length === 6) return { sx: Math.pow( this.matrix3d[0] ** 2 + this.matrix3d[2] ** 2, 0.5 ).toFixed(2), sy: Math.pow( this.matrix3d[1] ** 2 + this.matrix3d[3] ** 2, 0.5 ).toFixed(2), }; if (this.matrix3d.length === 16) return { sx: Math.pow( this.matrix3d[0] ** 2 + this.matrix3d[4] ** 2 + this.matrix3d[8] ** 2, 0.5 ).toFixed(2), sy: Math.pow( this.matrix3d[1] ** 2 + this.matrix3d[5] ** 2 + this.matrix3d[9] ** 2, 0.5 ).toFixed(2), sz: Math.pow( this.matrix3d[2] ** 2 + this.matrix3d[6] ** 2 + this.matrix3d[10] ** 2, 0.5 ).toFixed(2), }; }
(5) getRotateFactors
u, deg를 키값으로 갖는 객체로 rotate 인자를 반환합니다. 앞서 정의된 getScaleFactors()를 이용해 요소의 matrix3d 데이터에서 scaling factor를 제거하며, u와 deg를 구하는 원리는 아래 링크에서 확인 가능합니다.
각 key에 대응하는 value의 자료형은 사용의 편의성을 위해 문자열로 반환합니다.
getRotateFactors() { let scaleFactors = Object.values(this.getScaleFactors()); let dimension = scaleFactors.length; let tempMatrix = this.matrix3d.slice(); let deg; if (dimension === 2) { [0, 1].forEach((ele) => { for (let i = 0; i < 2; i++) { tempMatrix[ele + 2 * i] /= scaleFactors[ele]; } }); deg = (Math.acos(tempMatrix[0]) * 180) / Math.PI; return { u: undefined, deg: deg.toFixed(2) + "deg" }; } else if (dimension === 3) { [0, 1, 2].forEach((ele) => { for (let i = 0; i < 3; i++) { tempMatrix[ele + 4 * i] /= scaleFactors[ele]; } }); let u = [ tempMatrix[6] - tempMatrix[9], tempMatrix[8] - tempMatrix[2], tempMatrix[1] - tempMatrix[4], ]; if (u[0].toFixed(2) != 1) { deg = (Math.acos((tempMatrix[0] - u[0] ** 2) / (1 - u[0] ** 2)) * 180) / Math.PI; } else if (u[1].toFixed(2) != 1) { deg = (Math.acos((tempMatrix[5] - u[1] ** 2) / (1 - u[1] ** 2)) * 180) / Math.PI; } else if (u[2].toFixed(2) != 1) { deg = (Math.acos((tempMatrix[10] - u[2] ** 2) / (1 - u[2] ** 2)) * 180) / Math.PI; } return { u: u.map((ele) => ele.toFixed(2)).join(","), deg: deg.toFixed(2) + "deg", }; } }
6) setSameTransformTo
클래스 생성시 인자로 전달받은 요소의 trasform property에 적용된 translation, scaling, rotation을 메서드의 인자로 받은 요소에 적용합니다.
setSameTransformTo(ele) { let t = this.getTranslateFactors(); let s = this.getScaleFactors(); let r = this.getRotateFactors(); console.log(t, s, r); ele.style.transform = `translate3d(${t["tx"]}px, ${t["ty"]}px, ${ t["tz"] }px) scale3d(${s["sx"] + "," + s["sy"] + "," + s["sz"]}) rotate3d(${ r["u"] }, ${r["deg"]})`; }
3. Full code
class Transform { constructor(ele) { this.ele = ele; this.matrix3d = window .getComputedStyle(ele) .getPropertyValue("transform") // column priority .split("(")[1] .split(")")[0] .split(",") .map((ele) => Number(ele)); } show() { let temp = this.matrix3d.slice().map((ele) => Number(ele.toFixed(2))); if (temp.length === 6) { console.log( ` ${temp[0]} / ${temp[2]} / ${temp[4]} ${temp[1]} / ${temp[3]} / ${temp[5]} 0 / 0 / 1 ` ); } else if (temp.length === 16) { console.log( ` ${temp[0]} / ${temp[4]} / ${temp[8]} / ${temp[12]} ${temp[1]} / ${temp[5]} / ${temp[9]} / ${temp[13]} ${temp[2]} / ${temp[6]} / ${temp[10]} / ${temp[14]} ${temp[3]} / ${temp[7]} / ${temp[11]} / ${temp[15]} ` ); } return; } showAllFactors() { let t = this.getTranslateFactors(); let s = this.getScaleFactors(); let r = this.getRotateFactors(); console.log("\n--------------translation--------------\n"); Object.keys(t).forEach((ele) => console.log(`${ele} : ${t[ele]}`)); console.log("\n---------------scaling-----------------\n"); Object.keys(s).forEach((ele) => console.log(`${ele} : ${s[ele]}`)); console.log("\n---------------rotation----------------\n"); Object.keys(r).forEach((ele) => console.log(`${ele} : ${r[ele]}`)); } getTranslateFactors() { if (this.matrix3d.length === 6) return { tx: this.matrix3d[4].toFixed(2), ty: this.matrix3d[5].toFixed(2), }; if (this.matrix3d.length === 16) return { tx: this.matrix3d[12].toFixed(2), ty: this.matrix3d[13].toFixed(2), tz: this.matrix3d[14].toFixed(2), }; } getScaleFactors() { if (this.matrix3d.length === 6) return { sx: Math.pow( this.matrix3d[0] ** 2 + this.matrix3d[2] ** 2, 0.5 ).toFixed(2), sy: Math.pow( this.matrix3d[1] ** 2 + this.matrix3d[3] ** 2, 0.5 ).toFixed(2), }; if (this.matrix3d.length === 16) return { sx: Math.pow( this.matrix3d[0] ** 2 + this.matrix3d[4] ** 2 + this.matrix3d[8] ** 2, 0.5 ).toFixed(2), sy: Math.pow( this.matrix3d[1] ** 2 + this.matrix3d[5] ** 2 + this.matrix3d[9] ** 2, 0.5 ).toFixed(2), sz: Math.pow( this.matrix3d[2] ** 2 + this.matrix3d[6] ** 2 + this.matrix3d[10] ** 2, 0.5 ).toFixed(2), }; } getRotateFactors() { let scaleFactors = Object.values(this.getScaleFactors()); let dimension = scaleFactors.length; let tempMatrix = this.matrix3d.slice(); let deg; if (dimension === 2) { [0, 1].forEach((ele) => { for (let i = 0; i < 2; i++) { tempMatrix[ele + 2 * i] /= scaleFactors[ele]; } }); deg = (Math.acos(tempMatrix[0]) * 180) / Math.PI; return { u: undefined, deg: deg.toFixed(2) + "deg" }; } else if (dimension === 3) { [0, 1, 2].forEach((ele) => { for (let i = 0; i < 3; i++) { tempMatrix[ele + 4 * i] /= scaleFactors[ele]; } }); let u = [ tempMatrix[6] - tempMatrix[9], tempMatrix[8] - tempMatrix[2], tempMatrix[1] - tempMatrix[4], ]; if (u[0].toFixed(2) != 1) { deg = (Math.acos((tempMatrix[0] - u[0] ** 2) / (1 - u[0] ** 2)) * 180) / Math.PI; } else if (u[1].toFixed(2) != 1) { deg = (Math.acos((tempMatrix[5] - u[1] ** 2) / (1 - u[1] ** 2)) * 180) / Math.PI; } else if (u[2].toFixed(2) != 1) { deg = (Math.acos((tempMatrix[10] - u[2] ** 2) / (1 - u[2] ** 2)) * 180) / Math.PI; } return { u: u.map((ele) => ele.toFixed(2)).join(","), deg: deg.toFixed(2) + "deg", }; } } setSameTransformTo(ele) { let t = this.getTranslateFactors(); let s = this.getScaleFactors(); let r = this.getRotateFactors(); console.log(t, s, r); ele.style.transform = `translate3d(${t["tx"]}px, ${t["ty"]}px, ${ t["tz"] }px) scale3d(${s["sx"] + "," + s["sy"] + "," + s["sz"]}) rotate3d(${ r["u"] }, ${r["deg"]})`; } }
반응형'Javascript > 이론' 카테고리의 다른 글
[ JS ] trigger HTTP request (0) 2023.03.22 [ JS ] 이벤트 버블링(Bubbling) & 캡쳐링(Capturing) (0) 2023.03.11 [ JS ] Date 객체와 메서드 (0) 2023.01.01 [ JS ] 표준 입력 - process.stdin (0) 2022.12.29 [JS] .length는 함수가 아니라 프로퍼티이다. (0) 2022.12.28