آموزش ساخت اپلیکیشن نقاشی با React.JS و HTML5 Canvas

آموزش ساخت اپلیکیشن نقاشی با React.JS و HTML5 Canvas

احتمالا تا به حال با نرم‌افزارهایی مانند windows paint، adobe photoshop ، Gimp و یا نرم‌افزارهای مشابه دیگری کار کرده‌اید. در این مقاله قصد داریم کمی از دانش فرانت‌اندی خود استفاده کرده و به کمک کتابخانه React و canvas در HTML5 ، یک اپلیکیشن ساده اما جذاب بسازیم. تصویر زیر خروجی نهایی ما خواهد بود:

React یک کتابخانه جاوااسکریپتی کوچک برای ساخت رابط کاربری صفحات وب است. تگ canvas در HTML5 نیز برای نمایش المان‌های گرافیکی (مانند SVG) به کار میرود.
اجازه دهید قبل از شروع درباره پیشنیازهای این پروژه صحبت کنیم.

پیشنیازها:

از آنجایی که هدف این مقاله آموزش ساخت یک اپلیکیشن کاربردی بوده و آموزش ابتدایی React نیست انتظار میرود با موارد زیر آشنایی حداقلی داشته باشید:
• آشنایی با HTML5
• آشنایی با CSS
• آشنایی با javascript
• آشنایی مقدماتی با React

همچنین قبل از شروع، دقت داشته باشید که موارد زیر بر روی سیستم عامل شما نصب شده باشد:

• NodeJS: از nodejs برای ساخت اپلیکیشن‌‌های جاوااسکریپتی استفاده خواهیم کرد. برای نصب nodejs کافیست وارد لینک زیر شده و با توجه به سیستم عاملی که نصب دارید، نسخه مورد نظر را دانلود و نصب کنید: NodeJS
• Code editor: برای ویرایش کدهای برنامه به یک editor کد نیاز داریم. پیشنهاد میکنم از VS Code استفاده کنید. از ویژگی‌های این ویرایشگر کد قدرتمند میتوان به رایگان بودن، حجم کم، نصب آسان و وجود افزونه‌های بسیار زیاد اشاره کرد. کافیست بر روی لینک زیر کلیک کنید و این ویرایشگر را متناسب با سیستم عامل خود دانلود کنید: Visual Studio Code

ساخت پروژه React:

برای ساخت یک پروژه با React روش‌های مختلفی وجود دارد. ساده‌ترین روش برای ساخت یک پروژه SPA (مخفف Single Page Application) با React، استفاده از create-react-app است. برای این کار کافیست از دستور npx (که با نصب کردن nodejs بر روی سیستم عامل شما نصب میشود) استفاده کنید. Command line خود را باز کنید (مانند cmd در ویندوز). وارد مسیری که قصد ایجاد پروژه را دارید شده و دستور زیر را اجرا کنید:

npx create-react-app drawing_app

دستور بالا یک پروژه با نام drawing_app برای شما خواهد ساخت (میتوانید نام پروژه را به صورت دلخواه تغییر دهید). ممکن است اجرای این دستور چند لحظه طول بکشد. بعد از ساخته شدن پروژه، فولدر drawing_app ساخته خواهد شد. این فولدر را توسط ویرایشگر کد خود باز کنید. پروژه‌ای که با create-react-app ساخته میشود شامل فایل‌های مختلفی میباشد. در بین این فایل‌ها ما با فایل‌های App.js و App.css که در فولدر src قرار دارند سر و کار خواهیم داشت.

بیایید برای شروع یک template و ظاهر ساده برای اپلیکیشن بسازیم. برای این کار وارد فایل App.js شده و کدهای زیر را در تابع App قرار دهید:

import React from 'react';
import './App.css';

function App() {
return (
<div className="App">
<div className="panel-color-picker">
<h5>Colors:</h5>
<span title="black" className="color-item black" ></span>
<span title="white" className="color-item white"></span>
<span title="red" className="color-item red"></span>
<span title="blue" className="color-item blue"></span>
<span title="aqua" className="color-item aqua"></span>
<span title="green" className="color-item green"></span>
</div>
<div className="panel-drawing">
<canvas id="canvas"></canvas>
</div>
</div>
);
}

export default App;

در قطعه کد بالا دو div در نظر گرفته شده است. یکی برای نمایش color pallet (که رنگ‌ها از این قسمت انتخاب خواهند شد) و دیگری برای نمایش دادن canvas که با حرکت mouse طرح ما را رسم خواهد کرد (برای درک بهتر این دو قسمت به تصویر ابتدای مقاله نگاه کنید). برای هر رنگ یک تگ span در نظر گرفته شده است که با کمک CSS به هر یک style مورد نظر را اعمال خواهیم کرد.
در نظر داشته باشید برای راحتی کار با state ها و lifeCycle ها در React ، از functional component ها به جای class component ها کردیم. در ادامه از hook ها برای این منظور استفاده خواهیم کرد. (اگر با hookها آشنایی ندارید بر روی این لینک کلیک کنید)

حال برای تغییر style تگ‌ها، کدهای زیر را در فایل App.css قرار دهید:

* {
box-sizing: border-box;
}

.App {
display: flex;
width: 100%;
height: 100vh;
}

.panel-color-picker {
width: 60px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
background-color: #c8c8c8;
}

.panel-color-picker .color-item {
width: 50px;
height: 50px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
}

.panel-color-picker .color-item.black {
background-color: black;
}

.panel-color-picker .color-item.white {
background-color: white;
}

.panel-color-picker .color-item.red {
background-color: red;
}

.panel-color-picker .color-item.blue {
background-color: blue;
}

.panel-color-picker .color-item.aqua {
background-color: aqua;
}

.panel-color-picker .color-item.green {
background-color: green;
}

.panel-drawing {
width: 100%;
height: 100%;
border: 2px solid #4b4b4b;
}

.panel-drawing canvas {
width: 100%;
height: 100%;
}

اگر دقت کنید، در کدهای CSS بالا عرض قسمت سمت چپ (که رنگ‌ها را در بر خواهد گرفت) 60px در نظر گرفته شده است. این اندازه را به خاطر بسپارید چرا که در ادامه مقاله به این عدد احتیاج خواهیم داشت.

بسیار خب! تا اینجا ظاهر برنامه آماده شده است. میتوانید با اجرا کردن پروژه ظاهر برنامه را ببینید. برای اجرای پروژه کافیست command line را باز کرده، وارد مسیر پروژه شده و دستور زیر را اجرا کنید:

npm start


حال اگر مسیر localhost:3000 را در مرورگر خود باز کنید بایستی پروژه را مشاهده کنید.

همانطور که گفته شد از canvas برای نمایش المان‌های گرافیکی در وب استفاده میشود. برای دسترسی به محتوای canvas میتوانید با استفاده از کوئری‌های جاوا اسکریپت ابتدا تگ canvas را انتخاب کرده و با استفاده از متد getContext ، به محتوای آن دسترسی داشته باشید. مانند قطعه کد زیر:

let canvas = document.getElementById("canvas");

let ctx = canvas.getContext("2d");

برای دسترسی به ctx در کامپوننت App میتوان آن را در یک state ذخیره کرد. برای استفاده از state ها در functional component های React، از hook به نام useState استفاده میکنیم.
همچنین دقت داشته باشید تنها زمانی به canvas دسترسی خواهیم داشت که کامپوننت ما به صورت کامل mount شده و JSX رندر شده باشه (در غیر این صورت مقدار ctx برابر null خواهد بود). برای این منظور باید کوئری که در بالا گفته شد را داخل useEffect که یک hook برای استفاده از lifecycle ها در React است استفاده کنیم.

ابتدا useState و useEffect را از پکیج react وارد پروژه کنید:

import {useState, useEffect} from 'react';

...//

قطعه کد زیر به ما این امکان رو خواهد داد که از ctx در کامپوننت App استفاده کنیم:

function App() {

let [ctx, setCtx] = useState(null);


useEffect(() => {
let canvas = document.getElementById("canvas");
canvas.height = window.innerHeight;
canvas.width = window.innerWidth - 60;
setCtx(canvas.getContext("2d"));
}, []);

return ( /** ** /);

نکته: در کد بالا اندازه canvas را برابر با اندازه window قرار دادیم. فقط به خاطر داشته باشیم که 60px برای عرض panel رنگ ها در نظر گرفته بودیم که باید از عرض canvas کم کنیم.
نکته 2: دقت کنید که با اضافه کردن [] به عنوان آرگومان دوم در متد useEffect ، callback تنها یک بار و زمانی که کامپوننت mount میشود اجرا خواهد شد.

حال بیایید نحوه رسم اشکال مختلف داخل canvas را بررسی کنیم. برای رسم اشکال canvas متدهای مختلفی وجود دارد. به طور مثال متد ctx.fillReact(x,y,width,height) باعث میشود یک چهار ضلعی تو پُر داخل canvas رسم گردد. نقطه شروع این چهار ضلعی x و y و عرض و ارتفاع width و height خواهد بود. به طور مثال برای ساخت یک چهار ضلعی در نقطه (50,50) و با عرض و ارتفاع 100 میتوانید از کد زیر استفاده کنید:

ctx.fillRect(50,50,100,100);

کد بالا یک مستطیل تو پُر سیاه داخل canvase رسم خواهد کرد. برای اینکه این مستطیل تو خالی بوده و تنها دور مستطیل پُر باشد، میتوانید از strokeRect استفاده کنید. همچنین برای تعیین رنگ میتوانید از strokeStyle برای دور و از fillStyle برای داخل چهار ضلعی استفاده کنید. کد زیر مثالی از ساخت یک مستطیل با رنگ قرمز میباشد:

ctx.strokeStyle = "red";
ctx.strokeRect(100,100,300,300);

نکته: دقت کنید که رنگ باید قبل از رسم شکل تعیین شود.

اگر بخواهید یک خط در canvas رسم کنید، باید از متد beginPath استفاده کنید. بعد از صدا زدن این متد، ابتدا با استفاده از متد moveTo به نقطه ابتدای خط رفته و سپس با متد lineTo نقطه‌ی انتهایی خط را مشخص کنید. در نهایت برای رسم این خط باید از متد stroke استفاده کنید. مثال زیر خطی را رسم میکند که از نقطه (100,100) به نقطه (200,200) رسم شده است:

ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();

بسیار عالی! حال با رسم خط در canvas آشنا شدید. میتوان به جای مشخص کردن نقطه ابتدا و انتها با اعداد ثابت، از موقعیت mouse استفاده کرد و خطوط را در قسمتی که mouse قرار دارد و حرکت میکند رسم کرد. همچنین با استفاده از متد strokeStyle میتوان رنگ خطوط رو مشخص نمود. حال تنها کافیست این منطق را به اپلیکیشن React خود اضافه کنیم. برای این کار ابتدا سه متد تعریف میکنیم تا event ها هنگام کلیک کردن روی mouse، رها کردن mouse و حرکت دادن mouse را اجرا کند. در این متدها خطوط مورد نظر را بر روی canvas رسم میکنیم.
ابتدا متدهای زیر را در کامپوننت App اضافه کنید:

const startPainting = (e) => {

}

const paint = (e) => {

}

const finishPainting = (e) => {

}

سپس این متدها را به event های mouse در تگ canvas اختصاص دهید. کد زیر، کد مورد نظر برای این کار میباشد:

<canvas
id="canvas"
onMouseDown={startPainting}
onMouseUp={finishPainting}
onMouseMove={paint}
></canvas>

برای تشخیص اینکه آیا بر روی mouse کلیک شده است یا خیر میتوان از یک متغیر boolean استفاده کرد و در متدهای startPainting و finishPainting مقدار این متغیر را تغییر داد. برای این کار ابتدا متغیری با استفاده از useState به کامپوننت اضافه کنید:

let [isPainting, setIspainting] = useState(false);

سپس متدهای مورد نظر را به صورت زیر تغییر دهید:

const startPainting = (e) => {
setIspainting(true);
ctx.beginPath()
}

const finishPainting = (e) => {
setIspainting(false);
ctx.beginPath();
}

با استفاده از متغیر isPainting میتوان تشخیص داد که آیا بر روی mouse کلیک شده است یا خیر.
حال برای رسم شکل با استفاده از متد paint میتوان خطی در مکان فعلی mouse رسم کرد. برای این کار متد paint را به صورت زیر پیاده سازی کنید:

const paint = (e) => {
if (isPainting) {
ctx.lineWidth = 6;
ctx.lineCap = "round";

let rect = e.target.getBoundingClientRect();

let mouseX_RelevantToCanvas = e.clientX - rect.left;
let mouseY_RelevantToCanvas = e.clientY - rect.top;

ctx.lineTo(mouseX_RelevantToCanvas, mouseY_RelevantToCanvas);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(mouseX_RelevantToCanvas, mouseY_RelevantToCanvas);
}
}

در این متد به چند مورد باید توجه کرد. در ابتدای متد چک کردیم که آیا بر روی mouse کلیک شده است یا خیر. سپس با استفاده از ctx.lineWidth اندازه خط و با استفاده از ctx.lineCap نوع خط مشخص شده است. نکته مهمی که باید در نظر بگیرید این است که برای یافتن موقعیت mouse بر روی canvas ، بایستی موقعیت mouse را نسبت به تگ canvas بسنجید. برای این کار متغیری به نام rect در نظر گرفته شده است که موقعیت تگ canvas را نسبت به window محاسبه خواهد کرد. سپس با کم کردن اندازه این موقعیت از موقعیت mouse که نسبت به window در نظر گرفته میشود (با استفاده از e.clientX و e.clientY)، موقعیت mouse نسبت به تگ canvas به دست خواهد آمد. حال با داشتن موقعیت mouse نسبت به canvas و با استفاده از متدهای رسم خط، میتوان با حرکت دادن mouse ، خطوط را رسم کرد.

حال میتوان با استفاده از کلیک بر روی mouse و drag کردن داخل canvas خطوط را رسم کرد. تنها کافیست که رنگ این خطوط را تعیین کنیم. برای تعیین رنگ خطوط کافیست از ctx.strokeStyle استفاده کنیم. میتوان متدی برای این کار در نظر گرفت:

const onColorClickHandler = (color) => {
ctx.strokeStyle = color;
}

و با کلیک بر روی قسمت رنگ ها (سمت چپ)، رنگ مورد نظر را به آن اختصاص میدهیم. کافیست کدها را به صورت زیر تغییر دهید:

/**
* component code ...
*/

return (
<div className="App">
<div className="panel-color-picker">
<h5>Colors:</h5>
<span title="black" className="color-item black" onClick={() => onColorClickHandler('black')}></span>
<span title="white" className="color-item white" onClick={() => onColorClickHandler('white')}></span>
<span title="red" className="color-item red" onClick={() => onColorClickHandler('red')}></span>
<span title="blue" className="color-item blue" onClick={() => onColorClickHandler('blue')}></span>
<span title="aqua" className="color-item aqua" onClick={() => onColorClickHandler('aqua')}></span>
<span title="green" className="color-item green" onClick={() => onColorClickHandler('green')}></span>
</div>
<div className="panel-drawing">
<canvas
id="canvas"
onMouseDown={startPainting}
onMouseUp={finishPainting}
onMouseMove={paint}
></canvas>
</div>
</div>
);

بسیار عالی! اپلیکیشن مورد نظر تکمیل شد. کافیست فایل را save کنید و با وارد شدن به آدرس localhost:3000 ، اپلیکیشن را مشاهده کنید.

این پروژه را میتوانید در لینک زیر مشاهده کنید:

https://codesandbox.io/s/sokanacademy-painting-nnw98

تمرین

شما به عنوان تمرین میتوانید موارد زیر را به برنامه خودتان اضافه کنید و برنامه تان را در git قرار دهید و آدرس gitتان را به ما بدهید تا تمرینتان را تصحیح کنیم. (آموزش استفاده از گیت)

1- به کاربر اجازه بدهید ضخامت قلم نقاشی خود را انتخاب کند.

2- امکان کشیدن دایره ، مستطیل و مربع را به کاربر بدهید.

اگر در پیاده سازی این تمرین هم مشکل داشتید لطفا برای ما کامنت بزارید تا سریعا بهتون پاسخ بدیم.

سخن پایانی

در این مقاله با استفاده از React و HTML5 canvas ، یک اپلیکیشن ساده نقاشی ساختیم. میتوانید با استفاده از API های دیگر canvas قابلیت‌های دیگری به اپلیکیشن اضافه کنید. برای مشاهده API های canvas از لینک زیر استفاده کنید:

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API


و برای آشنایی بیشتر با React از این لینک استفاده کنید:

https://reactjs.org/

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس


online-support-icon