데모 페이지 : https://ohikmyeong.github.io/resize_dom/
깃 허브 : https://github.com/OhIkmyeong/resize_dom
HTML
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
31
32
33
34
35
36
37
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vanilla JS : Resizable</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{min-height:100vh;}
img{width:100%;height:100%;pointer-events:none;}
.resizable{
position:absolute;top:0;left:0;background:#eee; width:500px; height:200px;
min-width:100px;min-height:100px;
}
.resizable p{font-size:1rem;}
.btn-resize{
display:block;position:absolute;
right:0;bottom:0;
width:40px; aspect-ratio:1/1;
background:#eee;
border:2px solid black;
cursor:nwse-resize;
}
</style>
<script src="./js/main.js" type="module"></script>
</head>
<body>
<div class="resizable modal" data-resizable="true" data-modal>
<img src="https://source.unsplash.com/dqu6jrYxJ7I" alt="샘플 이미지"/>
</div>
<div class="resizable modal" data-resizable="true" data-modal>
<img src="https://source.unsplash.com/xS9KgKrR3ac" alt="샘플 이미지"/>
</div>
</body>
</html>
|
cs |
main.js
1
2
3
4
5
6
|
import { Modal_Ctrl } from "./Modal.js";
// import { Resizable } from "./Resizable.js";
// const RESIZE = new Resizable();
const MODAL = new Modal_Ctrl();
MODAL.init();
|
cs |
Modal.js (Draggable)
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import { Resize } from "./Resizable.js"; export class Modal_Ctrl{ /** 준비 */ init(){ //모달 드래그 관련 const $$modal = document.querySelectorAll('[data-modal]'); if(!$$modal.length){return;} for(let $modal of $$modal){ $modal && new Draggable($modal); }//for }//init }//class-Modal_Ctrl /* ----------- 모달 드래그 ------------ */ /* 윈도우 사이즈 */ const WINDOW_SIZE = { wid : window.innerWidth, hei : window.innerHeight }; /** 윈도우 사이즈 업데이트 */ function update_window_size(){ WINDOW_SIZE.wid = window.innerWidth; WINDOW_SIZE.hei = window.innerHeight; }//update_window_size /** 윈도우 드래그 해제 * @deprecated 원래는 모달 드래그시 셀렉션(드래그 선택)되는 현상을 막으려고 만들어놨으나, 정작 모달 안의 input같은것들이 바로 포커스 해제 되는 문제가 발생하여 사용하지 않습니다. * @see https://w3c.github.io/selection-api * @see https://stackoverflow.com/questions/3169786/clear-text-selection-with-javascript */ export function clear_selection(){ if (window.getSelection().empty) { // Chrome window.getSelection().empty(); }else if(window.getSelection().removeAllRanges){ // Firefox window.getSelection().removeAllRanges(); } }//clear_selection /* CLASS - DRAGGABLE */ class Draggable{ /** MODAL을 드래그 가능하게 만들어 줍니다. * @param $wrap DOM .wrap-modal */ constructor($wrap){ this.$modal = $wrap; console.log(this.$modal); this.is_draggable = false; this.SIZE = { wid : this.$modal.getBoundingClientRect().width, hei : this.$modal.getBoundingClientRect().height} this.LIMIT = { right : WINDOW_SIZE.wid - (this.SIZE.wid / 2), bottom : WINDOW_SIZE.hei - (this.SIZE.hei / 2)} this.POS = { last : {x:null, y:null}, final : {x:null, y:null}} //실행 this.RESIZE = new Resize(this); this.init(); }//constructor; /** 드래그 기능 실행 시작 */ init(){ this.$modal.addEventListener('mousedown', this.ready_to_drag, {once:true}); }//init /** 드래그 준비(mousedown) * @param e event */ ready_to_drag = (e) =>{ this.is_draggable = true; this.POS.last.x = e.clientX - this.$modal.getBoundingClientRect().left; this.POS.last.y = e.clientY - this.$modal.getBoundingClientRect().top; /* update limit size.. */ update_window_size(); this.LIMIT.right = WINDOW_SIZE.wid - (this.SIZE.wid / 2); this.LIMIT.bottom = WINDOW_SIZE.hei - (this.SIZE.hei / 2); window.addEventListener('mousemove', this.on_drag); window.addEventListener('mouseup',this.stop_drag,{once:true}); window.addEventListener('mouseleave',this.stop_drag,{once:true}); }//ready_to_drag /** 드래그 중(mousemove) * @param e event */ on_drag = (e) => { if(!this.is_draggable){return;} if(this.RESIZE.IS_REISZE) return; const currX = e.clientX - this.POS.last.x; const currY = e.clientY - this.POS.last.y; /* X축 */ if(currX <= (this.SIZE.wid / -2)){ this.POS.final.x = (this.SIZE.wid / -2); }else if(currX > this.LIMIT.right){ this.POS.final.x = this.LIMIT.right; }else{ this.POS.final.x = currX;} /* Y축 */ if(currY <= 0){ this.POS.final.y = 0; }else if(currY > this.LIMIT.bottom){ this.POS.final.y = this.LIMIT.bottom; }else{ this.POS.final.y = currY;} /* 최종 css 적용 */ const {final:{x,y}} = this.POS; this.$modal.style.transform = `translate(${x}px,${y}px)`; clear_selection(); }//on_drag /** 드래그 끝(mouseup) */ stop_drag = () => { this.is_draggable = false; this.POS.last.x = this.$modal.getBoundingClientRect().left; this.POS.last.y = this.$modal.getBoundingClientRect().top; window.removeEventListener('mousemove', this.on_drag); this.$modal.addEventListener('mousedown', this.ready_to_drag, {once:true}); }//stop_drag }//class-Draggable | cs |
Resizable
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
export class Resizable{
/** make DOM(data-resizable="true") Resizable */
constructor(){
this.$$dom = Array.from(document.querySelectorAll('[data-resizable]'));
this.$$dom.forEach($dom => new Resize($dom));
}//constructor
}//Resizable
export class Resize{
constructor(DRAG){
this.DRAG = DRAG;
this.$dom = this.DRAG.$modal;
this.$btn = null;
this.IS_REISZE = false;
this.POS_START = {x:null, y:null};
this.init();
}//constructor
/** Init Resizable */
init(){
this.$btn = this.add_btn();
this.$btn.addEventListener('mousedown', this.on_down,{once:true});
}//init
/** resize 가능한 버튼 추가
* @returns <button.btn-resize>
*/
add_btn(){
const $btn = document.createElement('BUTTON');
$btn.classList.add('btn-resize');
$btn.title = "사이즈조절";
this.$dom.appendChild($btn);
return $btn;
}//add_btn
on_down = (e) =>{
this.IS_REISZE = true;
this.POS_START.x = e.clientX;
this.POS_START.y = e.clientY;
window.addEventListener('mousemove', this.on_move);
window.addEventListener('mouseup', this.cancel,{once:true});
}//on_down
cancel = () => {
this.IS_REISZE = false;
window.removeEventListener('mousemove', this.on_move);
this.$btn.addEventListener('mousedown', this.on_down,{once:true});
}//cancel
on_move = e =>{
if(!this.IS_REISZE) return;
if(!this.DRAG.is_draggable) return;
const {x,y} = this.POS_START;
const nowX = e.clientX;
const nowY = e.clientY;
const wid = this.$dom.offsetWidth;
const hei = this.$dom.offsetHeight;
if(x < nowX){
const per = (nowX - x);
this.$dom.style.width = `${wid + per}px`;
}
if(x >= nowX){
const per = (x - nowX);
this.$dom.style.width = `${wid - per}px`;
}
if(y < nowY){
const per = (nowY - y);
this.$dom.style.height = `${hei + per}px`;
}
if(y >= nowY){
const per = (y - nowY);
this.$dom.style.height = `${hei - per}px`;
}
this.POS_START.x = nowX;
this.POS_START.y = nowY;
}//on_move
get_size(size,per){}//get_size
}//Resize
|
cs |
'CSS&JS > ⚡Thinkers' 카테고리의 다른 글
[CSS,JS] 타임 슬라이더 (0) | 2022.10.11 |
---|---|
[vanilla JS] 바닐라 자바스크립트로 무한 슬라이더 만들기. v1.0 (0) | 2022.10.11 |
clipText (0) | 2022.07.25 |
Table Builder 2.0 (0) | 2022.07.22 |
Table Builder (0) | 2022.07.08 |