[JavaScript] 그림판 만들기


CANVAS

Canvas API는 JavaScript와 HTML <canvas> 엘리먼트를 통해 그래픽을 그리기위한 수단을 제공합니다. 무엇보다도 애니메이션, 게임 그래픽, 데이터 시각화, 사진 조작 및 실시간 비디오 처리를 위해 사용됩니다. Canvas API는 주로 2D 그래픽에 중점을 두고 있습니다. WebGL API 또한 <canvas> 엘리먼트를 사용하며, 하드웨어 가속 2D 및 3D 그래픽을 그립니다.

HTML

  • CSS는 class 이용, JS는 id이용해 일관성 유지
<body>
  <canvas id="jsCanvas" class="canvas"></canvas>              <!-- canvas tag지정 -->
  <div class="controls">                                      <!-- ragne, button, color변경을 위한 div -->
    <div class="controls__range">                             <!-- paint 굵기 지정 -->
      <input type="range" id="jsRange" min="0.1" max="5" value="2.5" step="0.1"/>
    </div>
    <div class="controls__btns">                              <!-- fill/paint, save및 색생 지정을 위한 controls__btns div-->
      <button class="btn" id="fill">Fill</button>
      <button class="btn" id="save">Save</button>
    </div>
    <div class="controls__colors" id="colors">                <!-- 색 변경을 위한 controls__colors div 아래 각 div생성 후 색 지정 -->
      <div class="color jsColor" style="background-color:black"></div>
      <div class="color jsColor" style="background-color:white"></div>
      <div class="color jsColor" style="background-color:red"></div>
      <div class="color jsColor" style="background-color:yellow"></div>
      <div class="color jsColor" style="background-color:orange"></div>
      <div class="color jsColor" style="background-color:green"></div>
      <div class="color jsColor" style="background-color:rgb(128, 219, 255)"></div>
      <div class="color jsColor" style="background-color:blue"></div>
      <div class="color jsColor" style="background-color:rgb(158, 34, 158)"></div>
    </div>
  </div>
  <script src="app.js"></script>
</body>
</html>

CSS

@import "reset.css";                  /*css 초기화*/

body{                                 
  /* background-color: #dfe2e6; */
  background-color: #e0e0e0;
  font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 50px;
}

.canvas{                              /*canvas size및 style지정*/
  width: 700px;
  height: 700px;
  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.8);
}

.controls{
  padding-top:30px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.controls .controls__colors{
  display: flex;
}

.controls .controls__btns{
  margin-bottom : 20px;
}

.controls__btns .btn{
  all : unset;
  cursor: pointer;
  background-color:white;
  padding : 5px 0px;
  width : 80px;
  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.8);
  border : 1px solid rgba(0,0,0,0.2);
  color : rgba(0,0,0,0.8);
  font-weight: 600;
  font-size: 12px;
}

.controls__btns .btn:active{
  transform: scale(0.98);
}

.controls__colors .color{
  width: 50px;
  height: 50px;
  border-radius: 50%;
  text-align: center;
  line-height:50px;
  cursor: pointer;
  box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0,0,0,0.8);
}

.controls .controls__range{
  margin-bottom: 30px;
}

JS

const canvas = document.getElementById('jsCanvas');
const ctx = canvas.getContext('2d');
const colors = document.getElementsByClassName('jsColor')
const range = document.getElementById('jsRange')
const fill = document.getElementById("fill")
const save = document.getElementById("save")

canvas.width = 700;
canvas.height = 700;

ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);

// defualt값으로 초기화
ctx.strokeStyle = "black"
ctx.fillStyle = "black"
ctx.lineWidth =2.5;

let painting = false;
let filling = false;

startPainting = () =>{
  painting = true;
}

stopPainting = () => {
  painting = false;
}

function onMouseMove(event) {
  // canvas 안에서만 마우스의 움직임에 따라 좌표를 얻음(screen의 좌표는 clientX,Y참조)
  const x = event.offsetX
  const y = event.offsetY
  if(!painting) {            //마우스 이동(클릭X)지점으로 beginpath 및 해당좌표 붓 이동
    ctx.beginPath();
    ctx.moveTo(x, y);
  }else {                    //line생성
    ctx.lineTo(x, y);
    ctx.stroke();
  }
}

handleCanvasClick = () => {
  if(filling){
    ctx.fillRect(0,0,canvas.width,canvas.height);
    // console.log(e)
  }
}

handleCM = (e) => {
  // console.log(e)
  e.preventDefault();
}

if(canvas){
  canvas.addEventListener("mousemove", onMouseMove);    //마우스 좌표따라 path생성
  canvas.addEventListener("mousedown", startPainting);  //painting=true, onMouseMove함수로 인해 path 생성
  canvas.addEventListener("mouseup", stopPainting);     //painting=flase
  canvas.addEventListener("mouseleave", stopPainting);  //painting=flase
  canvas.addEventListener("click",handleCanvasClick);   //paint -> fill 변경
  canvas.addEventListener("contextmenu", handleCM);     //마우스 우클릭 방지
}

if(range){
  // line width조정
  range.addEventListener("input",handleRangeChange);
}

handleRangeChange = (e) =>{
  const size = e.target.value;
  ctx.lineWidth = size;
}

// console.log(Array.from(colors));
if(colors){
  Array.from(colors).forEach(color => color.addEventListener("click",changeColor))
  fill.addEventListener("click",handleModeClick)
}

changeColor = (e) => {
  const bgColor = e.target.style.backgroundColor
  // console.log(bgColor);
  ctx.strokeStyle = bgColor;
  ctx.fillStyle=ctx.strokeStyle;
}

function handleModeClick(){
  if(filling === true) {
    filling = false;
    fill.innerText = "Fill";
  }else{
    filling = true;
    fill.innerText="Paint";
  }
}

if(save){
  save.addEventListener("click",handleSaveClick)
}

//save
handleSaveClick = () => {
  // const image = canvas.toDataURL("image/jpeg"); //jpeg로 저장
  const image = canvas.toDataURL();                //png로 저장
  const link = document.createElement("a");
  link.href = image;
  link.download = "PainJS[EXPORT]";
  // console.log(link);
  link.click();
}

addEventListener - mouse

이벤트명 설명
mousedown 마우스를 클릭 했을 때 발생
mouseout 마우스가 특정 객체 밖으로 나갔을 때 발생
mouseover 마우스가 특정 객체 위로 올려졌을 때 발생
mousemove 마우스가 움직였을 때 발생
mouseup 마우스에서 손을 뗐을 때 발생

댓글남기기