跳到主要内容

画布 SVG 管理

更新时间 2025/02/05 08:08:31

画布 Web SDK 支持提供 SvgManager 来管理画布中使用的 svg 资源,主要原理是在 document.body 中添加 <svg> 标签,然后将每一个 svg 的内容放到 <symbol> 中,为每个 <symbol> 添加 id,然后在使用的时候使用 <use> 标签,可以重复利用 symbol 中的 svg 图标。

初始化加载

在页面加载完成后的时候可以执行统一加载,这会创建一个 svg container DOM,这个容器在当前项目全局只会创建一次,后续的所有操作都是基于这个容器,如果您不想创建容器,每个方法都支持传入自定义容器,保证是 svg 就可以。

import { SvgManager } from '@plaso-infi/whiteboard-sdk';

const ICON_PREFIX = 'default-';
const DEFAULT_ICON = {
[`${ICON_PREFIX}setting`]: `<g fill-rule="evenodd" fill="none"><path d="M0 0h24v24H0z"/><path data-follow-fill="currentColor" fill="currentColor" d="M4 4h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2Zm0 7h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2Zm0 7h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2Z"/></g>`,
[`${ICON_PREFIX}no-background`]: `<g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0z"/><path data-follow-fill="currentColor" d="M20.868 7.374A9.957 9.957 0 0 1 22 12c0 5.523-4.477 10-10 10a9.957 9.957 0 0 1-4.626-1.132l1.502-1.5c.96.407 2.016.632 3.124.632a8 8 0 0 0 7.367-11.124l1.501-1.502Zm-1.09-3.152a1 1 0 0 1 0 1.414L5.636 19.778a1 1 0 1 1-1.414-1.414L18.364 4.222a1 1 0 0 1 1.414 0ZM12 2a9.96 9.96 0 0 1 4.626 1.132l-1.502 1.5A8 8 0 0 0 4.633 15.124l-1.501 1.503A9.957 9.957 0 0 1 2 12C2 6.477 6.477 2 12 2Z" fill="currentColor" fill-rule="nonzero"/></g>`,
};

useEffect(() => {
SvgManager.load(DEFAULT_ICON);
}, []);

执行完后 svg container 下面会挂载所有的 svg 资源到 svg container 的 <symbol> 并增加相应的 id,如果您不想增加一个 svg container 可以直接使用 add 方法。

关于 prefix ,这个没有强制规定都是由外部自己定,但是一定要保证传入的 Map 的 key 值,一定要和使用 use 的时候传入 id 的值保持一致!

使用

在 React 环境中封装一个组件,来做 <use>

<SvgIcon icon={`${prefix}setting`} className={styles.icon} onClick={onSettingBtnClick} />

SvgIcon 这个组件已经从 Web SDK 导出,可以直接使用

import React from 'react';
import { classnames } from '@/utils';
import styles from './index.module.less';

type PropT = {
className?: string;
style?: React.CSSProperties;
title?: string;
icon: string;
onClick?: any;
[key: string]: any;
};

export const SvgIcon: React.FC<PropT> = ({ className, style, title, icon, onClick, ...rest }) => {
return (
<svg
style={style}
className={classnames(className, styles.icon)}
aria-hidden='true'
onClick={onClick}
{...rest}
>
<use xlinkHref={`#${icon}`}>
<title>{title || ''}</title>
</use>
</svg>
);
};

通过 <use> 标签上的 xlinkHref 属性可以全局查找 <symbol> 与之对应的那个 svg 图标。

在其他框架可以根据这段代码封装相应的组件来做渲染,原生 HTML 环境则可以直接使用

<svg
aria-hidden="true"
onClick={onClick}
>
<use xlinkHref='#upload'>
<title>上传</title>
</use>
</svg>

API

注意:所有 API 需要传入的 icons 都是一个对象,对象的 key 是生成 <symbol id='upload'> 的时候的 id 值,也是使用的时候 <use xlinkHref='#upload'> 的 xlinkHref 值;对象的 value 是去掉 <svg> 标签后剩余的内容部分!

可以随时在运行时做添加、替换操作实时生效,每个 API 都支持传入自定义的 SVG 资源容器,如果不传则根据 API 的不同区寻找或者创建容器。

interface Icon {
[key: string]: string;
}

add

批量添加 svg 资源,如果在当前 svgContainer 发现有 id 相等的 <symbol> 内容会被替换,如果不想被替换可以考虑增加 prefix,如果想要全局替换请使用 replace 方法。

定义
  /**
* @param icons svg 的id和内容的map
* @param svgContainer 想要查找替换的svg symbol容器,如果没有传尝试寻找 id 为 plaso-websdk-svg-container 的容器,如果没有找到会 使用 plaso-websdk-svg-container 为 id 创建
*/
add(icons: Icon, svgContainer?: SVGElement)
示例
SvgManager.add({
['setting']: `<g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0z"/><path data-follow-fill="currentColor" d="M19.062 5.9a1 1 0 1 1 1.533 1.284l-9.481 11.163a1 1 0 0 1-1.39.14l-5.872-4.924A1 1 0 1 1 5.101 12l5.106 4.313 8.855-10.414Z" fill="currentColor" fill-rule="nonzero"/></g>`,
});

replace

在运行时替换任何一个 svg 的内容,如果没有传第二个参数,会检索 document.body一级 DOM 中拥有 firstChild 为 <symbol><svg>, 然后遍历这些 SVG 容器,替换掉所有能找到的 id 相等的 <symbol>

注意 replace 中的 id 如果在当前环境的 DOM 上没有被检索到不会做添加操作,添加请使用 add 方法

定义
  /**
* @param icons svg 的id和内容的map
* @param svgContainer 想要查找替换的svg symbol容器
*/
replace(icons: Icon, svgContainer?: SVGElement)
示例
SvgManager.replace({
['download']: `<g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0z"/><path data-follow-fill="currentColor" d="M19.062 5.9a1 1 0 1 1 1.533 1.284l-9.481 11.163a1 1 0 0 1-1.39.14l-5.872-4.924A1 1 0 1 1 5.101 12l5.106 4.313 8.855-10.414Z" fill="currentColor" fill-rule="nonzero"/></g>`,
});