在数据可视化领域,ECharts 以其强大的功能和灵活的配置选项,成为了众多开发者的首选。然而,在实际开发过程中,我们经常会遇到图表需要根据窗口或容器大小自动调整尺寸的需求,自适应其实是很容易实现,并且有多种方式可以实现。但为了便于统一,避免后续项目中重新造轮子,于是(造了个轮子)开发了 echarts-adaptive-plugin 插件。
本文将详细介绍该插件的开发过程,包括技术栈、架构、功能实现、测试、发布插件和部署文档等方面,来帮助新手开发者入门新手开发类似的模块的流程与方法。
先看预览效果,可以拖拽灰色边框容器的右下角来改变容器大小,ECharts 图标会根据灰色边框容器的大小变化自适应变化。
项目概述
echarts-adaptive-plugin 是一个为 ECharts 图表提供自适应功能的插件。它可以监听一个元素的大小变化,并自动调整 ECharts 图表的大小,以确保图表在不同设备和屏幕尺寸下都能正常显示。
技术栈
- TypeScript: 提供了类型检查,增强了代码的可读性和可维护性。
- Rollup: 用于打包库,支持输出多种格式的模块。
- Vitest: 用于单元测试,保证代码质量。
- VitePress: 用于构建项目文档,提供了丰富的配置选项和主题支持。
架构
项目采用了 monorepo 架构,以便更好地管理项目中的多个包(其实就一个)
Monorepo 是一种项目管理策略,它允许将多个相关联的代码库存储在同一个仓库中,而不是分散在多个仓库中。这种架构有几个显著的优点:
- 统一的依赖管理:所有的包共享同一个
node_modules
目录,便于统一管理依赖版本,减少依赖冗余。 - 简化的跨包协作:在同一个仓库中开发多个包,可以轻松地进行跨包修改和测试,无需频繁地同步和发布中间版本。
- 统一的构建和测试流程:可以使用单一的命令来构建和测试仓库中的所有包,简化了持续集成的配置。
在 echarts-adaptive-plugin 项目中,我们使用了 npm 的 workspaces
功能来实现 monorepo 架构。通过在 package.json
中定义 workspaces
字段,npm 可以自动处理多个包之间的依赖关系,并优化安装过程。
{
"workspaces": [
"packages/*"
]
}
这种架构使得项目的扩展和维护变得更加容易,特别是对于可能包含多个相关插件或工具的项目。
实现
在实现上,echartsAdaptive
方法首先创建一个 ResizeObserver
实例来监听 monitorContent
元素的大小变化。当检测到大小变化时,使用ECharts 实例的 resize 方法来重新调整 ECharts 图表的大小。
因为 resize 方法是可以传递参数进行进一步配置的,所以又增加了一个处理函数 handle
,它会传递监听大小变化时的 echartsInstance
和 monitorContent
,当你需要某些额外的自定义处理时可以用到,然后你可以返回自定义的调整参数用于 Echarts
的 resize
方法。handle
能够进一步增强这个自适应插件的灵活性。目前只是基于我开发过程中碰到的场景进行的扩展,如果有额外需求,有兴趣动手的同学可以提交 issue 或者 pr。
import * as echarts from 'echarts';
interface EchartsAdaptiveOptions {
echartsInstance: echarts.ECharts;
monitorContent: HTMLElement;
handle?: (options: {
echartsInstance: echarts.ECharts;
monitorContent: HTMLElement;
}) => object;
}
export const echartsAdaptive = ({
echartsInstance,
monitorContent,
handle
}: EchartsAdaptiveOptions) => {
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
// 当 monitorContent 大小变化时
if (entry.target === monitorContent) {
// 获取自定义调整参数
const options = handle
? handle({ echartsInstance, monitorContent })
: {};
// 通过 ECharts 实例的 resize 方法来重新调整 ECharts 图表的大小
echartsInstance.resize({ ...options });
}
}
});
// 开始监听 monitorContent 的大小变化
resizeObserver.observe(monitorContent);
// 返回一个函数,用于销毁监听
return () => {
resizeObserver.unobserve(monitorContent);
};
};
关于 handle
的使用示例。
const tableData=ref<any{}>([])
const destroyAdaptive = echartsAdaptive({
echartsInstance,
monitorContent: document.getElementById('your-chart-container'),
handle: ({ echartsInstance, monitorContent }) => {
console.log(echartsInstance, monitorContent)
return {
// 比如我需要根据 tableData 是否有数据调整 Echart 的宽度。
width: monitorContent.offsetWidth / (this.tableData.length ? 2 : 1)
height: '300px' // 固定高度为300px
};
}
});
测试
项目使用 Vitest 进行单元测试。测试代码位于 packages/echarts-adaptive-plugin/test/index.test.ts,通过模拟 ECharts 实例和容器大小变化,验证自适应功能的正确性。
import * as echarts from 'echarts';
import { describe, expect, it, vi } from 'vitest';
import { echartsAdaptive } from '../src/index';
describe('echartsAdaptive', () => {
it('should call resize on echarts instance with custom options when monitorContent size changes and handle is provided', async () => {
const mockEchartsInstance = {
resize: vi.fn()
};
const monitorContent = document.createElement('div');
const customOptions = { width: 'auto', height: 'auto' };
const destroyAdaptive = echartsAdaptive({
echartsInstance: mockEchartsInstance as unknown as echarts.ECharts,
monitorContent,
handle: () => customOptions
});
// 模拟 monitorContent 大小变化
monitorContent.dispatchEvent(new Event('resize'));
// 确保 echartsInstance 的 resize 方法被调用,并传入了自定义选项
expect(mockEchartsInstance.resize).toHaveBeenCalledWith(customOptions);
// 清理
destroyAdaptive();
});
});
describe('echartsAdaptive', () => {
it('should call resize on echarts instance with empty options when monitorContent size changes and handle is not provided', async () => {
const mockEchartsInstance = {
resize: vi.fn()
};
const monitorContent = document.createElement('div');
// 创建一个 ResizeObserver 来模拟 monitorContent 大小变化的监听
global.ResizeObserver = class ResizeObserver {
callback: ResizeObserverCallback;
elements: Element[] = [];
constructor(callback: ResizeObserverCallback) {
this.callback = callback;
}
observe(target: Element) {
this.elements.push(target);
// 立即触发回调以模拟观察效果,这里可以根据需要调整
this.callback([{ target } as ResizeObserverEntry], this);
}
unobserve(target: Element) {
this.elements = this.elements.filter((element) => element !== target);
}
disconnect() {
this.elements = [];
}
};
const destroyAdaptive = echartsAdaptive({
echartsInstance: mockEchartsInstance as unknown as echarts.ECharts,
monitorContent
});
// 确保 echartsInstance 的 resize 方法被调用,并传入了空对象
expect(mockEchartsInstance.resize).toHaveBeenCalledWith({});
// 清理
destroyAdaptive();
});
});
发布插件
发布插件大概分为以下几个步骤
- 准备工作:确保项目符合发布到 NPM 的要求。
- 编写代码:开发你的插件功能。
- 编写文档:为你的插件编写 README.md 和其他文档。
- 测试:确保你的代码通过所有测试。
- 构建:构建你的项目,准备发布。
- 发布:将你的项目发布到 NPM。
准备工作
在发布之前,确保你的 package.json
文件已经正确配置。这包括项目名称、版本、描述、作者等信息。
确保你的项目名称是唯一的,版本号遵循 语义化版本控制。
编写代码
开发你的插件功能,确保代码清晰、可维护。echarts-adaptive-plugin
的主要功能是监听元素的大小变化,并自动调整 ECharts 图表的大小。
编写文档
为你的插件编写清晰的文档是非常重要的。这包括一个 README.md
文件,其中应该包含安装指南、使用示例、API 文档等。例如:
# echarts-adaptive-plugin
这是一个为 ECharts 图表提供自适应功能的插件。
## 安装
使用 npm 安装:
npm install echarts-adaptive-plugin
...
## 使用方法
...
测试
使用测试框架(如 vitest
)编写测试用例,确保你的代码按预期工作。echarts-adaptive-plugin
使用的是 vitest
进行测试。
构建
使用构建工具(如 rollup
)打包你的项目。echarts-adaptive-plugin
的 rollup
配置如下:
import terser from '@rollup/plugin-terser';
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/index.ts',
output: [
{
file: 'lib/index.js',
format: 'esm',
sourcemap: true
},
{
name: 'echartsAdaptivePlugin',
file: 'lib/echarts-adaptive-plugin.min.js',
format: 'iife'
}
],
plugins: [typescript(), terser()]
};
发布
在发布之前,需要确认你目前的 NPM 源是否是 NPM 官方源,因为很多时候,大家都会使用其他源来加速下载。如果不是官方源需要切换过去,对于切换 NPM 源的过程,我通常会使用 NRM 这个工具来协助,不做过多阐述,有兴趣可以自行查找。关于 NPM 源,你也可以在 packages.json
中增加发布配置。
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
另外,需要确认你已经登录到 NPM。使用以下命令登录:
npm login
然后,在项目根目录下运行以下命令发布你的项目:
npm publish
对于 echarts-adaptive-plugin
,你可以通过在 package.json
中配置的 release
脚本来发布:
{
...
"scripts": {
"release": "npm run readme && release-it"
},
...
}
这将自动处理版本控制、打包和发布到 NPM 的过程。因为 NPM 访问不稳定,没有 🪜 的同学如果遇到发布不成功,可以多试几次,偶尔会成功,实在不行只能寻求更稳定的网络访问了,这里就不展开讲解了。
部署文档
项目文档使用 VitePress 构建,在 vitepress 的使用中用到了我开发的另一个辅助 vitepress
使用的插件 vitepress-helper,可以开箱即用,在保持原扩展性的同时,精简了初始配置的过程。
文档通过 GitHub Actions 自动部署到 GitHub Pages。部署流程配置在 .github/workflows/publish.yml
中,这个工作流将在每次推送到 master 分支时触发,自动安装依赖、构建文档,并将构建的静态文件部署到 GitHub Pages。
name: Build and Deploy
on:
push:
branches:
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18]
steps:
- name: Checkout ️
uses: actions/checkout@v3
- name: Package Build
run: |
npm i
npm run build-docs
env:
NODE_OPTIONS: '--max_old_space_size=4096'
- name: Deploy to GitHub Pages
uses: crazy-max/ghaction-github-pages@v2
# 环境变量
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# 部署到 gh-pages 分支
target_branch: gh-pages
# 部署目录为 vitepress 的默认输出目录
build_dir: docs/.vitepress/dist
工作流可能没有权限执行相关操作,需要手动修改设置。在项目的 settings > actions > Workflow permissions
中勾选 Allow GitHub Actions to create and approve pull requests
选项。
工作流执行成功后,会生成一个新的分支 gh-pages
。在你的 GitHub 仓库设置中,找到 “Pages” 部分,选择 gh-pages 分支作为你的发布源。
等待 github 的处理完成,就可以看到文档已经部署成功了。huyikai.github.io/echarts-ada…
结语
虽然这只是一个很简单的插件,但是通过开发 echarts-adaptive-plugin
插件,我不仅解决了 ECharts 图表自适应的需求,也探索了一套关于插件的开发、测试和部署流程。希望这篇内容也能够帮助你理解该插件的设计和实现,学习到插件开发发布的流程。上手开发自己的插件项目。
如果你觉得内容还不错请帮忙点个赞和start,十分感谢❤️
Github:echarts-adaptive-plugin
原文链接:https://juejin.cn/post/7346798518361686079 作者:Tigger