預計會花十五篇到二十篇使用 React 做出復刻 XP 的小畫家!
讓大家在過程中也可以學習到相關的 canvas 技巧,不會 React 的人也不必擔心,使用 jQuery 或是 vue 利用相關的技巧也可以達成一樣的效果,跟著一起動手試試看吧~!
為了有真的復刻小畫家的感覺,所以拉了一個小畫家的 layout,各位可以先開一個 canvas 的畫布,整個結束後會再補上 gitlab 的連結給大家參考。
筆者使用到 react, recoil, lodash, 各位也可以依自己的習慣去使用擅長的工具。
大致區分了幾個區域
組件 | 功能 |
---|---|
App | 集合整體 |
CanvasBox | 主體 Canvas |
Menu | 上排功能列 |
SelectorColorList | 選擇顏色區域 |
StatusBar | 最下方狀態列 |
ToolList | 左側工具列 |
首先先開一個畫布出來
CanvasBox/index.tsx
/**
* 畫布區塊
*/
import React, { useEffect, useRef } from "react";
import { Wrapper, MainCanvas } from "./style";
const CanvasBox = () => {
const canvasRef = useRef(null);
return (
<Wrapper>
<MainCanvas ref={canvasRef} height={500} width={500}></MainCanvas>
</Wrapper>
);
};
export default CanvasBox;
再來在 ToolList 的檔案建好工具列
ToolList/index.tsx
/**
* 側邊工具欄
*/
import React, { useState } from "react";
import { Wrapper, Component, ToolIcon, List } from "./style";
import map from "lodash/map";
import toolsMap from "./toolsMap.json";
const ToolList = () => {
const [active, setActive] = useState(0);
return (
<Wrapper>
<Component>
<List className="tools">
{map(toolsMap, (item, index) => (
<ToolIcon
onClick={() => setTool(item?.key)}
key={item?.title}
title={item?.title}
index={index}
active={tool === item?.key}
>
<span></span>
</ToolIcon>
))}
</List>
</Component>
</Wrapper>
);
};
export default ToolList;
將上方的
const [active, setActive] = useState(0);
改寫為
const [tool, setTool] = useRecoilState<string>(toolState);
方便後續跨區使用
ToolList/toolsMap.json
[
{ "name": "freeFormSelec", "title": "選擇任意範圍" },
{ "name": "selec", "title": "選擇" },
{ "name": "eraser", "title": "橡皮擦/彩色橡皮擦" },
{ "name": "fillColor", "title": "填入色彩" },
{ "name": "pickColor", "title": "挑選顏色" },
{ "name": "magnifier", "title": "放大鏡" },
{ "name": "pencil", "title": "鉛筆" },
{ "name": "brush", "title": "粉刷" },
{ "name": "airbrush", "title": "噴槍" },
{ "name": "text", "title": "文字" },
{ "name": "line", "title": "直線" },
{ "name": "curve", "title": "曲線" },
{ "name": "rectangle", "title": "矩形" },
{ "name": "polygon", "title": "多邊形" },
{ "name": "ellipse", "title": "橢圓形" },
{ "name": "roundedRectangle", "title": "圓角矩形" }
]
SelectorColorList/index.tsx
/**
* 顏色列表
*/
import { useState } from "react";
import colorList from "./defalutColorList.json";
import map from "lodash/map";
import {
Wrapper,
CurrentColorBox,
ListBox,
Item,
ActiveColor,
SubColor,
} from "./style";
const SelectorColorList = () => {
const [activeColor, setActiveColor] = useState<string>("#000");
const [subColor, setSubColor] = useState<string>("#FFF");
return (
<Wrapper>
<CurrentColorBox>
<ActiveColor color={activeColor}></ActiveColor>
<SubColor color={subColor}></SubColor>
</CurrentColorBox>
<ListBox>
{map(colorList, (item) => (
<Item
color={item}
key={item}
onClick={() => setActiveColor(item)} // 左鍵選擇顏色
onContextMenu={() => setSubColor(item)} // 右鍵選擇顏色
></Item>
))}
</ListBox>
</Wrapper>
);
};
export default SelectorColorList;
與工具列同理,將選取的顏色改為
const [activeColor, setActiveColor] = useRecoilState<string>(
activeColorState
);
const [subColor, setSubColor] = useRecoilState<string>(subColorState);
最後開一個存控制項 state
data/atom.tsx
import { atom } from "recoil";
/**
* 全局正在編輯ID
*/
const activeColorState = atom({
key: "activeColorState",
default: "#000",
});
const subColorState = atom({
key: "subColorState",
default: "#FFF",
});
const toolState = atom({
key: "toolState",
default: "pencil",
});
export { activeColorState, subColorState, toolState };
準備就緒!下一篇就要來到我們第一個使用畫筆的功能!