티스토리 뷰
반응형
그리기, 채우기, 전체 삭제, 다운로드 기능이 있는 그림판.
HTML - BODY
<body class="flex-column">
<canvas id="canvas"></canvas>
<div class="controls flex-column">
<div class="controls_range">
<input type="range" id="range" min="0.1" max="5.0" value="2.5" step="0.1" />
</div>
<div class="controls_btns">
<button id="mode_btn">Draw Mode</button>
<button id="clear_btn">Clear</button>
<button id="save_btn">Save</button>
</div>
<div class="controls_colors" id="colors">
<div class="controls_color" style="background-color: rgb(44, 44, 44)"></div>
<div class="controls_color" style="background-color: rgb(255, 255, 255)"></div>
<div class="controls_color" style="background-color: rgb(255, 59, 48)"></div>
<div class="controls_color" style="background-color: rgb(255, 149, 0)"></div>
<div class="controls_color" style="background-color: rgb(255, 204, 0)"></div>
<div class="controls_color" style="background-color: rgb(76, 217, 99)"></div>
<div class="controls_color" style="background-color: rgb(90, 200, 250)"></div>
<div class="controls_color" style="background-color: rgb(5, 121, 255)"></div>
<div class="controls_color" style="background-color: rgb(88, 86, 214)"></div>
</div>
</div>
</body>
Javascript
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const colors = document.getElementsByClassName("controls_color");
const range = document.getElementById("range");
const mode = document.getElementById("mode_btn");
const save = document.getElementById("save_btn");
const clear = document.getElementById("clear_btn");
const INIT_FILL_COLOR = "rgb(255, 255, 255)";
const INIT_STROCKE_COLOR = "rgb(44, 44, 44)";
canvas.width = 500;
canvas.height = 500;
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.lineWidth = 2.5;
changeColor(INIT_STROCKE_COLOR);
let painting = false;
let filling = false;
function stopPainting() {
painting = false;
ctx.closePath();
}
function startPainting() {
if (!filling) {
painting = true;
ctx.beginPath();
ctx.moveTo(x, y);
}
}
function onMouseMove(event) {
const x = event.offsetX;
const y = event.offsetY;
if (painting) {
ctx.lineTo(x, y);
ctx.stroke();
}
}
function handleColorClick(event) {
changeColor(event.target.style.backgroundColor);
}
function changeColor(color) {
ctx.strokeStyle = color;
ctx.fillStyle = color;
Array.from(colors).forEach((e) => {
if (e.classList.contains("active") && e.style.backgroundColor !== color) {
e.classList.remove("active");
} else if (e.style.backgroundColor === color && !e.classList.contains("active")) {
e.classList.add("active");
}
});
}
function handleRangeChange(event) {
ctx.lineWidth = event.target.value;
}
function handleModeClick() {
filling = !filling;
if (filling) {
mode.innerText = "Fill Mode";
} else {
mode.innerText = "Draw Mode";
}
}
function handleCanvasClick() {
if (filling) ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function handleSaveClick() {
const image = canvas.toDataURL();
const link = document.createElement("a");
link.href = image;
link.download = "Paint";
link.click();
}
function handleClearClick() {
ctx.fillStyle = INIT_FILL_COLOR;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = ctx.strokeStyle;
}
canvas.addEventListener("mousemove", onMouseMove);
canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", stopPainting);
canvas.addEventListener("mouseleave", stopPainting);
canvas.addEventListener("click", handleCanvasClick);
Array.from(colors).forEach((e) => {
e.addEventListener("click", handleColorClick);
});
range.addEventListener("input", handleRangeChange);
mode.addEventListener("click", handleModeClick);
save.addEventListener("click", handleSaveClick);
clear.addEventListener("click", handleClearClick);
CSS
@import "reset.css";
body {
background-color: #e5e7e9;
padding: 50px 0px;
}
.flex-column {
display: flex;
flex-direction: column;
align-items: center;
}
#canvas {
width: 500px;
height: 500px;
background-color: white;
border-radius: 15px;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
}
.controls {
margin-top: 80px;
}
.controls_btns,
.controls_range {
margin-bottom: 30px;
}
.controls_btns button {
all: unset;
cursor: pointer;
background-color: white;
padding: 5px 0px;
width: 100px;
text-align: center;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
border: 2px solid rgba(0, 0, 0, 0.2);
color: rgba(0, 0, 0, 0.8);
text-transform: uppercase;
font-weight: 800;
font-size: 12px;
}
.controls_btns button:active {
transform: scale(0.97);
}
.controls_colors {
display: flex;
}
.controls_colors .controls_color {
width: 50px;
height: 50px;
border-radius: 25px;
cursor: pointer;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
margin: 1px;
}
.controls_colors .controls_color.active {
box-shadow: 0 7px 11px rgb(224, 10, 231), 0 4px 7px rgb(42, 168, 90);
}
반응형
'note..' 카테고리의 다른 글
expo 시작하기 (0) | 2022.03.21 |
---|---|
심심해서 찾아본 Wordle의 정답 알아내기.. (0) | 2022.03.20 |
신림역 쪽 괜찮은 스터디카페 (0) | 2022.03.12 |
[HTML + Javascript] Wordle 만들어보기 (0) | 2022.03.11 |
비밀번호 암호화 (0) | 2022.02.08 |
댓글