iT邦幫忙

2021 iThome 鐵人賽

DAY 5
0
Modern Web

Canvas 小錦囊系列 第 5

Day 5 - 用 canvas 復刻 小畫家 挑選顏色(顏色選取器)

選取器

選取器使用到 getImageData

ctx.getImageData(sx, sy, sw, sh);

利用 getImageData 可以得到指定範圍內的數值

可以看到在 data 內的值即為色碼,我們只需將它拼裝成 rgba 就完成了!

關於事件

在上一篇章用鉛筆繪畫時,mouseMove會回傳給我們
const point = { x: e.offsetX, y: e.offsetY }
但在做選取範圍時,我們操作的判斷,是做在 點擊 事件,
並沒有直接回傳 offsetX 回來,所以我們需要自己進行計算,
利用 element的 位置與滑鼠所點擊得 clientX 來計算。

來看看程式碼吧

/**
* 提取顏色
*/
const pickColor = (e: any) => {
let rect = canvasRef.current.getBoundingClientRect();
    const point = {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top,
    };
    if (canvasRef.current) {
      const ctx = canvasRef.current.getContext("2d");
      const p = ctx.getImageData(point?.x, point?.y, 1, 1).data;
      const color = `rgba(${p[0]}, ${p[1]}, ${p[2]}, ${p[3]})`;
      setActiveColor(color);
    }
};

我們也對上一篇的點擊滑鼠進行修改

// 滑鼠點下畫布
const handleMouseDown = (event: any) => {
    setIsDrawing(true);
    switch (tool) {
      case "fillColor":
        fillCanvas();
        break;
      case "pickColor":
        pickColor(event);
        break;
      default:
        break;
    }
  };

看看效果

補充

在上週我們建立的 toolsMap.json 做些修改

toolsMap.js

import airbrush from "../images/cursors/airbrush.png";
import eyeDropper from "../images/cursors/eye-dropper.png";
import fillBucket from "../images/cursors/fill-bucket.png";
import precise from "../images/cursors/precise.png";
import pencil from "../images/cursors/pencil.png";
import preciseDotted from "../images/cursors/precise-dotted.png";
import magnifier from "../images/cursors/magnifier.png";

const toolsMap = [
  { name: "freeFormSelec", title: "選擇任意範圍", cursor: precise },
  { name: "selec", title: "選擇", cursor: precise },
  { name: "eraser", title: "橡皮擦/彩色橡皮擦", cursor: precise },
  { name: "fillColor", title: "填入色彩", cursor: fillBucket },
  { name: "pickColor", title: "挑選顏色", cursor: eyeDropper },
  { name: "magnifier", title: "放大鏡", cursor: magnifier },
  { name: "pencil", title: "鉛筆", cursor: pencil },
  { name: "brush", title: "粉刷", cursor: preciseDotted },
  { name: "airbrush", title: "噴槍", cursor: airbrush },
  { name: "text", title: "文字", cursor: precise },
  { name: "line", title: "直線", cursor: precise },
  { name: "curve", title: "曲線", cursor: precise },
  { name: "rectangle", title: "矩形", cursor: precise },
  { name: "polygon", title: "多邊形", cursor: precise },
  { name: "ellipse", title: "橢圓形", cursor: precise },
  { name: "roundedRectangle", title: "圓角矩形", cursor: precise },
];

export default toolsMap;

利用 cursor 可以在畫布上指定對的游標圖案

CanvasBox/index.tsx

...more
 <MainCanvas
       ...
        cursor={tool}
      ></MainCanvas>

CanvasBox/style.tsx

import find from "lodash/find";
...
const MainCanvas = styled("canvas")<{ cursor: any }>`
  background: #fff;
  cursor: ${(props: { cursor: string }) => {
    const active = find(toolsMap, { name: props?.cursor });
    return `url(${active?.cursor}) 9 22, crosshair`;
  }};
`;

Done!

明天教學如何繪製線條~!


上一篇
Day 4 - 用 canvas 復刻 小畫家 填入色彩, 橡皮擦
下一篇
Day 6 - 用 canvas 復刻 小畫家 直線
系列文
Canvas 小錦囊30

尚未有邦友留言

立即登入留言