关于开发 ECharts 自适应插件的全面指南

在数据可视化领域,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,它会传递监听大小变化时的 echartsInstancemonitorContent,当你需要某些额外的自定义处理时可以用到,然后你可以返回自定义的调整参数用于 Echartsresize 方法。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();
  });
});

发布插件

发布插件大概分为以下几个步骤

  1. 准备工作:确保项目符合发布到 NPM 的要求。
  2. 编写代码:开发你的插件功能。
  3. 编写文档:为你的插件编写 README.md 和其他文档。
  4. 测试:确保你的代码通过所有测试。
  5. 构建:构建你的项目,准备发布。
  6. 发布:将你的项目发布到 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-pluginrollup 配置如下:

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

(0)
上一篇 2024年3月17日 上午11:14
下一篇 2024年3月17日 下午4:05

相关推荐

发表回复

登录后才能评论