반응형

비밀번호등을 받기 위해 숫자나 특정 단어 하나씩 입력하고 다음칸으로 이동하는 형태의 UI를 많이 접할 수 있습니다.

해당 포스팅에서는 하나의 Input태그마다 입력을 받으면 다음칸으로 이동하고 숫자만 받는 형태를 작성해보겠습니다.

 

단순하게 maxlength와 number값 타입을 지정하더라도 영문 'e' 또는 한글 자음 모음등이 입력되는 현상😓을 볼 수 있는데, 정규식과 사용할 수 있는 이벤트등을 활용하여 처리하였습니다.😋

 

좀 더 좋은 깔끔한 방식이 있다면 댓글 부탁드립니다!🙆‍♀️

<input type="tel" maxlength="1" min="0" max="9" onlyNumber>
$(function(){
    $(document).on("keypress keyup keydown", "input[onlyNumber]", function(e){
        console.log(e.which);
        if(/[a-z|ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/g.test(this.value)){ //한글 막기
            e.preventDefault();
            this.value = "";
        }else if (e.which != 8 && e.which != 0 //영문 e막기
            && e.which < 48 || e.which > 57    //숫자키만 받기
            && e.which < 96 || e.which > 105){ //텐키 받기
            e.preventDefault();
            this.value = "";
        }else if (this.value.length >= this.maxLength){ //1자리 이상 입력되면 다음 input으로 이동시키기
            this.value = this.value.slice(0, this.maxLength);
            if($(this).next("input").length > 0){
                $(this).next().focus();
            }else{
                $(this).blur();
            }
        }
    });    
});

태그 input에 type을 tel로 한 이유는 모바일 환경에서 넘버패드로 먼저 동작하도록 하기 위해 처리하였고, input태그 내부에 onlyNumber라는 속성이 있으면 동일하게 동작하도록 처리하였습니다.

 

마지막 else if문에서 길이를 체크하고 maxlength값만큼 커지거나 같아지면 다음 input이 있는지 체크 후 자동으로 포커싱하는 스크립트입니다.

 

 

동작테스트는 아래 codePen⌨을 활용해주세요!

See the Pen Get one number by one by myhappyman (@myhappyman) on CodePen.

 

 

 

 

반응형
  1. Favicon of https://weedev.tistory.com TulraPaul 2021.07.05 10:50 신고

    매번 잘 보고 있습니다
    좋은글 감사합니다. ^_^..

    • Favicon of https://myhappyman.tistory.com Park.S.W 2021.07.05 11:14 신고

      작성한 글들 봐주러 오셔서 감사합니다 :)
      좋은 하루 보내세요😁

  2. mingming 2022.08.30 13:47

    이제 시작하는 코린이라서 input 해봤는데 number에서 e가 나와서 왤까 검색해봤더니 딱 해결방안이 있네요. 근데 왜 나오는건가요???
    오류인건지 궁금하네요...

    • Favicon of https://myhappyman.tistory.com Park.S.W 2022.09.06 09:45 신고

      안녕하세요~
      수학에서 숫자적 의미로 부동소수점e를 처리하기 위해 허용하는것으로 알고있습니다!

      출처: https://stackoverflow.com/questions/31706611/why-does-the-html-input-with-type-number-allow-the-letter-e-to-be-entered-in

반응형

UI를 작성하다보면 input 박스 안에 버튼 이미지를 위치시키고 입력받은 값에 따라 보여주고 사라지고 제어등을 하게 되는 경우가 있다.

 

조건은 아래와 같다.

1. 입력하고자 하는 input에 focus를 잃는 경우(blur 발생) 버튼을 사라지게 하는 이벤트를 추가

2. 입력하는 input에 focus를 얻은 상태에서 입력중이면 버튼이 활성화

3. 활성화된 버튼을 클릭하면 input의 데이터가 다 지워짐

 

 

문제는 click보다 blur가 더 빨리 동작한다는 것이다.

 

stackoverflow의 글 덕분에 꼼수로 간단하게 해결하였다.

https://stackoverflow.com/questions/10652852/jquery-fire-click-before-blur-event

 

jQuery: fire click() before blur() event

I have an input field, where I try to make autocomplete suggestion. Code looks like

 
On input's blur() event I want to...

 

stackoverflow.com

 

 

click대신 mousedown 이벤트를 사용하였다.

 

아래는 실제 동작시킨 스크립트 코드이다.

$('.inp_box').on("mousedown", ".inp_remove_btn", function(){ //click 사용안됨 //blur가 더 빨리 동작함
    $(this).siblings("input").val("");

}).on("change keyup input", "input", function(e){ //입력이 시작되면 삭제버튼 활성화
    $(this).siblings(".inp_remove_btn").addClass("active");

}).on("blur", "input", function(e){ //input focus를 잃으면 삭제버튼 비활성화
    $(this).siblings(".inp_remove_btn").removeClass("active");

}).on("focus", "input", function(e){ //input focus를 얻으면 길이 체크하여 삭제버튼 활성화 유무체크
    if($(this).val().length > 0){
        $(this).siblings(".inp_remove_btn").addClass("active");
    }
});
반응형
반응형

파일 업로드 형태의 게시판 등 웹 UI에서 파일을 긁어와서 드롭하였을때 등록하고 ajax를 통해 업로드 하는 예제까지 진행해보겠습니다.(Spring Legacy 기준)

 

Drag And Drop

html, css

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<style>
    *{padding:0;margin:0}
    html, body, .wrap{width: 100%;}
    .clear{clear:both;}
    .wrap>.fileBox{padding: 20px;}
    .fileBox input, textarea{width: 100%;}
    .fileBox textarea{resize:none;}
    .fileBox .fileDrop{display: inline-block;width: 700px;height: 75px;border: 1px solid #000;overflow: auto;}
    .fileDrop .fileList .fileName{padding-left: 20px;}
    .fileDrop .fileList .fileSize{padding-right: 20px; float:right;}
</style>
<body>
    <div class="wrap">
        <div class="fileBox">
            <form id="fileForm" name="fileForm" enctype="multipart/form-data" method="post">
                <table>
                    <tr>
                        <td><input type="text" name="title"></td>
                    </tr>
                    <tr>
                        <td><textarea name="contents"></textarea></td>
                    </tr>
                    <tr>
                        <td><div id="fileDrop" class="fileDrop"></div></td>
                    </tr>
                </table>
                <div class="buttonBox">
                    <button type="button" id="save">저장</button>
                </div>
            </form>
        </div>
    </div>
</body>
</html>

js

var fileList = []; //파일 정보를 담아 둘 배열
$(function(){

    //드래그앤드랍
    $("#fileDrop").on("dragenter", function(e){
        e.preventDefault();
        e.stopPropagation();
    }).on("dragover", function(e){
        e.preventDefault();
        e.stopPropagation();
        $(this).css("background-color", "#FFD8D8");
    }).on("dragleave", function(e){
        e.preventDefault();
        e.stopPropagation();
        $(this).css("background-color", "#FFF");
    }).on("drop", function(e){
        e.preventDefault();

        var files = e.originalEvent.dataTransfer.files;
        if(files != null && files != undefined){
            var tag = "";
            for(i=0; i<files.length; i++){
                var f = files[i];
                fileList.push(f);
                var fileName = f.name;
                var fileSize = f.size / 1024 / 1024;
                fileSize = fileSize < 1 ? fileSize.toFixed(3) : fileSize.toFixed(1);
                tag += 
                        "<div class='fileList'>" +
                            "<span class='fileName'>"+fileName+"</span>" +
                            "<span class='fileSize'>"+fileSize+" MB</span>" +
                            "<span class='clear'></span>" +
                        "</div>";
            }
            $(this).append(tag);
        }

        $(this).css("background-color", "#FFF");
    });

    //저장
    $(document).on("click", "#save", function(){
        var formData = new FormData($("#fileForm")[0]);
        if(fileList.length > 0){
            fileList.forEach(function(f){
                formData.append("fileList", f);
            });
        }         

        $.ajax({
            url : "서버 맵핑 URL",
            data : formData,
            type:'POST',
            enctype:'multipart/form-data',
            processData:false,
            contentType:false,
            dataType:'json',
            cache:false,
            success:function(res){
                alert("저장에 성공하셨습니다.");
            },error:function(res){
                alert("오류 발생.\n관리자에게 문의해주세요.");
            }
        });
    });
});

drag관련 이벤트를 처리하고 싶은 개체에 등록하여 enter, over, leave, drop에 따른 처리를 각각 처리하였습니다.

drop하였을때는 파일을 내려놨을때 드래그앤드롭의 동작 중 가지고 있던 데이터의 정보를 확인하기 위해 dataTransfer 파일 정보를 가져옵니다.

 

이후 파일 정보가 담긴 object를 통해 하나씩 확인하여 tag를 생성하고 별도의 파일정보는 배열에 담아두었다가 서버에 전송시 사용합니다.

 

java - Server Controller

@ResponseBody
@RequestMapping(value = { "uploadPath" }, method = RequestMethod.POST, produces = "json/plain;charset=UTF-8")
public int uploadPath(MultipartHttpServletRequest mtfRequest, 
		final HttpServletRequest request, 
		final HttpServletResponse response) {
	int res = 1;
	System.out.println("제목 > " + request.getParameter("title"));
	System.out.println("내용 > " + request.getParameter("contents"));
	if(mtfRequest != null) {
		List<MultipartFile> fileList = mtfRequest.getFiles("fileList");
		for(int i=0; i<fileList.size(); i++) {
			MultipartFile multi = fileList.get(i);
			if(multi == null) {
				return 0;
			}else if(multi.getSize() == 0) {
				return 0;
			}else {
				System.out.println("파일명 : " + multi.getOriginalFilename() + " / 파일 사이즈 : " + multi.getSize());
			}
		}
	}
		
	return res;
}

ajax에서 전달한 데이터를 받을 컨트롤러입니다. 별도의 서비스나 처리는 하지 않았습니다.

전달된 데이터의 파라미터가 출력된 콘솔 결과는 아래와 같습니다.

컨트롤러에 전달된 데이터 정보

 

동작결과

반응형
반응형

체크박스가 포함된 게시판형태의 데이터들을 다루다보면 전체 선택 해제 기능이 자주 들어갑니다.

전체 선택에 따른 하위 체크박스들을 선택하거나 해제하고 전체박스가 선택된 상태에서 하위 체크박스를 해제하면 전체체크박스의 상태값도 해제되도록 변경되는 예제를 진행해보겠습니다.

 

체크박스 전체 선택, 해제 제어하기

allcheckbox.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<body>
    <table>
        <tr>
            <th>
                <input type="checkbox" name="check" class="allcheck">
            </th>
            <th>순번</th>
            <th>제목</th>
        </tr>
        <tr>
            <td><input type="checkbox" name="check"></td>
            <td>1</td>
            <td>제목입니다.</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="check"></td>
            <td>2</td>
            <td>제목입니다.</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="check"></td>
            <td>3</td>
            <td>제목입니다.</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="check"></td>
            <td>4</td>
            <td>제목입니다.</td>
        </tr>
    </table>
</body>
</html>

css

*{margin:0;padding:0;}
table{width:800px;text-align:center;border-collapse:collapse;border-left:1px solid #ddd;border-right: 1px solid #ddd;}
table tr{border-bottom: 1px solid #ddd;}

JS

$(function(){
    $("[type=checkbox][name=check]").on("change", function(){ //0
        var check = $(this).prop("checked"); //1
        //전체 체크
        if($(this).hasClass("allcheck")){ //2
            $("[type=checkbox][name=check]").prop("checked", check);

        //단일 체크
        }else{ //3
            var all = $("[type=checkbox][name=check].allcheck");
            var allcheck = all.prop("checked")
            if(check != allcheck){ //3-1
                var len = $("[type=checkbox][name=check]").not(".allcheck").length; //3-2
                var ckLen = $("[type=checkbox][name=check]:checked").not(".allcheck").length; //3-2
                if(len === ckLen){ //3-3
                    all.prop("checked", true);
                }else{
                    all.prop("checked", false);
                }
            }
        }
    });
});

저는 모든 체크박스의 이름을 check로 두었고 전체선택기능의 체크박스와 일반체크박스를 class에 allcheck라는 이름으로 구분하였습니다.

 

주석번호와 매칭하여 설명을 확인하시면 됩니다.

0. jQuery를 활용하여 페이지가 로드되면 체크박스에 이벤트를 추가합니다.

1. input type이 checkbox이면서 name값이 check인 요소에 change 이벤트가 발생하면 현재 발생한 요소의 checked 값을 받아옵니다.

2. 이벤트가 발생한 요소의 클래스에 allcheck가 존재하면 전체 체크박스로 판단하고 전체 체크를 진행합니다.

(해제가 되었으면 전부다 해제, 선택이면 전부 다 선택 처리이므로 자신의 상태값과 맞춰줍니다.) 

3. 단일 체크일 경우

   3-1. 전체 체크박스의 상태값과 자신의 상태값을 비교합니다. 상태가 다를 경우 확인 작업이 필요합니다.

   3-2. 페이지에 노출된 체크 박스의 개수와 체크된 개수가 같은지 확인을 하기 위해 값을 가져옵니다.

         여기서 .not()메소드를 사용하여 전체 체크박스는 제외하였습니다.

   3-3. 가져온 개수가 서로 같다면 전체가 이미 선택된 것이므로 전체체크박스에도 선택처리를 합니다.

         반대의 경우 전체가 체크된게 아니므로 전체체크박스에 해제처리를 합니다.

 

동작 결과

잘 동작한다!

반응형
  1. yunaa 2020.10.27 11:28

    감사합니다 :)

  2. Favicon of https://blog.naver.com/puzzler20 puzzler 2022.04.09 23:40

    글을 읽고 코드를 따라서 짜던 중 궁금한 점이 있어 글 남깁니다.
    3-1 에 전체 체크 박스의 상태값과 변화가 생긴 요소의 상태값이 일치하는지 여부를 왜 확인해야하는지 설명 부탁드립니다.

    감사합니다!

    • Favicon of https://myhappyman.tistory.com Park.S.W 2022.04.09 23:47 신고

      총 4개짜리의 게시글이 있다고 가정을 하겠습니다.
      3개를 체크해둔 상태이고, 남은 4번째를 체크를 하면서 모두 체크가 된 경우 전체체크박스도 체크가 된 형태가 되어야 하기 때문입니다.

  3. Favicon of http://https://blog.naver.com/puzzler20 puzzler 2022.04.10 18:01

    답변 감사합니다!

    3-1 과정을 거치지 않은 코드를 한번 작성해 보았습니다.
    Park.S.W님께 보여드리고 Park.S.W님의 생각을 듣고 싶었는데,
    글쓰는 곳에 코드를 그대로 복사하면 중간에 웃는 얼굴이 포함되네요.
    방법을 몰라 이렇게 글을 남깁니다.

    감사합니다.

    • Favicon of https://myhappyman.tistory.com Park.S.W 2022.04.11 09:00 신고

      안녕하세요!

      코딩은 아시다시피 답이 정해져 있지 않습니다. 오래 개발하신분이 무조건 좋은 코드를 짜는것도 아니기도 하구요!

      제가 제시한 방법을 거치지 않았지만 더 간단하고 동일한 조건이 충족되는 소스를 구성하셨다면 좋은 코드를 작성했다고 보면 되겠지요~!

      ps. 작성하신 코드의 공유를 원하신다면 CODEPEN과 같은 사이트에 글을 올리시고 공유 url을 남겨주시면 됩니다!

반응형

xhr(XMLHttpRequest) 객체는 서버와 데이터를 확인하기 위해 사용됩니다.

 

ajax또한 xhr 규격을 사용하여 동작하고 있고, 다양한 메소드를 통해 요청의 상태값이나 시간, 결과, 진행상태 등을 확인 할 수 있습니다.

 

여기서 xhr의 upload.onprogress 메소드를 사용하여 파일의 업로드 진행상황을 확인하고 UI적으로 페이지 진행상태를 표현 할 수 있습니다.

 

대량의 파일이나 다중으로 여러 파일을 넘길 때 상태를 알 수 있다보니 아무래도 기다리는데, 도움이 될 것 같습니다.

 

바로 예제를 통해 확인해 보겠습니다.

 

xhr.upload.progress

사용법 ajax로 넘길때 xhr메소드를 추가하고 내부에 upload.onprogress메소드를 추가하여 정의하고자 하는 파일 내용을 추가하면 됩니다.

xhr: function(){
	var xhr = $.ajaxSettings.xhr();
	xhr.upload.onprogress = function(e){
		var per = e.loaded * 100 / e.total;
		console.log(per);
	};
	return xhr;
},

 

 

사용예제

fileupload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<style>
	*{margin:0;padding:0}
	.progressContainer{position:relative;width: 450px;padding:20px 10px;border: 1px solid #eee;margin-top: 15px;background:#000;height:20px;}
	.progress{position:absolute;width: calc(100% - 20px);height: 20px;}
	.progressTotal{background: #5D5D5D;border-radius: 10px;}
	.progressNow{width: calc(0% - 20px);background: #FFF;border-radius: 10px;}
	.progressPer{background: transparent; text-align:center;color:#A6A6A6;}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<body>
<h1>
	File Upload Test
</h1>

<P>  The time on the server is ${serverTime}. </P>
	<div style="width: 100%;padding: 25px;">
		<form id="fileForm" action="/upload.do" method="post" enctype="multipart/form-data">
			<input type="file" name="uploadFile" multiple>
			<button type="button" id="btn">전송</button>
		</form>
		<div class="progressContainer">
			<div class="progress progressTotal"></div>
			<div class="progress progressNow"></div>
			<div class="progress progressPer">0 %</div>
		</div>
	</div>
</body>
<script>
	$(function(){	
		$("#btn").on("click", function(){
			console.log("click Time : " + new Date);
			
			var form = $("#fileForm")[0];
			var formData = new FormData(form);
			$.ajax({
				type: "POST",
				enctype: 'multipart/form-data',
				url: "/upload.do",
				data: formData,
				processData: false,
				contentType: false,
				cache: false,
				xhr: function(){
					var xhr = $.ajaxSettings.xhr();
					xhr.upload.onprogress = function(e){
						var per = e.loaded * 100 / e.total;
						progressBar(per);
					};
					return xhr;
				},
				success: function (data) {
					console.log("SUCCESS : ", data);
				},
				error: function (e) {
					console.log("ERROR : ", e);
				}
			});
		});
	});
	
	function progressBar(per){
		if(per > 55){
			$(".progressPer").css("color", "#000");
		}
		per = per.toFixed(1);
		$(".progressPer").text(per+" %");
		$(".progressNow").css("width", "calc(" + per + "% - 20px)");
	}
</script>
</html>

btn이라는 버튼을 클릭하면 file에 존재하는 데이터를 넘기고 xhr메소드에 정의된 onprogress 메소드에 의해 결과 값을 노출 하는 예제입니다.

 

 

결과

극단적으로 퍼센트를 잘 보기위해 3천개의 텍스트파일을 업로드하는 테스트를 진행해봤습니다.

 

좀 더 자세한 xhr에 대해서는 아래 URL을 참조바랍니다.

 

developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest/upload

 

XMLHttpRequest.upload

XMLHttpRequest upload 프로퍼티는 업로드 진행 상황을 모니터링 할 수 있는 XMLHttpRequestUpload 객체를 반환합니다.

developer.mozilla.org

 

반응형
반응형

jQuery-ui를 사용하여 드래그 이벤트와 리사이즈 이벤트를 추가 할 수 있는데, 직사각형의 영역을 서로 침범할 경우 기존 위치로 원위치 시키는 방법을 알아보겠습니다.

 

겹침 처리 방법

1. 일반 2차원 배열에 0으로 채워넣고, 도형이 있는 위치는 1로 채웁니다.

도형이 존재하는 x,y에 넓이 높이 만큼 영역을 1로 채웁니다.

 

2. 도형 위치마다 1로 더하기때문에 겹치는 영역이 생기면 아래처럼 2가 존재하게 됩니다.

겹치는 영역은 2가 된다.

 

3. 각 도형마다의 위치와 넓이, 높이를 기억하고 있다가 겹치면 원위치 시킨다.

 

 

실적용 소스

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        #box {
            width: 500px;
            height: 500px;
            border: 1px solid black;
            background: #eee;
        }

        #box .rect {
            position: absolute;
            width: 50px;
            height: 50px;
            border: 1px solid black;
        }
    </style>
</head>

<body>
    <div id="box">
        <div class="rect" idx=0></div>
        <div class="rect" idx=1></div>
    </div>
    <script src="./draggable_rect.js"></script>
</body>

</html>

 

draggable_rect.js

var rectArr = [];
var canvasArr = [];

$(function () {
    //초기 세팅
    for (i = 0; i < $(".rect").length; i++) {
        var rect = $($(".rect")[i])
        var idx = rect.attr("idx");
        var x = rect.offset().left;
        var y = rect.offset().top;

        var left = rect.css("left");
        var top = rect.css("top");
        var w = rect.width();
        var h = rect.height();
        rectArr[idx] = { x: x, y: y, left: left, top: top, w: w, h: h };
    }



    var width = $("#box").width();
    var height = $("#box").height();
    for (i = 0; i < height; i++) {
        canvasArr[i] = new Array(width);
    }

    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            canvasArr[i][j] = 0;
        }
    }
});

$(".rect").draggable({
    containment: "parent",
    start: function (event, ui) {

    },
    stop: function (event, ui) {
        var idx = $(this).attr("idx");
        var left = $(this).css("left");
        var top = $(this).css("top");
        var x = $(this).offset().left;
        var y = $(this).offset().top;
        var w = $(this).width();
        var h = $(this).height();
        var thisObj = { x: x, y: y, w: w, h: h, idx: idx };
        if (overLapChecker(".rect", thisObj)) {
            //통과
            rectArr[idx] = { x: x, y: y, left: left, top: top, w: w, h: h };
        } else {
            //겹침 - 초기화
            var obj = rectArr[idx];
            $(".rect[idx=" + idx + "]").css("top", obj.top);
            $(".rect[idx=" + idx + "]").css("left", obj.left);
        }
    }
}).resizable({
    containment: "parent",
    start: function (event, ui) {

    },
    stop: function (event, ui) {
        var idx = $(this).attr("idx");
        var left = $(this).css("left");
        var top = $(this).css("top");
        var x = $(this).offset().left;
        var y = $(this).offset().top;
        var w = $(this).width();
        var h = $(this).height();
        var thisObj = { x: x, y: y, w: w, h: h, idx: idx };
        if (overLapChecker(".rect", thisObj)) {
            //통과
            rectArr[idx] = { x: x, y: y, left: left, top: top, w: w, h: h };
        } else {
            //겹침 - 초기화
            var obj = rectArr[idx];
            $(".rect[idx=" + idx + "]").css("top", obj.top);
            $(".rect[idx=" + idx + "]").css("left", obj.left);
            $(".rect[idx=" + idx + "]").css("width", obj.w);
            $(".rect[idx=" + idx + "]").css("height", obj.h);
        }
    }
})



function overLapChecker(className, thisObj) {
    var len = $(className).length;
    if (len > 0) {
        var thisMapArr = JSON.parse(JSON.stringify(canvasArr)); //빈 배열을 복사한다.
        var x = thisObj.x;
        var y = thisObj.y;
        var w = thisObj.w;
        var h = thisObj.h;
        for (i = y; i < y + h; i++) {
            for (j = x; j < x + w; j++) {
                thisMapArr[i][j] = thisMapArr[i][j] + 1;
            }
        }
        for (z = 0; z < len; z++) {
            var idx = $($(className)[z]).attr("idx");
            if (idx == thisObj.idx) {
                continue;
            } else {
                var checkerArr = JSON.parse(JSON.stringify(thisMapArr));
                var x2 = $(".rect[idx=" + idx + "]").offset().left;
                var y2 = $(".rect[idx=" + idx + "]").offset().top;
                var w2 = $(".rect[idx=" + idx + "]").width();
                var h2 = $(".rect[idx=" + idx + "]").height();

                for (i = y2; i < y2 + h2; i++) {
                    for (j = x2; j < x2 + w2; j++) {
                        checkerArr[i][j] = checkerArr[i][j] + 1;
                        if (checkerArr[i][j] > 1) {
                            return false;
                        }
                    }
                }
            }
        }

    }
    return true;
}

드래그, 리사이즈 이벤트 처리를 하고 각 도형의 위치를 특정 배열에 담아둡니다.

 

드래그 또는 리사이즈 이벤트가 멈추면 멈추는 동시에 위치를 체크합니다. 겹치는 동선이 존재하여 배열에(2)가 처리되면 원위치 시킵니다.

 

적용 모습

겹침이 방지되었다!

반응형
반응형

 

css를 활용하여 div를 동그라미로 만들었고 jQuery-ui의 Draggable 이벤트를 추가하였습니다.

 

기본적으로 position을 활용하기 때문에 서로 두개의 도형을 위 이미지형태로 처리하면 겹치게 되는데, 두 개 이상의 원형이 있을경우 겹치지 않도록 처리해보겠습니다.

 

소스를 보기전에 간단하게 겹침처리 방지에 사용한 방식을 설명하겠습니다.

위 그림의 공식을 사용하였습니다.

각 도형의 좌측, 상단의 좌표값을 알때 중간점을 구할수 있고, 중간점과 중간점의 거리를 구해서

그 거리값이 반지름 + 반지름한 값보다 작다면 겹쳤다고 판단하여 원래 위치로 돌리는 소스입니다.

 

 

드래그이벤트 원형 겹침 방지

See the Pen BaLQdbG by myhappyman (@myhappyman) on CodePen.

반응형
반응형

클릭 이벤트를 처리하고자 할때, jQuery를 통해 보다 쉽게 이벤트를 정의할 수 있습니다.

on(), click(), bind(), onclick()등 여러가지 방법이 있는데, 제가 주로 사용하는 on()click()의 차이에 대해 알아보겠습니다.

 

 

click()

단순하게 정적페이지에 로드된 요소에 클릭이벤트를 처리하고자 할때 click()메소드를 자주 사용합니다. 해당 클릭이벤트는 동적처리가 불가능합니다.

 

다음 예제를 확인해보겠습니다.

 

See the Pen jQuery click by myhappyman (@myhappyman) on CodePen.

 

 

 

name속성이 save인 button요소를 클릭하면 click()이벤트 처리로 body태그에 click!!!을 찍어냅니다.

 

 

on()

이번엔 on() 메소드입니다.

on() 메소드는 주체가 되는 부모속성의 이벤트를 물려받아서 지정 선택자에게 이벤트를 연결할 수 있습니다.

물론 잘 못사용하면 click()이벤트처럼 정적으로 사용이 되므로 부모속성을 이용하여 처리한다는 이부분을 참고하셔야 합니다.

바로 예제를 확인해보겠습니다.

 

See the Pen jQuery on Click by myhappyman (@myhappyman) on CodePen.

 

 

 

ready안에 동작을 간단하게 설명해자면 HTML 내 클릭한 대상이 name값으로 add를 가지는 버튼 태그이면 body태그에 "+버튼"을 생성하는 예제입니다.

적용한 on()메소드의 파라미터를 확인해보겠습니다.

1. 첫번째 파라미터에는 행위(click, change, keypress 등)를 지정합니다. 이번 예제에서는 클릭을 처리하고 싶으므로 "click"으로 지정합니다.

 

2. 두번째 파라미터에는 지정자를 선택할 수 있습니다. name의 속성이 add인 버튼에 이벤트를 지정하고 싶으므로

"button[name='add']"으로 처리했습니다.


3. 세번째 파라미터는 구현부입니다. 콜백 메소드로 지정한 행위가 일어나면 콜백메소드에 정의한 내용이 동작합니다. body태그에 name속성이 add인 버튼을 생성하도록 append처리하였습니다.

 

동적으로 생성된 버튼도 동일한 동작을 한다.

 

 

동적으로 이벤트가 전부 할당되어 정상 동작하는 것을 볼 수 있습니다.

 

 

 

동적 이벤트 처리시 잘못된 방법

그럼 동적으로 처리하고자 할 때 잘못된 표현방법은 무엇일까요?

$("button[name='add']").on("click", function () {
    $("body").append("<button name='add'>+</button>");
});

부모요소가 name값이 add인 버튼에 바로 클릭이벤트를 처리하였습니다.

 

결과는 아래와 같습니다.

추가로 생성된 버튼은 동작하지 않는다.

이번엔 동일하게 on()메소드를 활용하였지만 동적으로 생성된 버튼은 동작하지 않습니다.

 

당연하게도 문서가 첫 로드되면서 이벤트는 현재 로드된 요소 중 name값이 add인 첫번째 버튼에만 클릭이벤트가 처리되고 이후에 동적으로 생성된 데이터는 연결되지 않았기 때문입니다.

 

이 부분을 유의해서 처리하시면 언제든지 동적으로 클릭이벤트뿐만 아니라 키이벤트 마우스이벤트등을 처리 할 수 있습니다.

반응형
  1. psy 2021.11.18 16:07

    와 진짜 사랑합니다. 백엔드 교육 받고 있었는데 프로젝트 진행 중에 프엔쪽 지식이 부족해서 뭐가 문제인지 한참 몰랐는데 이거 덕분에 해결했습니다.

    • Favicon of https://myhappyman.tistory.com Park.S.W 2021.11.18 16:40 신고

      제 글이 도움이되어서 다행입니다!!😁 방문해주셔서 감사합니다~

  2. null_1 2022.04.01 15:54

    정확히 원하던 정보입니다... 계속 해매고 있었는데 너무 감사합니다.

  3. Favicon of http://fishcoding.tistory.com fishcoding 2022.05.02 14:11

    좋은글 감사합니다 퍼가도 될까요?

    • Favicon of https://myhappyman.tistory.com Park.S.W 2022.05.02 14:27 신고

      네~ 출처만 남겨주시면 감사하겠습니다 ^^

    • Favicon of https://fishcoding.tistory.com jeongyj 2022.05.02 15:34 신고

      네 출처 남기고 업로드 했습니다
      Park.S.W님 좋은하루 되세요~^^

    • Favicon of https://myhappyman.tistory.com Park.S.W 2022.05.02 17:11 신고

      네! jeongyj 님도 좋은하루 보내세요😁

  4. ㄳㄳㄳ 2022.06.17 23:36

    ㄳㄳㄳ