주요 API
API | 설명 |
Drag and Drop | HTML 요소 혹은 파일을 끌어서(드래그) 다른 HTML 요소에 놓을 때(드롭할 때) 데이터를 전달하는 기능을 제공 |
Blob | 이진 데이터를 다루는 기능을 제공 |
File | 프로그램 여러 개를 멀티스레드로 병렬 처리하는 기능을 제공 |
Web Workers | 대용량이며 저장 기간에 제한이 없는 데이터를 로컬에 저장하는 기능을 제공 |
Indexed Database | 로컬에 키값 타입의 관계형 데이터 베이스 기능을 제공 |
WebSockets | 서버와의 양방향 통신 기능을 제공 |
Geolocation | GPS 등의 위치 정보를 다루는 기능을 제공 |
Canvas | 2차원 3차원 그래픽스 기능을 제공 |
드래그 앤 드롭 API
*HTML 요소나 로컬 파일을 마우스로 끌어서 옮길 수 있으며 다른 요소에 드롭할 수 있음
*이때 드래그한 요소 또는 파일의 데이터는 드롭 타킷 요소에 전달
*HTML 요소를 드래그 할 수 있게 만들기
-<div draggable="true"> 드래그 할 수 있습니다. </div>
-이 속성을 지정하지 않거나 auto로 지정하면 해당 HTML요소의 기본값을 사용
-href 속성을 지정한 a 요소와 src 속성을 지정한 img 요소는 기본적으로 드래그 할 수 있도록 만들어져 있음
드래그 앤 드롭 이벤트
API | 설명 |
dragstart | 드래그를 시작할 때 발생 |
drag | 드래그를 하는 동안 발생 |
dragend | 드래그가 끝났을 때 발생 |
dragenter | 마우스 포인터가 드롭 요소의 경계선 안쪽으로 들어갈 때 발생 |
dragover | 마우스 포인터가 드롭 요소의 경계선 안쪽에 있을 때 발생 |
dragleave | 마우스 포인터가 드롭 요소의 경계선 바깥으로 나왔을 때 발생 |
drop | 요소에 드롭할 때 발생 |
*모든 드래그 앤 드롭 이벤트는 dataTransfer 프로퍼티를 가짐
*dataTransfer 프로퍼티 값은 Datatransfer 객체이며, 이 객체로 드래그 타깃 요소가 드롭 타깃 요소에 데이터를 전달할 수 있음
*DataTransfer 객체의 프로퍼티와 메소드
프로퍼티 이름/ 메소드 이름 |
설명 |
type | setData 메소드로 설정한 데이터 타입 목록 |
files | 드래그한 파일 객체 목록 |
effectAllowed | 드래그 타깃 요소가 허용하는 작업의 유형("none", "copy", "copyLink", "copyMove" 등) |
dropEffect | 드롭 타깃 요소에 표시하는 효과("none", "copy", "move", "link") |
setData(format, data) | 드래그 타깃 요소의 데이터 타입을 특정 데이터 타입으로 설정 |
데이터 전달하기(드래그 타깃 요소에서 드롭 타깃 요소에 데이터 전달)
*드래그 타깃 요소의 dragstart 이벤트 처리기 안에서 dataTransfer 프로퍼티의 setData메소드에 데이터 타입을 지정한 데이터를 추가
e.dataTransfer.setData("text/plain", value);
*드롭 타깃 요소의 dragover 이벤트 처리기 안에서 브라우저의 기본 동작을 취소
드래그 타깃 요소가 드롭 타깃 요소 위에 올라가면 브라우저의 기본 동작인 drop 이벤트가 취소되기 때문.
e.preventDefault();
*드롭 타깃 요소의 drop 이벤트 처리기 안에서 dataTransfer 프로퍼티의 getData 메소드를 사용해서 데이터를 지정한 데이터 타입으로 가져옴
*var value = e.dataTransfer.getData("text/plain");
데이터는 데이터 타입(format)별로 하나만 전달할 수 있음
*setData 메소드로 같은 데이터 타입의 데이터를 두번 설정하면 이전에 설정한 데이터를 덮어씀
드래그 앤 드롭 예제
<드롭하는 영역을 사용자에게 알림>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title> 드롭 하는 영역을 사용자에게 알리기 </title>
<script>
window.onload = function() {
var dragbox = document.getElementById("dragbox"); //드래그박스 가져오기
var dropbox = document.getElementById("dropbox"); //드롭박스 가져오기
dropbox.addEventListener("dragenter", function(e) {
e.target.style.borderColor = "red";
}, false);
dropbox.addEventListener("dragleave", function(e) {
e.target.style.borderColor = "gray";
}, false);
dropbox.addEventListener("drop", function(e) {
}, false);
};
</script>
<style>
#dragbox {width: 150px; border: 10px solid blue; }
#dropbox {width: 150px; padding: 50px; border: 10px solid blue;}
</style>
<body>
<div id="dragbox" draggable="true">이것을 드래그하세요</div>
<div id="dropbox">이곳에 드롭하세요</div>
</body>
</head>
<드래그 앤 드롭으로 배경색 설정하기>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>드래그 앤 드롭 예제</title>
<script>
window.onload = function() {
var color = document.getElementById("color");
var dropbox = document.getElementById("dropbox");
//드래그를 시작할 때, 색상의 값을 dataTransfer 객체의 데이터로 설정한다
color.ondragstart = function(e) {
e.dataTransfer.setData("text/plain", e.target.value);
};
//드래그 타깃 요소 위에 마우스 포인터가 올라가면, 브라우저의 기본 동작을 취소한다(필수)
dropbox.ondragover = function(e) {
e.preventDefault();
};
//요소를 드롭하면, dataTransfer의 데이터로 보더 박스의 배경색을 설정한다
dropbox.ondrop = function(e){
e.preventDefault(); //브라우저의 기본 동작을 취소한다(선택사항)
e.target.style.backgroundColor = e.dataTransfer.getData("text/plain");
};
};
</script>
<style>
#color {margin-bottom: 10px; }
#dropbox {width: 150px; padding: 50px; border: 1px solid gray; }
</style>
</head>
<body>
<input type="color" id="color" draggable="true">
<div id="dropbox">이곳에 드롭하세요</div>
</body>
</html>
[그림판 프로젝트]
painter.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Simple Painter</title>
<script src="../js/elt.js"></script>
<script src="../js/painter.js"></script>
<script>
window.onload=function(){
createPainter(document.body, 800, 600);
};
</script>
</head>
<body>
</body>
</html>
elt.js
function elt(name, attributes){
var node = document.createElement(name);
if(attributes){
for(var attr in attributes){
if(attributes.hasOwnProperty(attr)){
node.setAttribute(attr, attributes[attr]);
}
}
}
for(var i=2;i<arguments.length; i++){
var child = arguments[i];
if(typeof child =='string'){
child = document.createTextNode(child);
}
node.appendChild(child);
}
return node;
}
painter.js
/*--------------------------------------------------------------------------------*
* 화면을 구성하는 요소를 생성하고, 요소에 이벤트 처리기 등록하기
*--------------------------------------------------------------------------------*/
function createPainter(parent, width, height) {
// 타이틀
var title = elt("h2", null, "Simple Painter");
// canvas요소와 랜더링 컨텍스트 가져오기
var [canvas,ctx] = createCanvas(width, height);
// 도구 막대 : controls 객체의 프로퍼티를 순회하면서 등록한다
var toolbar = elt("div", null);
for(var name in controls) {
toolbar.appendChild(controls[name](ctx));
}
toolbar.style.fontSize = "small";
toolbar.style.marginBottom = "3px";
// toolbar 요소와 canvas 요소를, 지정한 요소(parent)의 자식 요소로 삽입한다
parent.appendChild(elt("div", null, title, toolbar, canvas));
}
function createCanvas(canvasWidth,canvasHeight) {
var canvas = elt("canvas", { width: canvasWidth, height: canvasHeight });
var ctx = canvas.getContext("2d");
canvas.style.border = "1px solid gray";
canvas.style.cursor = "pointer";
// 그리기 도구를 mousedown 이벤트 처리기로 등록한다
canvas.addEventListener("mousedown", function(e) {
// Firefox 대책 : 색상 선택시, change 이벤트를 강제로 발생시킨다
var event = document.createEvent("HTMLEvents");
event.initEvent("change", false, true);
colorInput.dispatchEvent(event);
// 선택한 그리기 도구를 초기화
paintTools[paintTool](e,ctx);
}, false);
canvas.addEventListener("dragover", function(e) {
e.preventDefault();
}, false);
canvas.addEventListener("drop", function(e) {
var files = e.dataTransfer.files;
if( files[0].type.substring(0,6) !== "image/" ) return;
loadImageURL(ctx, URL.createObjectURL(files[0]));
e.preventDefault();
}, false);
return [canvas,ctx];
}
/*--------------------------------------------------------------------------------*
* 유틸리티
*--------------------------------------------------------------------------------*/
// * element의 왼쪽 위 모서리에서 마우스의 상대적 위치를 가져온다
function relativePosition(event, element) {
var rect = element.getBoundingClientRect();
return { x: Math.floor(event.clientX - rect.left),
y: Math.floor(event.clientY - rect.top ) };
}
/*--------------------------------------------------------------------------------*
* 그리기 도구
* paintTools 메서드는 그리기에 사용하는 도구입니다.
* 그리기 도구는 그리기를 위한 각종 설정과 이벤트 처리기 등록을 담당합니다.
* 각 메서드는 controls.painter를 통해 자동으로 도구 선택 메뉴에 추가됩니다.
* 메뉴에서 선택한 도구는, 변수 paintTool에 저장되어 그림을 그릴 때 사용됩니다.
* 그리기 도구를 추가하려면, paintTools 메서드에 새로운 그리기 도구를 추가하십시오.
*--------------------------------------------------------------------------------*/
var paintTool; // 선택된 그리기 도구 (controls.painter로 선택)
var paintTools = Object.create(null); // 그리기 도구 객체
// * brush : 브러시 도구
paintTools.brush = function(e, ctx) {
ctx.lineCap = "round";
ctx.lineJoin = "round";
// Canvas 화면을 img에 저장한다
var img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
// canvas 요소에 대한, 마우스 포인터의 상대 위치를 구한다
var p = relativePosition(e, ctx.canvas);
// 경로를 정의한다
ctx.beginPath();
ctx.moveTo(p.x,p.y);
// 드래그 이벤트 처리기를 등록한다
setDragListeners(ctx, img, function(q) {
ctx.lineTo(q.x,q.y); // 경로를 추가한다
ctx.stroke (); // 경로를 그린다
});
};
// * line : 선 그리기 도구
paintTools.line = function(e, ctx) {
ctx.lineCap = "round";
var img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
var p = relativePosition(e, ctx.canvas);
setDragListeners(ctx, img, function(q) {
ctx.beginPath();
ctx.moveTo(p.x,p.y); ctx.lineTo(q.x,q.y);
ctx.stroke();
});
};
// * circle : 동그라미 그리기 도구
paintTools.circle = function(e, ctx) {
var img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
var p = relativePosition(e,ctx.canvas);
setDragListeners(ctx, img, function(q) {
var dx = q.x - p.x;
var dy = q.y - p.y;
var r = Math.sqrt(dx*dx+dy*dy);
ctx.beginPath();
ctx.arc(p.x, p.y, r, 0, 2*Math.PI, false);
ctx.stroke();
});
};
// * circleFill : 채워진 동그라미 그리기 도구
paintTools.circleFill = function(e, ctx) {
var img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
var p = relativePosition(e,ctx.canvas);
setDragListeners(ctx, img, function(q) {
var dx = q.x - p.x;
var dy = q.y - p.y;
var r = Math.sqrt(dx*dx+dy*dy);
ctx.beginPath();
ctx.arc(p.x, p.y, r, 0, 2*Math.PI,false);
ctx.fill();
});
};
/*--------------------------------------------------------------------------------*
* 그리기 도구의 유틸리티
*--------------------------------------------------------------------------------*/
// * 마우스를 드래그할 때의 이벤트 리스너를 등록한다
function setDragListeners(ctx,img,draw) {
// mousemove 이벤트 리스너를 등록한다
var mousemoveEventListener = function(e) {
// 저장한 이미지를 읽어들인다
ctx.putImageData(img, 0, 0);
// 지정한 그리기 함수 draw로 마우스 위치까지 그린다
draw(relativePosition(e, ctx.canvas));
};
document.addEventListener("mousemove", mousemoveEventListener, false);
// mouseup 이벤트 처리기를 등록한다
document.addEventListener("mouseup", function(e) {
// 저장한 이미지를 읽어들인다
ctx.putImageData(img, 0, 0);
// 지정한 그리기 함수 draw로 마우스 위치까지 그린다
draw(relativePosition(e, ctx.canvas));
// mousemove, mouseup 이벤트 리스너를 제거한다
document.removeEventListener("mousemove", mousemoveEventListener, false);
document.removeEventListener("mouseup", arguments.callee, false);
},false);
}
/*--------------------------------------------------------------------------------*
* 컨트롤러
* 각종 설정을 변경하는 제어판을 정의합니다.
* 각 컨트롤러는 controls 객체의 메서드로 등록되어 있습니다.
* 각 메서드는 필요한 HTML 요소를 생성해서 반환하며, 이벤트 리스너를 등록합니다.
* 각 메서드는, createPainter를 통해 자동으로 도구 막대에 추가됩니다.
* 새로운 컨트롤을 추가하려면, controls 객체에 새로운 메서드를 추가하십시오.
*--------------------------------------------------------------------------------*/
var controls = Object.create(null); // 컨트롤러 객체
var colorInput; // Firefox의 change 이벤트 대책. input[type="color"] 객체를 저장한다
// * 그리기 도구 선택
controls.painter = function(ctx) {
var DEFAULT_TOOL = 0;
var select = elt("select", null);
var label = elt("label", null, "그리기 도구 : ", select);
for(var name in paintTools) {
select.appendChild(elt("option", {value: name}, name));
}
select.selectedIndex = DEFAULT_TOOL;
paintTool = select.children[DEFAULT_TOOL].value;
select.addEventListener("change", function(e) {
paintTool = this.children[this.selectedIndex].value;
},false);
return label;
};
// * 색상 선택 (선과 채우기를 모두 설정함 → 필요하면 별도의 컨트롤로 만드세요)
controls.color = function(ctx) {
var input = colorInput = elt("input", {type: "color"});
var label = elt("label", null, " 색:", input);
input.addEventListener("change", function (e) {// 참고 : Firefox에서는 change 이벤트가 발생하지 않습니다.
ctx.strokeStyle = this.value;
ctx.fillStyle = this.value;
},false);
return label;
};
// * 선의 너비 선택
controls.brushsize = function(ctx) {
var size = [1,2,3,4,5,6,8,10,12,14,16,20,24,28];
var select = elt("select", null);
for(var i=0; i<size.length; i++) {
select.appendChild(elt("option",{value:size[i].toString()},size[i].toString()));
}
select.selectedIndex = 2;
ctx.lineWidth = size[select.selectedIndex];
var label = elt("label",null," 선의 너비:",select);
select.addEventListener("change", function(e) {
ctx.lineWidth = this.value;
},false);
return label;
};
// * 투명도 선택
controls.alpha = function(ctx) {
var input = elt("input", {type:"number",min:"0", max:"1",step:"0.05",value:"1"});
var label = elt("label", null, " 투명도:", input);
input.addEventListener("change", function(e) {
ctx.globalAlpha = this.value;
},false);
return label;
};
controls.save = function(ctx) {
var input = elt("input", {type: "button", value:"저장"});
var label = elt("label", null, " ", input);
input.addEventListener("click", function(e) {
var dataURL = ctx.canvas.toDataURL();
open(dataURL, "save");
}, false);
return label;
};
var filterTools = Object.create(null);
controls.filter = function(ctx) {
var DEFAULT_FILTER = 0;
var select = elt("select",null);
var label = elt("label",null, " ",select);
select.appendChild(elt("option",{value: "filter"},"필터"));
for(var name in filterTools) {
select.appendChild(elt("option",{value: name},name));
}
select.selectedIndex = DEFAULT_FILTER;
select.addEventListener("change", function(e) {
var filterTool = this.children[this.selectedIndex].value;
var inputImage = ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height);
var outputImage = filterTools[filterTool](inputImage);
ctx.putImageData(outputImage,0,0);
select.selectedIndex = DEFAULT_FILTER;
}, false);
return label;
};
function weightedAverageFilter(image, n, Weight, keepBrightness, offset) {
var width = image.width, height = image.height;
var outputImage = new ImageData(width, height);
for(var x=0; x<width; x++) {
for(var y=0; y<height; y++) {
var iR = 4*(width*y+x);
for(var i=0; i<3; i++) {
var average = 0, weightSum = 0;
for(ix=-n; ix<=n; ix++) {
var xp = x + ix;
if(xp<0 || xp>=width) continue;
for(iy=-n; iy<=n; iy++) {
var yp = y + iy;
if(yp<0 || yp>=height) continue;
var w = Weight[iy+n][ix+n];
weightSum += w;
average += w*image.data[4*(width*yp+xp)+i];
}
}
if(keepBrightness) {
average /= weightSum;
}
outputImage.data[iR+i] = average + offset;
}
outputImage.data[iR+3] = image.data[iR+3];
}
}
return outputImage;
}
// * 블러 필터
filterTools.blur = function(inputImage) {
var size = 2;
var W = [];
for(var i=0; i<=2*size; i++) {
W[i] = [];
for(var j=0; j<=2*size; j++) {
W[i][j] = 1;
}
}
return weightedAverageFilter(inputImage, size, W, true, 0);
};
// * 샤프 필터
filterTools.sharp = function(inputImage) {
var W = [[ 0,-1, 0],
[-1, 5,-1],
[ 0,-1, 0]];
return weightedAverageFilter(inputImage, 1, W, false, 0);
};
// * 엠보싱 필터
filterTools.emboss = function(inputImage) {
var W = [[-1, 0, 0],
[ 0, 0, 0],
[ 0, 0, 1]];
return weightedAverageFilter(inputImage, 1, W, false, 128);
};
// * 테두리 강조
filterTools.edgeDetection = function(inputImage) {
var W = [[-1,-1,-1],
[-1, 8,-1],
[-1,-1,-1]];
return weightedAverageFilter(inputImage, 1, W, false, 0);
};
// 파일 입력 컨트롤
controls.file = function(ctx) {
var input = elt("input", {type: "file"});
var label = elt("label", null, " ", input);
input.addEventListener("change", function(e) {
if(input.files.length == 0) return;
var reader = new FileReader();
reader.onload = function() {
loadImageURL(ctx, reader.result);
};
reader.readAsDataURL(input.files[0]);
}, false);
return label;
};
// url을 ctx에 그린다 (그림이 Canvas의 경계선에 내접하도록 한다)
function loadImageURL(ctx, url) {
var image = document.createElement("img");
image.onload = function() {
var factor = Math.min(
ctx.canvas.width/this.width, ctx.canvas.height/this.height
);
var wshift = (ctx.canvas.width - factor*this.width )/2;
var hshift = (ctx.canvas.height - factor*this.height)/2;
var savedColor = ctx.fillStyle;
ctx.fillStyle = "white";
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.drawImage(image, 0, 0,
this.width, this.height, wshift, hshift,
this.width*factor, this.height*factor
);
ctx.fillStyle = savedColor;
};
image.src = url;
}
'웹 프로그래밍 > JavaScript' 카테고리의 다른 글
[JavaScript] 자바스크립트 예외처리 및 이벤트 처리 (1) | 2024.11.26 |
---|---|
[JavaScript] 브라우저 객체 모델 (0) | 2024.11.26 |
[JavaScript] 자바스크립트 내장 객체 (1) | 2024.11.25 |
[JavaScript] 사용자 정의 자료형 활용 (2) | 2024.11.25 |
문서 객체 모델 DOM(Document Object Model) (0) | 2024.11.20 |