운동하다가 허리를 심하게 다쳐서 오늘 코딩을 많이 하진 못했다. 완전히 완성하지 못해서 아쉽지만 부상은 내가 어떻게 할 수 있는 게 아니니까 어쩔 수 없지…😢
당분간은 잘 쉬면서 틈틈이 코딩하고, 허리가 많이 나아지면 열심히 코딩해야겠다. 그리고 디자인은 누워서도 할 수 있으니까 누워서 그림판 디자인하고 그대로 CSS로 적용해봐야지!
작은 프로젝트를 하나씩 만드니까 보람도 있고 재미도 있다. 이렇게 연습하다보면 나중에 내가 원하는 앱도 뚝딱 만들 수 있겠지…? 😂
ctx.lineWidth = 2;
let isPainting = false;
// 클릭 후, 사용자가 이동할 때마다 그림이 그려지도록 만들기
// ctx.moveTo(e.offsetX, e.offsetY);
function onMove(e){
if(isPainting){
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
return;
}
ctx.moveTo(e.offsetX, e.offsetY);
}
function onMoveDown(){
isPainting = true;
}
function cancelPainting(){
isPainting = false;
}
canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", onMoveDown);
canvas.addEventListener("mouseup", cancelPainting);
// click은 마우스를 눌렀다가 뗐을 때 발생
// mousedown은 마우스가 눌러진 상태
//canvas 밖으로 나갔을 때, 다시 누르지 않아도 그려지는 오류 고치기
canvas.addEventListener("mouseleave", cancelPainting);
<canvas></canvas>
<input id="line-width" type="range" min="1" max="10" value="5" />
const canvas = document.querySelector("canvas");
const lineWidth = document.getElementById("line-width");
const ctx = canvas.getContext("2d");
canvas.width = 800;
canvas.height = 800;
ctx.lineWidth = lineWidth.value; // 연결
let isPainting = false;
function cancelPainting(){
isPainting = false;
ctx.beginPath(); // 마우스를 움직일 때마다 새로운 path 생성
// 도중에 선 굵기 변경해도 이전 선에 영향을 안 주기 위함.
}
function lineWidthChange(e){
ctx.lineWidth = e.target.value; // 변화를 캐치
}
canvas.addEventListener("mouseup", cancelPainting);
// 선 굵기 조절
lineWidth.addEventListener("change", lineWidthChange)
<input id="line-width" type="range" min="1" max="10"
value="5" step="0.5" />
<!-- step: 단계 변경 `기본 : 1->2... step 0.5 : 1 -> 1.5...` -->
<input id="color" type="color" />
const color = document.getElementById("color");
function colorChange(e){
ctx.strokeStyle = e.target.value;
ctx.fillStyle = e.target.value;
}
// 선 색상 변경
color.addEventListener("change", colorChange);
<div class="color-option" style="background-color: #cd84f1;" data-color="#cd84f1"></div>
<div class="color-option" style="background-color: #ffb8b8;" data-color="#ffb8b8"></div>
<div class="color-option" style="background-color: #ff3838;" data-color="#ff3838"></div>
<div class="color-option" style="background-color: #ff9f1a;" data-color="#ff9f1a"></div>
<div class="color-option" style="background-color: #fff200;" data-color="#fff200"></div>
<div class="color-option" style="background-color: #32ff7e;" data-color="#32ff7e"></div>
<div class="color-option" style="background-color: #17c0eb;" data-color="#17c0eb"></div>
<div class="color-option" style="background-color: #7158e2;" data-color="#7158e2"></div>
<div class="color-option" style="background-color: #3d3d3d;" data-color="#3d3d3d"></div>
<div class="color-option" style="background-color: #67e6dc;" data-color="#67e6dc"></div>
<!-- 속성 data-"": ""안에 원하는 값(string) 넣을 수 있다. -->
<!-- 값은 dateset에 나와있다. -->
/* 팔레트 */
.color-option {
width: 50px;
height: 50px;
cursor: pointer;
}
const color = document.getElementById("color");
const colorOptions = Array.from(
document.querySelectorAll(".color-option")
// = const colorOptions = document.getElementsByClassName(".color-option");
);
function colorChange(e){
ctx.strokeStyle = ctx.fillStyle = e.target.value;
}
function colorClick(e){
const colorValue = e.target.dataset.color; // dataset에 접근해서 미리 설정한 color 추출
ctx.strokeStyle = ctx.fillStyle = color.value = colorValue;
// 클릭한 컬러 color에 동기화
}
// 색상 변경
color.addEventListener("change", colorChange);
colorOptions.forEach((color) => color.addEventListener("click", colorClick));
// 클릭될 때마다 함수 실행
// 함수가 아니라는 오류
// why? colorOptions은 배열이 아니라 HTMLcollection이기 때문에 가져올 수 없어서
// => 배열로 만들어줘야 한다. Array.from();
<button id="mode-btn">Fill</button>
<button id="reset">Reset</button>
<button id="eraser">Eraser</button>
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const modeBtn = document.getElementById("mode-btn");
const reset = document.getElementById("reset");
const eraser = document.getElementById("eraser");
canvas.width = 800;
canvas.height = 800;
const CANVAS_WIDTH = ctx.canvas.width;
const CANVAS_HEIGHT = ctx.canvas.height;
let isFilling = false;
// 채우기 모드(배경색 바꾸기), 그리기 모드
function onMode(){
if(isFilling){
isFilling = false;
modeBtn.innerText = "Fill";
}else{
isFilling = true;
modeBtn.innerText = "Draw";
}
}
function canvasClick() {
if(isFilling){
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
}
// 리셋
function onReset(){
// ctx.fillStyle = "white";
// ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
// 지우개
function onEraser(){
ctx.strokeStyle = "white";
isFilling = false;
modeBtn.innerText = "Fill";
}
modeBtn.addEventListener("click", onMode);
reset.addEventListener("click", onReset);
eraser.addEventListener("click", onEraser);
let filledColor = "white";
function canvasClick() {
if(isFilling){
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
filledColor = ctx.fillStyle;
}
}
function onEraser(){
ctx.strokeStyle = filledColor; // 지우개 색상 배경색으로 바꾸기
isFilling = false;
modeBtn.innerText = "Fill";
}
<input type="file" accept="image/*" id="file" />
<!-- accept image 안 하면 비디오도 선택할 수 있음 -->
const file = document.getElementById("file");
function fileChange(e){
const file = e.target.files[0];
const url = URL.createObjectURL(file); // 브라우저는 url로 파일을 불러온다. // 다른 브라우저에서는 사용 불가능한 url
const img = new Image();
img.src = url;
img.onload = function(){
ctx.drawImage(img, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
fileInput.value = null;
// 사용자가 다른 사진도 선택할 수 있게 사진 업로드하면 선택된 파일 없음이 뜨게 한다.
}
}
file.addEventListener("change", fileChange);
<input type="text" placeholder="Write and then double click" id="text" />
const txtInput = document.getElementById("text");
ctx.lineCap = "round"; // 브러쉬 모양 둥글게
function dbClick(e){
const txt = txtInput.value;
if (txt !== ""){
// ctx.save(); // ctx의 현재 상태(색상, 스타일 등) 저장할 수 있음
ctx.lineWidth = 1; // 텍스트 굵기 1으로 변경 -> 브러쉬에도 영향 줌
ctx.font = "48px sans-serif";
ctx.fillText(txt, e.offsetX, e.offsetY);
// ctx.restore(); // save와 restore 사이에서는 어떤 것도 저장되지 않을 것
ctx.lineWidth = lineWidth.value;
}
}
canvas.addEventListener("dblclick", dbClick); // ❗ 오타 주의 "dbl"click임!
<button id="save">Save Image</button>
const save = document.getElementById("save");
function onSave(){
const url = canvas.toDataURL(); // 이미지 url 링크로 변환
const a = document.createElement("a");
a.href = url;
a.download = "myDrawing.png" // 이미지 파일 이름
a.click();
}
save.addEventListener("click", onSave);