Day 18 - 用 canvas 制作电子贺卡

前述

接续昨天做的『文字换行』,今天利用上一篇的操作来做一个应用,
这次的应用灵感是从这个网站来的,滑到最下方,有一个填上文字、修改位置与大小,就可以下载成为贺卡的功能,偷看了一下他的程序码是用 jQuery 完成的,这边我用 React 带大家试试看!

实践

建立材料

首先我们将观察到的材料准备好

需要一个主要的 canvas 以及几个控制项

  const canvasRef = useRef(null);
  const [style, setStyle] = useState({ size: 14, top: 10, left: 10 });
  const [text, setText] = useState("");
  const [image, setImage] = useState(new Image());
  
  return <div>
      <canvas ref={canvasRef}></canvas>
      <div className="mt-8 max-w-xl mx-auto px-8">
        请输入文字
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
      </div>
      <div>
        左右
        <input
          type="range"
          value={style?.left}
          onChange={(e) => updateStyle(e, "left")}
        />
      </div>
      <div>
        上下
        <input
          type="range"
          value={style?.top}
          onChange={(e) => updateStyle(e, "top")}
        />
      </div>
      <div>
        大小
        <input
          type="range"
          value={style?.size}
          onChange={(e) => updateStyle(e, "size")}
        />
      </div>
      <button onClick={download}>下载</button>
    </div>

再来就是依据不同的控制项作出不同的处理


/** 放上背景图 **/
  useEffect(() => {
    if (canvasRef.current) {
      const drawImage = () => {
        const base_image = new Image();
        base_image.setAttribute("crossorigin", "anonymous");
        base_image.src = exampleImg;
        base_image.onload = () => {
          setImage(base_image);
        };
      };
      drawImage();
    }
  }, [canvasRef]);


/** 依照不同的控制项目对文字做改变 **/
  useEffect(() => {
    const drawText = async () => {
      const canvas = canvasRef.current;
      const ctx = canvas.getContext("2d");
      ctx.fillStyle = "#FFF";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
      ctx.font = `bold ${style?.size}px Arial`;
      ctx.strokeStyle = "white";
      ctx.lineWidth = 3;
      ctx.fillStyle = "black";
      ctx.fillText(text, style?.left, style?.top);
    };

    drawText();
  }, [text, style, image]);

  const updateStyle = (e, key) => {
    setStyle((prev) => ({ ...prev, [key]: e.target.value }));
  };

这里有一个很重要需要注意的地方!
在改变控制项的时候
需要随时清掉画面,如果不将画面清掉,就会反覆在画布上增加文字,造成画面混乱
所以
ctx.fillRect(0, 0, canvas.width, canvas.height);

这个是必要得存在!

再来重复复习昨天的换行功能,
将上方的 fillText 改为 canvasTextAutoLine(text, canvas, style?.left, style?.top, style?.size);
也可以将 textarea 内的 \n作为判断条件来达成文字换行。

今天的电子贺卡就完成啦~
也可以像上面的范例一样,增加选择图片或是文字颜色来增加贺卡的丰富度~

查看完成程序码 codesendbox


<<:  Day18 NiFi - 与 AWS Athena & AWS Redshift 对接设定

>>:  Vue.js 从零开始:元件

Day 14 - useContext

如果有错误,欢迎留言指教~ Q_Q 在各个 component 们都需要的状态的 在前几篇, co...

WSL2, VM, Dual Boot, Proxmox怎麽选?

更多会员限定文章可以到patreon观看 WSL2, VM, Dual Boot, Proxmox怎...

[第二十九天]从0开始的UnityAR手机游戏开发-攻击按钮和UI血条

在ChangeAnimation脚本中新增此程序码 public void AniSJskill1(...

Day29 Data Storage in iOS 05 - Core Data 实作专案范例

之前在Android 就接触过MVC、MVP以及MVVM,这边先不对各差别去作比较分析,直接来对M...

Leetcode 挑战 Day 12 [ 26. Remove Duplicates from Sorted Array]

26. Remove Duplicates from Sorted Array 今天我们一起挑战le...