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!

明天教学如何绘制线条~!


<<:  第 5 集:CSS 社交距离(上)

>>:  Day8-D3 资料整理的API们:Array、Time Formats、Number Formats、Random

The field that fears with

In my career path, there is one type of job that I...

【把玩Azure DevOps】Day18 CI/CD从这里:Pipeline设定Yaml以外的Trigger方式

前一篇提到了Build pipeline的排程除了可以在Yaml内设定之外,也可以透过传统UI的方式...

【第十二天 - Flutter NetWork 网路判断】

前言 今日的程序码 => GIHUB 说明 这是一个网路判断的一个范例,将会使用 data_c...

【後转前要多久】# Day17 BootStrap - 介绍、导入

个人主要是看金鱼都能懂的Bootstrap影片学习BootStrap的, 比起看文件的方式学习,金鱼...

[day-30] 从U-net 学到了什麽

心得 这次的铁人赛又完赛了,想起第一次参加,学习自己不熟的东西,每天都要实作,实作到最後竟然断赛了,...