🗡 剑走偏锋,开发 Echarts 调试工具!

638 阅读4分钟

前言

作者现在公司的业务有可视化大屏的项目,选用 echarts 开发,社区成熟案例多,自定义程度高,可以做出很多炫酷的效果,在开发中遇到一些问题和存在一些思考 🤔,开发了一款在线调试图表的工具 🔧

问题

  • 样式问题:在使用 echarts 的时候,常常会因为样式配置问题,需要在文件和浏览器之间来回修改,比如 UI 说 柱状图窄一点,散点图散点小一点或者自己需要调整表格的位置,想想这个过程都会觉得繁琐。
  • 数据问题:当我想看到某个数值在图表上的显示效果的时候,或者使用自己设定的数据在图表上展示的时候,常常会因为存在接口或者频繁的回到文件中修改感到繁琐,并且会动到代码结构,会有一点的风险。

思考

有没有一个可以实现不修改文件但又可以实现上述效果的工具呢? 针对于上述问题做一个问题拆解 👇

  • echarts 是作为一个实例存在的,它不会频繁创建,除非主动销毁它。
  • 我需要获取管理所有图表的图表配置项,在修改配置的时候通知到 echarts 进行更新
  • 为了实现更新 setOption 我们需要保存 echarst 的实例
  • 为了我们频繁操作或可以拿到我们想要的最终值然后拿去写入代码,需要记录配置的修改记录

解决

  • 创建一个专门展示调试 echarts 视图组件,里面包含有多少个图表,可以切换图表实现显示不同配置,类似tab的效果。
  • 创建一个全局的 eventBus 进行全局通信事件,创建一个存储echarts实例的全局实例类,那么我们在图表创建完成的时候将图表实例保存在实例类中,然后通过 eventBus 可以通知展示的视图,视图从全局类中获取 list 图表实例,进行遍历。
  • 遍历后,将每个图表实例的 option 传入展示 json 的组件中,那么就可以在线实时看到我们 option的结构。
  • 对于高自定的场景,我们希望用户可以进行编码,因此可以将图表实例传入到 new Function 中执行书写的代码
  • 对于修改记录,可以获取到用户修改的字段,然后存入一个全局的记录类中,然后通过全局的 eventBus 更新记录。

✨ React-echarts-json 登场

  • 易于学习和使用
  • 无侵入性
  • 依赖更新
  • 日志视图监控
  • 可视化调试 echarts 选项
  • React 编码调试
  • 支持多图表
  • 可以自定义组合视图

技术难点攻克

一、数据视图更新及时

展示视图组件是放在最外层的,子组件会先渲染,会存在发布完事件,订阅组件没渲染的情况,会导致展示视图获取不到全局存入的图表实例,因此我采用了 class + hook 的方式让这个class 具备了 effect 的功能,在hook 只渲染一次的前提下,在 emit 发布的时候进行缓存,尽管在发布的时候订阅组件没有渲染,但在订阅组件渲染完成的时候会主动的根据事件名获取缓存进行执行,让其具备 effect 的功能并且不会重复创建订阅事件,还让工具具备获取异步数据的功能进行实时更新。

二、如何进行在线编写,并且是 React 语法?

采用的是执行代码块的方式 new Function ,首先我们通过 monaco-editor 获取到用户输入的 code 字符串,然后通过 @babel/standalone 进行转换语法,然后再使用 acornparse 方法解析语法,再传入 new Function 执行。

为了支持 react 需要创建一个元素,调用 ReactDOM.render

const render = (
    Component: React.DOMElement<React.DOMAttributes<Element>, Element>
  ) => {
    ReactDOM.render(Component, document.getElementById('node'))
  }
  const getWrapperFunction = (code: string) => {
    try {
      const esCode = babelTransform(
        `
const App = ()=>{
  ${code}
  return <div></div>
}
render(<App />)`,
        { presets: ['es2015', 'react'] }
      ).codeconst ast = parse(esCode, {
        sourceType: 'module',
        ecmaVersion: 3,
      })
      return new Function(
        'React',
        'render',
        'require',
        'instance',
        generateJs(ast)
      )
    } catch ({ message }) {
      throw new Error(`${message}`)
    }
  }

结语

Github地址 大家 🌟🌟 多多支持!

下面为大家展示功能截图

iShot_2022-10-27_11.49.39.png

iShot_2022-10-27_11.49.49.png

iShot_2022-10-27_11.50.06.png