LWC에서 Canvas 사용해서 글씨 쓰기 (2)

ahncheer·2024년 8월 9일
0

LWC & LWR

목록 보기
50/52

(1)에서 색상 변경 + 현재 색상 보기 + Fill + Clear 추가

1-1. html

<template>
    <div class="cpCanvas">
        <h4 class="page-title">Canvas Test</h4>
        <ul class="top-btn">
            <li class="current-color">Current Color : <span class="color-circle" style={circleColorStyle}></span></li>
            <li class="fill-btn" onclick={colorFill}>Fill</li>
            <li class="clear-btn" onclick={canvasClear}>Clear</li>
        </ul>
        <div class="canvas" style="width:100%"
            onmousemove={onMouseMove} onmousedown={startPainting}
            onmouseup={stopPainting} onmouseleave={stopPainting}></div>
        <ul class="color-btn">
            <li>Color Change : </li>
            <template for:each={colorBtnList} for:item="item" for:index="index">
                <li key={item.label} data-idx={index} 
                    onclick={changeColor} class="btn" style={item.style}></li>
            </template>
        </ul>
    </div>
</template>

1-2. JS

import { LightningElement, track } from 'lwc';

export default class CpCanvas extends LightningElement {
    @track chartValue;
    @track painting = false;
    @track currentColor = '#706671';
    get circleColorStyle(){
        return `background-color : ${this.currentColor}`;
    }

    @track width = 1000;
    @track height = 500;

    @track isFirstRender = true;

    @track colorBtnList = [
        {label : '회색', color: '#706671', style : 'background-color: #706671;'},
        {label : '하늘색', color: '#b5d9e0', style : 'background-color: #b5d9e0;'},
        {label : '보라색', color: '#b784d0', style : 'background-color: #b784d0;'},
    ];
    async renderedCallback() {
        if (this.isFirstRender) {
            this.createCanvas();
            this.isFirstRender = false;
        }
    }
    createCanvas() {
        // Gauge 만들기 (CodePen) 참고
        const canvas = document.createElement('canvas');
        this.template.querySelector('div.canvas').appendChild(canvas);
        const ctx = canvas.getContext("2d");
        console.log('ctx : ', ctx);

        canvas.width = this.width;
        canvas.height = this.height;
        canvas.style.margin = "0 auto";
        canvas.style.border = "3px double";
        canvas.style.display = "block";

        ctx.strokeStyle = this.currentColor;
        ctx.lineWidth = 3;

        this.painting = false;
    }
    
    // 클릭 (stopPainting)
    stopPainting(e) {
        console.log('stopPainting');
        this.painting = false;
    }
    // 클릭 해제 (startPainting)
    startPainting(e) {
        console.log('startPainting');
        this.painting = true;
    } 

    // 마우스 움직였을 때 
    onMouseMove(e) {
        console.log('onMouseMove');
        const ctx = this.template.querySelector('div.canvas canvas').getContext("2d");

        const x = e.offsetX;
        const y = e.offsetY;
            if (!this.painting) {
                ctx.beginPath();
                ctx.moveTo(x, y);
            } else {
                ctx.lineTo(x, y);
                ctx.stroke();
            }
    }
    // 색상 변경
    changeColor(e){
        let idx = e.currentTarget.dataset.idx;
        if(idx > -1){ 
            let newColor = this.colorBtnList[idx].color;
            console.log('newColor : ', newColor);
            this.currentColor = newColor;

            const ctx = this.template.querySelector('div.canvas canvas').getContext("2d");
            ctx.strokeStyle = this.currentColor;
        }
    }

    // 색 채우기
    colorFill(){
        console.log('colorFill');
        const ctx = this.template.querySelector('div.canvas canvas').getContext("2d");
        ctx.fillStyle = this.currentColor;
        ctx.fillRect(0, 0, this.width, this.height);
    }
    // 캔버스 Clear
    canvasClear(){
        console.log('canvasClear');
        const ctx = this.template.querySelector('div.canvas canvas').getContext("2d");
        ctx.clearRect(0, 0, this.width, this.height);
    }

}

1-3. CSS

.cpCanvas{
    max-width: 1080px;
    margin: 0 auto;
}
.page-title{
    font-size: 24px;
    font-weight: bold;
    padding: 20px 0;
}

/*  */
ul.top-btn {
    padding: 35px 0 20px;
    display: flex;
    gap:  20px;
}
.top-btn .fill-btn,
.top-btn .clear-btn{
    background-color: #333;
    color: #fff;
    font-weight: bold;
    padding: 6px 16px;
    border-radius: 5px;
}
.top-btn  li.current-color {
    margin-right: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    font-weight: bold;
    font-size: 18px;
}
.top-btn .current-color .color-circle{
    width: 15px;
    height: 15px;
    border-radius: 50%;
    margin-right: auto;
    display: inline-flex;
}

/*  */
.color-btn{
    padding: 35px 0 20px;
    display: flex;
    gap: 20px;
    justify-content: center;
}

ul.color-btn .btn {
    padding: 8px 16px;
    border-radius: 50%;
    box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
    cursor: pointer;
}

1-4. 화면 확인

profile
개인 공부 기록용.

0개의 댓글