(1)에서 색상 변경 + 현재 색상 보기 + Fill + Clear 추가
<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>
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);
}
}
.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;
}