Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- SSL
- Eclipse
- tomcat
- es6
- SPC
- vaadin
- Sqoop
- GIT
- IntelliJ
- 공정능력
- react
- mapreduce
- hadoop
- window
- Python
- R
- plugin
- Spring
- JavaScript
- 보조정렬
- Java
- xPlatform
- Kotlin
- mybatis
- Express
- MSSQL
- SQL
- NPM
- Android
- table
Archives
- Today
- Total
DBILITY
div move + rotate + resize test 본문
반응형
수학을 열심히 해야 하는 이유가 이런 것이었다. 삼각함수, 회전 변환..집에 가서 '수학이 필요한 순간'을 읽어야겠다.
우측과 하단(가장 쉬운 형태)으로 크기 변경이 가능하고 이동, 회전도 된다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.container {
position: absolute;
margin: 0;
width: 100%;
min-height: 100%;
box-shadow: 0 0 0 1px #000 inset;
padding: 0;
}
.layer {
position: absolute;
width: 200px;
height: 200px;
text-align: center;
padding: 0;
border: 1px dotted black;
vertical-align: middle;
left: calc(50% - 100px);
top: calc(50% - 100px);
transform: rotate(0deg);
padding: 0;
margin: 0;
}
.border-red {
cursor: all-scroll;
border-color: red;
}
.border-black {
cursor: default;
border-color: black;
}
.ui-rotate-handle {
width: 20px;
height: 20px;
background-color: transparent;
border: 0px solid #000000;
position: absolute;
}
.ui-rotate-s {
bottom: -40px;
left: calc(50% - 10px);
cursor: grab;
background-image: url("./image/arrow-repeat.svg");
background-repeat: no-repeat;
background-size: 100%;
}
.ui-rotate-dsp-handle {
width: 33px;
height: 20px;
background-color: transparent;
border: 1px solid darkcyan;
position: absolute;
}
.ui-rotate-dsp-output {
bottom: -40px;
left: calc(50% + 20px);
cursor: auto;
color: darkcyan;
}
.ui-resizable-handle {
width: 16px;
height: 16px;
background-color: transparent;
border: 0px solid #000000;
position: absolute;
}
.ui-resizable-e {
right: -8px;
top: calc(50% - 8px);
cursor: grab;
background-image: url("./image/arrows-expand-horizontal.svg");
background-repeat: no-repeat;
background-size: 100%;
}
.ui-resizable-s {
bottom: -8px;
left: calc(50% - 8px);
cursor: grab;
background-image: url("./image/arrows-expand-vertical.svg");
background-repeat: no-repeat;
background-size: 100%;
}
img {
max-width: 100%;
max-height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
</style>
</head>
<body>
<div class="container">
<div class="layer">
<img src="https://dummyimage.com/200x200/fff/000.png&text=Rotate,Move,Resize!" alt="">
</div>
</div>
<script>
const log = function () {
for (argument of arguments) {
console.log(argument);
}
};
let eEle, sEle, angleDsp, rotator;
let resizeOn = false;
let dragOn = false;
let rotateOn = false;
let mouseMoveX = 0, mouseMoveY = 0, mouseDownX = 0, mouseDownY = 0;
const MIN_WIDTH = 16, MIN_HEIGHT = 16;
let layers = document.getElementsByClassName("layer");
let container = document.getElementsByClassName("container")[0];
rotator = document.createElement("div");
rotator.classList.add("ui-rotate-handle", "ui-rotate-s");
rotator.id = "rotator";
eEle = document.createElement("div");
sEle = document.createElement("div");
eEle.classList.add("ui-resizable-handle","ui-resizable-e");
sEle.classList.add("ui-resizable-handle","ui-resizable-s");
angleDsp = document.createElement("div");
angleDsp.classList.add("ui-rotate-dsp-handle", "ui-rotate-dsp-output");
angleDsp.innerText = "0";
const fnGetAngle = function (element) {
let val = {degree: 0, radian: 0};
let tgt = window.getComputedStyle(element, null);
let tf = tgt.getPropertyValue("-webkit-transform") ||
tgt.getPropertyValue("-moz-transform") ||
tgt.getPropertyValue("-ms-transform") ||
tgt.getPropertyValue("-o-transform") ||
tgt.getPropertyValue("transform") ||
"none";
if (tf && tf != "none") {
let matrix = tf.split("(")[1].split(")")[0].split(",");
let radian = Math.atan2(Number(matrix[1]), Number(matrix[0])); // radian
let degree = Math.round(radian * 180 / Math.PI);
degree = degree >= 360 ? 360 - degree : (degree < 0 ? 360 + degree : degree);
radian = Math.round((degree * Math.PI / 180) * 1000000) / 1000000;
val.degree = degree;
val.radian = radian;
}
return val;
};
const fnGetNewPosition = function (element, newWidth, newHeight) {
let angle = fnGetAngle(element);
let pos = {left: element.offsetLeft, top: element.offsetTop};
let initW = element.clientWidth;
let initH = element.clientHeight;
let x = Math.round(-initW / 2);
let y = Math.round(initH / 2);
let newX = y * Math.sin(angle.radian) + x * Math.cos(angle.radian);
let newY = y * Math.cos(angle.radian) - x * Math.sin(angle.radian);
let diff1 = {left: Math.round(newX - x), top: Math.round(newY - y)};
let newW = newWidth;
let newH = newHeight;
x = Math.round(-newW / 2);
y = Math.round(newH / 2);
newX = y * Math.sin(angle.radian) + x * Math.cos(angle.radian);
newY = y * Math.cos(angle.radian) - x * Math.sin(angle.radian);
let diff2 = {left: Math.round(newX - x), top: Math.round(newY - y)};
let offset = {left: diff2.left - diff1.left, top: diff2.top - diff1.top};
let newPos = {left: pos.left - offset.left, top: pos.top + offset.top};
return newPos;
};
window.addEventListener("load", e => {
rotator.addEventListener("mousedown", function(e) {
dragOn = false;
rotateOn = true;
resizeOn = false;
let target = this.parentElement;
let cx = target.offsetLeft + (target.offsetWidth / 2); //회전대상 원점X
let cy = target.offsetTop + (target.offsetHeight / 2); //회전대상 원점Y
e.preventDefault();
e.stopPropagation();
container.onmousemove = e => {
if(!rotateOn) return;
e.preventDefault();
if (target != null) {
//atan2는 두 점 사이의 상대좌표(x, y)의 절대각을 -π ~ π의 라디안 값으로 반환한다.
let radian = Math.atan2(e.pageY - cy, e.pageX - cx);
let degree = Math.round(radian * 180 / Math.PI) - 90; // radian to degree
target.style.transform = "rotate(" + degree + "deg)"; // 대상 회전
this.style.transform = "rotate(" + degree + "deg)"; // 로테이터 회전
angleDsp.style.transform = "rotate(" + (360-degree) + "deg)"; // 각도표시영역 역회전
angleDsp.innerText = degree >= 360 ? 360 - degree : (degree < 0 ? 360 + degree : degree)+"˚"; // 각도표시
//내부에 this로 자신을 참조하고 싶으면 arrow function을 사용하지 말라고 적혀 있음. 위의 this는 rotator
}
};
layers[0].appendChild(angleDsp);
angleDsp.onmousedown = e => {
e.preventDefault();
e.stopPropagation();
dragOn = false;
rotateOn = false
resizeOn = false;
};
});
rotator.addEventListener("mouseup", function(e) {
rotator.onmousemove = null;
container.onmousemove = null;
document.onmousemove = null;
eEle.onmousemove = null;
sEle.onmousemove = null;
rotateOn = false;
});
layers[0].addEventListener("mouseover", function(e) {
this.classList.remove("border-black");
this.classList.add("border-red");
});
layers[0].addEventListener("mouseout", function(e) {
this.classList.remove("border-red");
this.classList.add("border-black");
});
layers[0].addEventListener("mousedown", function(e) {
if(layers[0].contains(angleDsp)) {
layers[0].removeChild(angleDsp);
}
dragOn = true;
rotateOn = false;
resizeOn = false;
this.appendChild(rotator);
e.preventDefault();
e.stopPropagation();
mouseMoveX = 0, mouseMoveY = 0;
mouseDownX = e.clientX;
mouseDownY = e.clientY;
let target = this;
container.onmousemove = function(e) {
if(resizeOn) return;
e.preventDefault();
e.stopPropagation();
mouseMoveX = mouseDownX - e.clientX;
mouseMoveY = mouseDownY - e.clientY;
mouseDownX = e.clientX;
mouseDownY = e.clientY;
let targetX = target.offsetLeft - mouseMoveX;
let targetY = target.offsetTop - mouseMoveY;
let availX = container.clientWidth - target.clientWidth;
let availY = container.clientHeight - target.clientHeight;
let offsetLeft = (targetX >= 0 && targetX <= availX ? targetX : targetX > availX ? availX : 0);
let offsetTop = (targetY >= 0 && targetY <= availY ? targetY : targetY > availY ? availY : 0);
target.style.left = offsetLeft + "px";
target.style.top = offsetTop + "px";
};
/* 우측 */
layers[0].appendChild(eEle);
eEle.addEventListener("mousedown", function(e) {
if(layers[0].contains(angleDsp)) {
layers[0].removeChild(angleDsp);
}
mouseMoveX = 0;
dragOn = false;
rotateOn = false
resizeOn = true;
e.preventDefault();
e.stopPropagation();
let target = this.parentElement;
container.onmousemove = function(e) {
resizeOn = true;
e.preventDefault();
e.stopPropagation();
mouseMoveX = e.clientX - target.offsetLeft;
if(mouseMoveX > MIN_WIDTH) {
let newPos = fnGetNewPosition(target, mouseMoveX, target.clientHeight);
target.style.left = newPos.left + "px";
target.style.top = newPos.top + "px";
target.style.width = mouseMoveX + "px";
} else {
resizeOn = false;
}
};
});
/* 하단 */
layers[0].appendChild(sEle);
sEle.addEventListener("mousedown",function(e) {
if(layers[0].contains(angleDsp)) {
layers[0].removeChild(angleDsp);
}
mouseMoveY = 0;
dragOn = false;
rotateOn = false
resizeOn = true;
e.preventDefault();
e.stopPropagation();
let target = this.parentElement;
container.onmousemove = function(e) {
e.preventDefault();
e.stopPropagation();
mouseMoveY = e.clientY - target.offsetTop;
if(mouseMoveY > MIN_HEIGHT) {
let newPos = fnGetNewPosition(target, target.clientWidth, mouseMoveY);
target.style.left = newPos.left + "px";
target.style.top = newPos.top + "px";
target.style.height = mouseMoveY + "px";
} else {
resizeOn = false;
}
};
});
});
document.addEventListener("mouseup", e => {
e.preventDefault();
e.stopPropagation();
rotator.onmousemove = null;
container.onmousemove = null;
document.onmousemove = null;
dragOn = false;
rotateOn = false;
resizeOn = false;
mouseMoveX = 0, mouseMoveY = 0, mouseDownX = 0, mouseDownY = 0;
});
container.addEventListener("mousedown", e => {
e.preventDefault();
e.stopPropagation();
let objArray = [rotator, eEle, sEle, angleDsp];
for (const objArrayElement of objArray) {
if (layers[0].contains(objArrayElement)) {
layers[0].removeChild(objArrayElement);
}
}
dragOn = false;
rotateOn = false;
resizeOn = false;
mouseMoveX = 0, mouseMoveY = 0, mouseDownX = 0, mouseDownY = 0;
});
});
</script>
</body>
</html>
반응형
'front-end & ui > javascript' 카테고리의 다른 글
kendogrid auto scroll to row and select (0) | 2021.09.28 |
---|---|
javascript currency number format (0) | 2021.08.06 |
div rotate test (0) | 2021.05.18 |
div drag test (0) | 2021.05.14 |
EventSource + Spring Server Sent Event (0) | 2021.05.12 |
Comments