Skip to content

ECharts 完整集成

从注入 echarts 到让用户在属性面板配 chartType / xAxis / series 的完整链路。


1. 宿主注入

ts
import * as echarts from 'echarts'
import { createHyperCard } from '@hy-bricks/core'

app.use(createHyperCard({
  libs: { echarts },
}))

详细 libs 注入:/guide/quick-start


2. 组件源码完整三栏

HTML:

html
<div ref="el" style="width:100%; height:100%"></div>

JS:

js
export default {
  name: { value: 'MyECharts', CN: 'ECharts 图表' },

  attribute: {
    chartType: '图表类型 line/bar/pie',
    title: '标题',
    xAxisData: 'x 轴数据(逗号分隔)',
  },

  custom: {
    seriesData: {
      label: '系列数据',
      dataInput: true,                  // ★ 可被 binding 灌入
      value: [],
    },
  },

  data() {
    return { chart: null }
  },

  methods: {
    mounted() {
      const echarts = __HYPERCARD__.libs.echarts
      this.chart = echarts.init(this.$refs.el)
      this.applyOption()

      // 监听 attribute 变化
      this.$watch(() => this.chartType, () => this.applyOption())
      this.$watch(() => this.title, () => this.applyOption())
      this.$watch(() => this.xAxisData, () => this.applyOption())

      // 监听 custom.seriesData(binding 灌入)
      this.$watch(() => this.custom.seriesData.value, () => this.applyOption())

      // resize
      this._resizeObs = new ResizeObserver(() => this.chart?.resize())
      this._resizeObs.observe(this.$refs.el)
    },

    beforeUnmount() {
      this._resizeObs?.disconnect()
      this.chart?.dispose()
    },

    applyOption() {
      const xData = (this.xAxisData ?? '').split(',').map(s => s.trim())
      this.chart?.setOption({
        title: { text: this.title ?? '' },
        xAxis: { type: 'category', data: xData },
        yAxis: { type: 'value' },
        series: [{
          type: this.chartType ?? 'line',
          data: this.custom.seriesData.value,
        }],
      })
    },
  },
}

CSS:

css
.root { width: 100%; height: 100%; }

3. 用户在画布看到什么

Step 1:拖入组件

用户从 palette 拖 "ECharts 图表" 到画布,SDK addInstance 创建实例,默认布局 fill。

Step 2:属性面板出现 4 项

宿主属性面板按 attribute + custom 渲染表单:

基础属性
├─ chartType        [line ▼]
├─ title            [我的图表]
├─ xAxisData        [一月,二月,三月]
└─ seriesData(数据源)  [绑定...]   ← custom.dataInput=true 显示绑定按钮

Step 3:用户改 chartType

属性面板 select 切到 barinstance.props.chartType = 'bar' → Vue reactivity → $watch 触发 → applyOption() 重画。

Step 4:用户绑数据源

seriesData(数据源) → 选择已注册 dataSource → 写 PageDocument.bindings:

ts
{
  id: 'b1',
  source: { kind: 'dataSource', sourceId: 'sales-2024' },
  target: { kind: 'instanceDataInput', instanceId: '<chart-id>', key: 'seriesData' },
}

运行时 SDK wire binding → fetch dataSource → setDataInput('seriesData', data) → 组件 $watch 触发 → 重画。


4. 完整 DataAdapter 接入

ts
import type { DataAdapter } from '@hy-bricks/canvas'

const dataAdapter: DataAdapter = {
  async query({ sourceId, params }) {
    const data = await fetch(`/api/data/${sourceId}`).then(r => r.json())
    return { status: 'ok', data }
  },
  subscribe() { return () => {} },
}

<HyperCardPageRenderer
  :payload="payload"
  :adapters="{ data: dataAdapter }"
  canvas-id="dashboard"
/>

5. 常见坑

现象原因
组件挂载但 echarts 没出.rootwidth:100%; height:100%,echarts canvas 0×0
改 attribute 组件不响应没在 mounted 里 $watch 那个字段
binding 灌不进custom.seriesData.dataInput: true 没声明 → console.warn + no-op
切窗口大小 echarts 没 resize没用 ResizeObserver / chart.resize()
浏览器 console 报 echarts is undefined宿主没 createHyperCard({ libs: { echarts } })