March 02, 2020
๋ฐ์ดํฐ๋ค์ ๊ทธ๋ํ๋ก ํํํด๋ณด๊ณ ์ถ์ด์ ๋ง๋ค์ด๋ณด์๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ canvas๋ฅผ ์ด์ฉํด์ ๋ง๋ค์ด๋ณด๋ ค๊ณ ํ๋๋ฐ ๋ง๋ค๊ณ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ๊ฒฌํด๊ฐ ๋ฌ๋ผ์ง๊ฒ ๋์๋ค.
๊ทธ๋ํ๋ canvas๋ฅผ ์ด์ฉํด ๊ทธ๋ ธ๊ณ
๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐ, ์์ , ์ญ์ ํ ์ ์๋ form Input ์์๋ค๋ ๋ฃ์ด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๊ธฐ ๋ฐ์ดํฐ๋ก ์์์ ํค๋ค๊ณผ ๊ฐ๋ค์ ๋ฃ์ด์ฃผ์๋ค.
const data = useSelector(state => state.graph)
const [graphData, setGraphData] = useState(
data.graphData || {
Austrailia: 500,
India: 1800,
USA: 500,
Brasil: 2100,
China: 1500,
}
)
const entries = Object.entries(graphData)
const [country, setCountry] = useState(data.country || '')
const [population, setPopulation] = useState(data.population || '')
const [country2, setCountry2] = useState('')
const [errorMessage, setErrorMessage] = useState('')
const inputRef1 = useRef()
const inputRef2 = useRef()
์ปดํฌ๋ํธ๋ฅผ class ๊ฐ ์๋ ํจ์ํ
์ผ๋ก ๊ตฌ์ฑํ๊ณ ํด๋ก์ , hooks
๋ฅผ ์ด์ฉํด์ ์ปดํฌ๋ํธ ๋ด์์์ ์ํ๊ด๋ฆฌ๋ฅผ ํ์๋ค.
์ํ๋ณ์๋
graphData
: ๊ทธ๋ํ์ ๋ค์ด์๋ ๊ฐ์ฒด ํํ์ ๋ฐ์ดํฐ
country
: ์ถ๊ฐ, ์์ ์ ์ํ ํค๊ฐ
country2
: ์ญ์ ๋ฅผ ์ํ ํค๊ฐ
population
: ์ถ๊ฐ, ์์ ์ ์ํ ๋ฐธ๋ฅ๊ฐ
errorMessage
: ์๋ฌ๋ฉ์์ง๋ฅผ ๋ด์ string ๊ฐ
์ด๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋๋ผ์ ์ธ๊ตฌ๋ก ํด์ country, population์ผ๋ก key, value ๊ฐ๋ค์ ๋ณ์ ๋ค์ด๋ฐ ํด์คฌ๋ค.
๊ทธ๋ฆฌ๊ณ object์ ํค๊ฐ๊ณผ ๋ฐธ๋ฅ๊ฐ์ ๊ด๋ฆฌํ๊ธฐ ์ํด entries ๋ณ์๋ฅผ ๋ง๋ค์ด์คฌ๊ณ
form submit ํ์ ์๋ input focus๋ฅผ ์ํด inputRef1, inputRef2 ๋ณ์๋ ๋ง๋ค์ด์ฃผ์๋ค.
์ฒ์ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ฑํ ๋, graph reducer์ ์ด๊ธฐ๊ฐ์ ๊ฐ์ ธ์ค๋๋ก ์ค์ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฐ๊ธฐ ์ํด ์ด ๊ทธ๋ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ ์ Docker์ ๋ฃ์์ ๋, ํ์ฌ ๋ฆฌ์กํธ state๋ฅผ ๋ฆฌ๋์ค state๋ก ์ฎ๊ธฐ๋๋ก ์ค์ ํ๋ค.
์ฆ, ํด๋น ์ดํ๋ฆฌ์ผ์ด์ ์ state ์กฐ์์ ๋ฆฌ์กํธ๋ก,
ํด๋น ์ดํ๋ฆฌ์ผ์ด์ ์ state ์์์ ์ฅ( Docker ๋๊ธฐ๊ธฐ )์ ๋ฆฌ๋์ค๋ก ํ์๋ค.
useEffect(() => {
let canvasElem = document.querySelector('canvas')
canvasElem.width = 840
canvasElem.height = 320
const ctx = canvasElem.getContext('2d')
drawGrid(canvasElem, ctx)
drawAxis(ctx)
drawChart(ctx)
})
์ปดํฌ๋ํธ๊ฐ ๋ง์ดํ ๋ ํ useEffect hooks๋ฅผ ํตํ์ฌ canvas๋ฅผ ๊ทธ๋ฆฌ๋๋ก ํ์๋ค.
const drawGrid = (canvasElem, ctx) => {
let xGrid = 10
let yGrid = 10
let cellSize = 10
ctx.beginPath()
while (xGrid < canvasElem.height) {
ctx.moveTo(0, xGrid)
ctx.lineTo(canvasElem.width, xGrid)
xGrid += cellSize
}
while (yGrid < canvasElem.width) {
ctx.moveTo(yGrid, 0)
ctx.lineTo(yGrid, canvasElem.height)
yGrid += cellSize
}
ctx.strokeStyle = '#ccc'
ctx.stroke()
}
์ ์ฒด ๊ทธ๋ฆฌ๋๋ฅผ ๊ทธ๋ ค์ฃผ๋ ํจ์ ์์ฑ
const drawAxis = ctx => {
let yPlot = 300
let pop = 0
ctx.beginPath()
ctx.strokeStyle = 'black'
ctx.moveTo(50, 50)
ctx.lineTo(50, 300)
ctx.lineTo(800, 300)
ctx.moveTo(50, 300)
for (let i = 0; i < 10; i++) {
ctx.strokeText(pop, 20, yPlot)
pop += 500
yPlot -= 50
}
ctx.stroke()
}
x์ถ๊ณผ y์ถ, x์ถ์ ๊ฐ๋ค์ ๊ทธ๋ ค์ฃผ๋ ํจ์ ์์ฑ
const drawChart = ctx => {
ctx.beginPath()
ctx.strokeStyle = 'black'
ctx.moveTo(50, 300)
ctx.font = 'bold normal 10px Verdana'
var xPlot = 100
let i = 0
for (const [country, population] of entries) {
var populationInBlocks = population / 10
ctx.fillText(
country + '(' + population + ')',
xPlot,
i % 2 === 0
? 300 - populationInBlocks - 10
: 300 - populationInBlocks - 10 + 30
)
ctx.lineTo(xPlot, 300 - populationInBlocks)
ctx.arc(xPlot, 300 - populationInBlocks, 2, 0, Math.PI * 2, true)
xPlot += 50
i++
}
ctx.stroke()
}
๊ทธ๋ํ๋ฅผ ๊ทธ๋ฆฌ๋ ํจ์ ์์ฑ
๊ทธ๋ํ์ ๊ฐ๊ฐ์ ํ ์คํธ ๊ฐ๋ค์ด ๋์ผํ ์์น์ ์์นํ ๊ฒฝ์ฐ ํ ์คํธ๊ฐ ๊ฒน์น๋ ํ์์ด ์์๋ค. ๊ทธ๋์ ๋ณ์ i๋ฅผ ํ ๋นํ๊ณ ์ง์์ผ ๊ฒฝ์ฐ๋ ๊ผญ์ง์ ๋ฐ์ ํ ์คํธ๋ฅผ ์ ๊ณ ํ์์ผ ๊ฒฝ์ฐ๋ ๊ผญ์ง์ ์์ ํ ์คํธ๋ฅผ ์ ๊ฒํด์ ๊ฒน์น๋ ํ์์ ํผํด์ฃผ์๋ค.
const submitHandler1 = e => {
console.log(graphData)
e.preventDefault()
if (
isNaN(Number(population)) ||
Number(population) > 2500 ||
Number(population) < 0
) {
setErrorMessage('0~2500์ฌ์ด์ ๊ฐ์ ์
๋ ฅํ์ธ์.')
return
}
let obj = { ...graphData }
obj[country] = Number(population)
// obj.county = population not same!!
let graphData_temp = Object.assign({}, obj)
setGraphData(graphData_temp)
setCountry('')
setPopulation('')
setErrorMessage('')
inputRef1.current.focus()
}
๊ฐ input์ ๊ฐ์ด ์ซ์๊ฐ ์๋ ๊ฒฝ์ฐ, ๊ทธ๋ฆฌ๊ณ ์ ๋ ฅ๊ฐ์ ๋ฒ์๊ฐ canvas ๋ฅผ ๋์ ๊ฒฝ์ฐ ํธ๋ค๋งํ๋ ์กฐ๊ฑด๋ฌธ์ ๋ฃ์ด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ ์กฐ๊ฑด๋ฌธ์ ๊ฑธ๋ฆด ๊ฒฝ์ฐ, ์๋ฌ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๊ฒ๋ ํด์ฃผ์๋ค.
ํด๋น ํค์ ๊ฐ์ด ์ ์์ ์ผ ๊ฒฝ์ฐ, state๋ฅผ ๋ถ๋ณ์ฑ์ ์ ์งํ๋ฉด์ ์ ๋ฐ์ดํธํด์ฃผ๋ ค ํ๋ค.
์๋ก์ด obj ๋ณ์์ spread ๋ฌธ๋ฒ(โฆ)์ ํตํด ๊ธฐ์กด state๋ฅผ ์ด๊ธฐํํด์ฃผ์๊ณ obj์ ์๋ก์ด ํค, ๊ฐ์ ๋ฃ์ด์ค ๋ค ์ ๋ฐ์ดํธ ํด์ฃผ์๋ค.
์ฌ๊ธฐ์ ์๋กญ๊ฒ ์ ์ ์,
obj.key = value
๋ฅผ ํตํ obj ์
๋ฐ์ดํธ๋ ์ค์ ๋ก key๊ฐ์ผ๋ก key๊ฐ ๋ค์ด๊ฐ๋ค.
์ด๋ฅผ ํผํ๊ธฐ ์ํด์ obj[key] = value
๋ฅผ ์ด์ฉํด์ผ ์ ์์ ์ผ๋ก key์ string๊ฐ์ด key๋ก ๋ค์ด๊ฐ๋ค.
delete ์ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง๋ค.
delete obj[country2]
์ฌ์ค ๊ทธ๋ํ ์์ ์๋ ์ ์ด๋ ์ ์ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์๋ค.
๊ทผ๋ฐ canvas๋ ํจ์๋ฅผ ํตํด ๋ํ์ ๊ทธ๋ฆด ๋ฟ DOM์ฒ๋ผ ์ง์ ์์ ๋ํ์ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ ์ ์๋ค.
์ค์ canvas์ ์ด๋ฒคํธ๋ฅผ ๊ฑธ๋ ค๋ฉด canvas ์์ฒด์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฌ๊ฑฐ๋ ํด์ผํ๋ค.
์์ง canvas๋ฅผ ์์ ์์ฌ๋ก ์ฌ์ฉํ ์ ์๋ ์ค๋ ฅ์ด๊ธฐ๋ ํ๊ณ canvas ๋ด๋ถ์ ๋ํ์ ์ด๋ฒคํธ๋ฅผ ๋ฃ์ง ๋ชปํ๊ฒ ์ข ์์ฝ๋ค.
๊ทธ๋ํ์ ์ด๋ฒคํธ๋ฅผ ๋ฃ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
๋ค์ ํ๋ก์ ํธ๋ก ๊ทธ๋ํ, ์ฐจํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด๋ณด๊ณ ์ถ๋ค.
๋์์ธ์ด ๋งค์ฐ ๊ตฌ๋ฆฌ๋ค..!
๋ณ์๋ฅผ country, population ์ฒ๋ผ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ชฉ์ ์ฑ์ด ๋ค์ ๋ง์ง ์๋ ๋ค์ด๋ฐ์ ํ๋ค.
๋ผ๋ ํฉ๋ฆฌํ๋ฅผ ํ ์ ์๊ฒ ์ง๋ง,
country, country2 ์ด๋ฐ ๋ณ์ ๋ค์ด๋ฐ์ ํฉ๋ฆฌํ ์์ฒด๋ ๋ถ๊ฐ๋ฅํ๋ค.
๊ฐ๋ฐ์๋ ํท๊ฐ๋ฆฌ๊ธฐ ๋๋ฌธ..
ํด๋น ์ดํ๋ฆฌ์ผ์ด์ ์ด ๊ธฐ๋ฅ์ด ๋ง์ ํธ์ด ์๋๋ผ์ ๋ค์ด๋ฐ์ ์์ ํ์ง๋ ์์์ง๋ง, ์ฒ์ ๋ณ์ ๋ค์ด๋ฐ์ ์ง์ ๋ ๊ทธ๋๋ ์ข ๋ ์ ๊ฒฝ์ฐ๋ ์ต๊ด์ ๋ค์ฌ์ผ๊ฒ ๋ค.