순수 자바스크립트로 드래그 한 영역을 이미지로 캡쳐하여 다운로드를 해 보았다.
html2canvas라이브러리를 같이 사용해야 한다.
html, script파일
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>이미지 캡쳐</title>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<div id="page">
<div class="title">순수자바스크립트 영역 캡쳐 후 저장</div>
<button type="button" class="btn" id="edit">캡쳐하기</button>
<div>
<img src="image/bunny.jpg" alt="bunny" id="image" />
</div>
<a id="target"></a>
</div>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script>
window.onload = function (){
document.getElementById("edit").addEventListener("click", function(e){
document.querySelector("body").classList.add('edit_cursor');
screenshot(e)
})
}
function screenshot(e){
let startX, startY;
let height = window.innerHeight;
let width = window.innerWidth;
//배경을 어둡게 깔아주기 위한 div 객체 생성
let screenBg = document.createElement("div");
screenBg.id = "screenshot_background";
screenBg.style.borderWidth = "0 0"+ height + "px 0";
//마우스 이동하면서 선택한 영역의 크기를 보여주기 위한 div 객체 생성
let screenShot = document.createElement("div");
screenShot.id = "screenshot";
document.querySelector("body").appendChild(screenBg)
document.querySelector("body").appendChild(screenShot)
let selectArea = false;
let body = document.querySelector('body');
//마우스 누르는 이벤트 함수
const mouseDown = function(e){
e.preventDefault();
selectArea = true;
startX = e.clientX;
startY = e.clientY;
console.log("mousedown", startX, startY)
body.removeEventListener("mousedown", mouseDown);
}
function mouseMove(e){
let x = e.clientX;
let y = e.clientY;
screenShot.style.left = x;
screenShot.style.top = y;
if(selectArea){
let top = Math.min(y, startY);
let right = width - Math.max(x, startX)
let bottom = height - Math.max(y, startY)
var left = Math.min(x, startX)
screenBg.style.borderWidth = `${top}px ${right}px ${bottom}px ${left}px`;
console.log("screenBg", screenBg.style.borderWidth)
}
}
function save(canvas){
if(navigator.msSaveBlob){
let blob = cnavas.msSaveBlob()
return navigator.msSaveBlob(blob, '파일명.jpg');
}else {
let el = document.getElementById('target');
el.href = canvas.toDataURL("image/jpeg");
el.download = "bunny.jpg";
el.click();
}
}
function mouseUp (e){
selectArea = false;
//(초기화) 마우스 떼면서 마우스 무브 이벤트 삭제
body.removeEventListener("mousemove", mouseMove);
//(초기화) 스크린샷을 위해 생성한 객체 삭제
screenShot.parentNode.removeChild(screenShot);
screenBg.parentNode.removeChild(screenBg);
let x = e.clientX;
let y = e.clientY;
let top = Math.min(y, startY)
let left = Math.min(x, startX)
let width = Math.max(x, startX) - left;
let height = Math.max(y, startY) - top;
console.log("mouseup", left,top, width, height)
html2canvas(document.body).then(
function(canvas){
let img = canvas.getContext('2d').getImageData(left, top, width, height);
console.log(img);
let c = document.createElement('canvas');
c.width = width;
c.height = height;
c.getContext('2d').putImageData(img, 0, 0);
save(c); // crop한 이미지 저장
}
)
body.removeEventListener("mouseup", mouseUp);
document.querySelector('body').classList.remove('edit_cursor');
}
body.addEventListener("mousedown", mouseDown);
body.addEventListener("mousemove", mouseMove);
body.addEventListener("mouseup", mouseUp);
}
</script>
</body>
</html>
css파일
#page{
width: 70%;
min-height: 900px;
margin: 0 auto;
}
#target {
display: none;
}
.title{
margin: 30px 0;
font-size: 24px;
font-weight: 700;
}
#image{
width: 100%;
max-width: 700px;
}
.btn{
background: darkmagenta;
border: transparent;
outline: none;
padding: 8px 24px;
color: white;
font-size: 17px;
border-radius: 4px;
margin-bottom: 15px;
}
.btn:hover{
cursor:pointer;
background: rgb(206, 10, 206);
}
/* 캡쳐 시 배경 어둡게 */
#screenshot_background {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
display:block;
opacity: 0.3;
text-align: center;
box-sizing: border-box;
z-index: 9999;
border: 1px solid black;
}
/* 캡쳐 영역만 밝게 하기 위한 요소 */
#screenshot:before, #screenshot:after {
border: none ;
content: "";
height: 100% ;
position: absolute;
width: 100%;
}
#screenshot::before{
border-right: 1px solid white;
border-bottom: 1px solid white;
left: -100%;
top: -100%;
}
#screenshot:after{
border-top: 1px solid white;
border-left: 1px solid white;
left: 0;
top:0;
}
#screenshot{
height: 100%;
position:fixed;
width: 100%;
z-index: 99999;
}
body.edit-cursor {
cursor: crosshair;
}
핵심요점
위의 코드에서는 배경을 div의 배경색이 아니라 border의 두께값을 계산하여 검은 색상을 채웠다. 배경색상을 넣으면 캡쳐된 내용물이 가려지기 때문이다.
mousedown, mousemove, mouseup 이렇게 3가지 단계에 함수를 각각 만든다.