使用excalidraw搭建自己的中文手写画板

news2024/9/23 1:35:34

使用excalidraw搭建自己的中文手写画板

成品预览地址:https://guizimo.github.io/excalidraw/

excalidraw提供了英文的手写体,但中文还是正正方方的,感觉不搭。希望中文也可以有那样一种手写风格。

效果预览

本文使用的是excalidraw,它是一个十分优秀的开源项目,地址:https://github.com/excalidraw/excalidraw

1、创建项目

1.1、拉取代码

首先在excalidrawGithub主页Fork一份代码到自己的账户下

excalidraw

Fork之后,clone到本地

 git clone git@github.com:guizimo/excalidraw.git

然后在这里,签出一个新的分支:zh-dev,这个分支用来提交我们自定义的提交和变动,在后续如果excalidraw更新后,可以合并主干,得到最新的特性。

1.2、运行

尝试本地运行

// 安装依赖
yarn install
// 运行
yarn run start

在浏览器中打开http://localhost:3000/,发现已经可以正常运行了

预览

2、下载中文字体

选择一款你看的舒服的中文手写字体,当然这里你喜欢其他的字体也可。需要注意的是字体的版权问题哈。笔者在选择中文字体的时候发现了一个网站:猫啃网,大家有空可以自己去了解哈。

我这边选择的是平方雨桐体,在这里感谢作者提供那么好的字体!

平方雨桐体预览

下载好中文字体包,并重命名为 Yutong.ttf

3、加入中文字体

到这一步了需要手动调整代码了,因为不同的版本,代码会有一些调整。目前的excalidraw使用了monorepo来管理项目了。

这里提供一种思路,观察其中的一个内置的字体,通过断点调试了解它的加载流程,按照它的思路,添加我们自定义的字体即可。

3.1、放置字体资源

将我们之前下载好的字体文件 Yutong.ttf放置到 packages/excalidraw/fonts/assetspublic目录下。

3.2、注册字体

编辑 packages/excalidraw/fonts/assets/fonts.css,添加中文手写体Yutong

@font-face {
  font-family: "Yutong";
  src: url(./Yutong.ttf) format("truetype");
  style: normal;
  display: swap;
}

编辑packages/excalidraw/index-node.ts添加registerFont

registerFont("./public/Virgil.woff2", { family: "Virgil" });
registerFont("./public/Yutong.ff2", { family: "Yutong" });
registerFont("./public/Cascadia.woff2", { family: "Cascadia" });

3.3、预加载字体资源

编辑excalidraw-app/index.html,添加一个link

<link
   rel="preload"
   href="../packages/excalidraw/fonts/assets/Yutong.ttf"
   as="font"
   type="font/ttf"
   crossorigin="anonymous"
/>

编辑scripts/woff2/woff2-vite-plugins.js,添加一个link

<link
  rel="preload"
  href="/Yutong.ttf"
  as="font"
  type="font/ttf"
  crossorigin="anonymous"
/>

编辑 packages/excalidraw/constants.ts,在 FONT_FAMILY 常量中加入字体的枚举。

这里可以把枚举的数字设置大一点,防止后续更新新加了字体,导致冲突。

export const FONT_FAMILY = {
  Virgil: 1,
  Helvetica: 2,
  Cascadia: 3,
  // leave 4 unused as it was historically used for Assistant (which we don't use anymore) or custom font (Obsidian)
  Excalifont: 5,
  Nunito: 6,
  "Lilita One": 7,
  "Comic Shanns": 8,
  "Liberation Sans": 9,
  Yutong: 999
}

编辑packages/excalidraw/components/FontPicker/FontPicker.tsx,在列表中添加切换按钮。

这里懒得去添加图标和枚举了,我把Nunito的位置给占了哈,不像我这边懒的人可以去加上图标哈。

  {
    value: FONT_FAMILY.Yutong,
    icon: FontFamilyNormalIcon,
    text: t("labels.normal"),
    testId: "font-family-yutong",
  },
  // {
  //   value: FONT_FAMILY.Nunito,
  //   icon: FontFamilyNormalIcon,
  //   text: t("labels.normal"),
  //   testId: "font-family-normal",
  // },

编辑packages/excalidraw/fonts/index.ts添加_register

import Yutong from "./assets/Yutong.ttf";

......
_register("Yutong", FONT_METADATA[FONT_FAMILY.Excalifont], {
  uri: Yutong,
});

再次运行起来,那么在使用字体的第二项的时候,已经可以正常使用我们刚添加的中文手写字体了。

测试

4、部署

在本地已经可以正常使用了,为了更加方便使用,这边直接选择使用Github Page部署。可以借助gh-pages来实现。

gh-pages的原理

就是创建一个gh-pages的分支,将选中的已经构建好的资源文件,放入该分支,然后推送到远程的Github仓库,Github识别到gh-pages的分支有更新,会生成一个deploy,通过该链接就可以正常访问了。

4.1、安装依赖

yarn add -D gh-pages

修改package.json文件,添加deploy脚本。

"scripts": {
  ......,
  "deploy": "gh-pages -d excalidraw-app/build"
}

4.2、调整配置

注意:目前笔者是使用二级部署的,即部署之后访问的链接形式是:https://xxx.com/xxx/excalidraw,需要调整打包之后的资源引用路径。

编辑excalidraw-app/vite.config.mts,使用相对路径base: './'

export default defineConfig({
  ......,
  base: './', // 使用相对路径
  ......,
})

4.3、构建部署

首先打包成为静态资源

yarn run build

部署

yarn run deploy

执行之后,在远程仓库中,会自动创建github-pages deployments

deployments

这里会给到一个链接:https://guizimo.github.io/excalidraw/

image-20240812181447558

打开链接就可以看到成功部署的中文手写版excalidraw了。

image-20240808141942539

编辑Github主页配置。

image-20240812182014787

4.4、踩坑

部署成功之后,自己添加的字体无法正常显示。

报错信息

DOMException: The source provided ('url(https://guizimo.github.io/excalidraw/assets/Yutong-BrR4G41P.ttf) format('ttf')') could not be parsed as a value list.

发现format('ttf')并不是一个合法的格式。但是搜索整个代码,并未声明format('ttf')这样的一种格式。

通过断点调试找到了在packages/excalidraw/fonts/ExcalidrawFont.tsgetFormat方法中,会将字体文件的后缀名作为format,导致浏览器加载不上我们添加的ttf格式字体。

改造getFormat

ttf对应的格式为:truetype

private static getFormat(url: URL) {
  try {
    const pathname = new URL(url).pathname;
    const parts = pathname.split(".");

    if (parts.length === 1) {
      return "";
    }
    // ttf is not a valid format, so we are converting it to truetype
    let type = parts.pop()
    if (type === 'ttf') {
      type = 'truetype'
    }
    return `format('${type}')`;
  } catch (error) {
    return "";
  }
}

各种字体对应的格式

  • format(‘truetype’):用于指定 TrueType 字体(.ttf 文件)的格式。
  • format(‘woff’):用于指定 Web Open Font Format 字体(.woff 文件)的格式。
  • format(‘woff2’):用于指定 Web Open Font Format 2 字体(.woff2 文件)的格式。
  • format(‘opentype’):用于指定 OpenType 字体(.otf 文件)的格式。

重新构建部署,自定义的字体已经生效!

效果预览

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054165.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArchWsl 运行图形界面程序

最新的WSL2已经支持图形界面&#xff08;wslg&#xff09;了&#xff0c;这里教大家运行GUI应用&#xff08;桌面环境同理&#xff0c;但是我建议大家不要安装桌面环境&#xff0c;没有桌面环境也可以单独运行GUI应用&#xff09; 更新WSL 建议更新到最新版本&#xff0c;早期…

web实现drag拖拽布局

这种拖拽布局功能其实在电脑操作系统或者桌面应用里面是经常使用的基础功能&#xff0c;只是有时候在进行web开发的时候&#xff0c;对这个功能需求量不够明显&#xff0c;但却是很好用&#xff0c;也很实用。能够让用户自己拖拽布局&#xff0c;方便查看某个区域更多内容&…

【教学类-72-02】20240819建筑对称图纸02(图案最大化)

背景需求 【教学类-72-01】20240803建筑对称图纸01-CSDN博客文章浏览阅读423次&#xff0c;点赞13次&#xff0c;收藏5次。【教学类-72-01】20240803建筑对称图纸01https://blog.csdn.net/reasonsummer/article/details/140893003 我感觉房子有大有小&#xff0c;有大量空白&…

2、目标识别(颜色识别)

一、根据所使用的视觉模块的官方网站或软件&#xff0c;获取相应颜色的阈值 blue [(23, 74, -119, 19, -125, -29)] #蓝紫色 [(0, 53, -128, 127, -128, -8)] red [(0, 44, 40, 62, 16, 127)] #红色 [(0, 44, 40, 62, 16, 127)] org [(44, 100, 13, 126, 2…

【多线程开发 6】spring中的注解/API的线程问题

【多线程开发 6】spring中的注解/API的线程问题 2024年8月14日 文章目录 【多线程开发 6】spring中的注解/API的线程问题1 Future和CompletableFuture2 hutool的异步任务3 Async4 Schedule5 stream Parallel6 ForkJoinPool7 Transactional 除了Java自带默认线程池&#xff0c;…

mac本地搭建docker+k8s步骤

概览&#xff1a; * kubectl安装 * minikube安装 * dashboard安装 主机配置&#xff1a; * mac M2 &#xff08;arm架构&#xff09; 服务及版本概览&#xff1a; 服务名称版本 kubectl v1.29.2 Kubernetes v1.30.0 kicbase v0.0.44 dashboard v2.7.0 docker 26.…

Linux:进程概念

文章目录 进程概念1、冯诺依曼体系结构2、进程2.1基本概念2.2描述进程-PCB2.3组织进程2.4查看进程2.5通过系统调用获取进程标识符2.6通过系统调用创建进程-fork初识 进程概念 1、冯诺依曼体系结构 目前我们认识的计算机中&#xff0c;都是由一个个硬件构成 输入单元&#xff1…

c语言基础-------指针变量作为函数参数

指针变量作为函数参数 在 C 语言中&#xff0c;指针变量作为函数参数是一种常见的做法&#xff0c;它允许函数修改通过指针传递的变量。这是通过指针的地址传递实现的&#xff0c;而不是通过值传递。 指针作为函数参数的优点 修改原始数据&#xff1a;当函数接受一个指针作…

经典游戏,用java实现的坦克大战小游戏

今天给大家分享一个使用java编写的坦克大战小游戏&#xff0c;整体还是挺好玩的&#xff0c;通过对这款游戏的简单实现&#xff0c;加深对java基础的深刻理解。 一、设计思路 1.坦克大战小游戏通过java实现&#xff0c;其第一步需要先绘制每一关对应的地图&#xff0c;地图包括…

机器学习(5)--正则化之L1和L2正则化

文章目录 正则化一、正则化的基本原理二、L1正则化&#xff08;Lasso&#xff09;三、L2正则化&#xff08;Ridge&#xff09;四、L1与L2正则化的比较 总结 正则化 正则化是一种在机器学习和深度学习中常用的技术手段&#xff0c;旨在提高模型的泛化能力&#xff0c;减少过拟合…

深入探讨C语言中的高级指针操作

目录 指针与内存管理的高级技巧 1. 动态数组的重新分配 2. 内存碎片化的处理 3. 内存对齐 函数指针数组与回调函数的高级用法 1. 基本函数指针用法 2. 函数指针数组 3. 回调函数的使用 指针与数据结构的结合 1. 自定义链表 C语言以其强大的底层操作能力和高效的性能著…

【信创】Linux下EFI引导配置工具efibootmgr _ 统信 _ 麒麟 _ 方德

往期好文&#xff1a;deepin V23 Release 安装与功能介绍&#xff01;&#xff01;&#xff01; Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在信创操作系统上使用EFI引导管理器配置工具efibootmgr命令详解的文章。efibootmgr是一个在基于UEFI的系统中管理EF…

AI数字员工技能全开,招生、培训、写教案,样样都行

只需要几个AI数字员工&#xff0c;就可以协助您办一所高质量的学校。 教务管理、教师培训、招生咨询、家校沟通、学生评价、资料整理、学习伴侣、写教案、总结、学生评语等。 这些都可以用AI数字员工来完成。 比如&#xff0c;AI培训专员给教师做制度培训、教学培训&#xf…

裴蜀定理相关结论

裴蜀定理: axbygcd(a,b) 必定有解 1. 有无限个数凑不出来 有无限个数凑不出来 2. 最大凑不出的数字 在 的条件下&#xff0c;最大凑不出的数为 推广&#xff1a;若数字数目大于2&#xff0c;gcd仍然为1&#xff0c;最大凑不出来的数字一定小于上面的结论值&#xff0c;即局…

计算机网络——TCP协议与UDP协议详解(上)

一、前言 1.1 再次理解传输层 传输层是计算机网络中的一层&#xff0c;位于网络层和应用层之间。它主要负责在网络中的两个端系统之间提供可靠的、端到端的数据传输服务。简单理解&#xff0c;传输层就是负责在源主机和目标主机之间提供端到端的数据传输。 传输层的两个主要协…

EasyRecovery 16/17数据恢复软件2024最新永久破解版激活码注册码分享

EasyRecovery &#xff08;易恢复中国&#xff09;是由全球著名数据厂商Ontrack 出品的一款数据文件恢复软件。支持恢复不同存储介质数据&#xff1a;硬盘、光盘、U盘/移动硬盘、数码相机、Raid文件恢复等&#xff0c;能恢复包括文档、表格、图片、音视频等各种文件。 开发背…

鸿蒙开发5.0【基于ArkUI的验证码】实现

场景描述 场景一&#xff1a;基于自定义键盘的验证码实现&#xff0c;进入页面后直接输入验证码&#xff0c;第一个验证码输入完后可自动跳到下一个&#xff0c;拉起的键盘是自定义数字键盘&#xff0c;验证码的输入框带选中效果。 场景二&#xff1a;基于系统键盘的验证码实…

顶顶通呼叫中心中间件-一句话识别语音识别安装步骤

顶顶通呼叫中心中间件-一句话模型安装步骤&#xff0c;对接mod_vad。一句话识别&#xff08;http接口提交录音文件识别&#xff09; 一、安装一句话模型 一句话识别&#xff08;http接口提交录音文件识别&#xff09;&#xff0c;比如对接mod_vad(老电话机器人接口) curl -s…

C#中的多线程案例

使用Task写一个进度条 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.For…

【有手就行】:从无到有在win10上用docker搭建svn服务器

前言 之所以要搭建svn服务器&#xff0c;是因为在用docker打包项目时方便&#xff0c;如果没有svn就需要手动拷贝项目到容器内&#xff0c;用svn直接update就可以轻松拿到最新代码&#xff0c;岂不快哉 准备工作 1、先安装docker&#xff0c;请移步 docker安装 2、选择svn-s…