Taro Vue 小程序 使用ucharts

1、文档

具体使用方式参考官方文档
官方文档-指南 - uCharts 跨平台图表库

2、使用方式选择

uCharts 包含原生 canvas 和组件两种引用方式:
1、原生方式 uCharts 体积小巧(18 个类型的图表压缩后 130kb)性能强大、各端的表现一致, 跨平台兼容性好;
2、uCharts 组件是官方在原生 uCharts 的基础上进行的封装,把一些新手容易出问题的用法、各平台不一致特有的需要注意的地方做了优化。支持 uni-app 组件和原生小程序组件,小程序组件需要根据不同平台引入对应版本。
由于小程序目前使用 taro.js 框架, 以及考虑到后续会兼容支付宝小程序,我们这里采用原生 canvas 的引用方式。

3、Taro vue 组件封装

官方演示文档 Taro 版本为 React 版本,下面配置参考微信原生组件开启 2d 版本。为解决 ios canvas 兼容问题,需开启 canvas 2d,避免使用定位和 scroll-view。

<template>
  <view :id="'box-' + id" @tap="tap">
    <canvas
      :id="id"
      :canvas-id="id"
      :style="'width:' + width + 'rpx;height:' + height + 'rpx;'"
      type="2d"
      :disable-scroll="false"
    />
  </view>
</template>

<script>
import uCharts from "@qiun/ucharts/u-charts";
import Taro from "@tarojs/taro";
import &#123; mapState &#125; from "vuex";
const uChartsInstance = &#123;&#125;;
export default &#123;
  name: "Chart",
  props: &#123;
    width: &#123;
      type: Number,
      default: 750,
    &#125;,
    height: &#123;
      type: Number,
      default: 500,
    &#125;,
    id: &#123;
      type: String,
      default: "",
    &#125;,
    showTip: &#123;
      type: Function,
      default: function () &#123;&#125;,
    &#125;,
    option: &#123;
      type: Object,
      default() &#123;
        return &#123;&#125;;
      &#125;,
    &#125;,
  &#125;,
  data() &#123;
    return &#123;
      path: "",
      cWidth: 0,
      cHeight: 0,
    &#125;;
  &#125;,
  computed: &#123;
    ...mapState(&#123;
      systemInfo: (state) => state.base.systemInfo,
    &#125;),
  &#125;,
  watch: &#123;
    option: &#123;
      handler(newVal) &#123;
        if (newVal.series !== undefined && newVal.series.length > 0) &#123;
          this.updateCharts();
        &#125;
      &#125;,
      deep: true,
    &#125;,
  &#125;,
  created() &#123;
    if (this.id) &#123;
      this.cWidth =
        (this.width / 750) *
        this.systemInfo.windowWidth *
        this.systemInfo.pixelRatio;
      this.cHeight =
        (this.height / 750) *
        this.systemInfo.windowWidth *
        this.systemInfo.pixelRatio;
      Taro.nextTick(() => &#123;
        setTimeout(() => &#123;
          this.drawCharts();
        &#125;, 500);
      &#125;);
    &#125;
  &#125;,
  methods: &#123;
    drawCharts() &#123;
      // taro vue 版本不可加.in(this) 否者找不到
      // const query = wx.createSelectorQuery().in(this);
      const query = Taro.createSelectorQuery();
      query
        .select("#" + this.id)
        .fields(&#123; node: true, size: true &#125;)
        .exec((res) => &#123;
          if (res[0]) &#123;
            const canvas = res[0].node;
            const ctx = canvas.getContext("2d");
            canvas.width = res[0].width * this.systemInfo.pixelRatio;
            canvas.height = res[0].height * this.systemInfo.pixelRatio;
            uChartsInstance[this.id] = new uCharts(&#123;
              context: ctx,
              width: this.cWidth,
              height: this.cHeight,
              pixelRatio: this.systemInfo.pixelRatio,
              ...this.option,
            &#125;);
          &#125; else &#123;
            console.error("[uCharts]: 未获取到 context");
          &#125;
        &#125;);
    &#125;,
    updateCharts() &#123;
      uChartsInstance[this.id].updateData(&#123;
        ...this.option,
      &#125;);
    &#125;,
    // 获取点击item 索引
    getIndex(e) &#123;
      const dataIndex = uChartsInstance[this.id].getCurrentDataIndex(e);
      if (typeof dataIndex === "object") return dataIndex.index;
      else return dataIndex;
    &#125;,
    tap(e) &#123;
      e.changedTouches = [];
      // 计算点击 坐标
      e.changedTouches.unshift(&#123;
        x: e.detail.x - e.currentTarget.offsetLeft,
        y: e.detail.y - e.currentTarget.offsetTop,
      &#125;);
      let tipOption = &#123;&#125;;
      const origin = this.getIndex(e);
      // 自定义tip配置
      if (this.showTip && typeof this.showTip === "function") &#123;
        if (origin !== -1)
          tipOption = this.showTip(this.option.series, origin) || &#123;&#125;;
      &#125;
      uChartsInstance[this.id].touchLegend(e);
      uChartsInstance[this.id].showToolTip(e, tipOption);
      // 获取x轴  点击索引
      // e.changedTouches[0].y = e.changedTouches[0].y - 25
      // const xAxis = this.getIndex(e)
      // console.log(origin, xAxis)
      // if (origin === -1 && xAxis !== -1) &#123;
      //     this.$emit('getXAxisIndex', xAxis)
      // &#125;
    &#125;,
  &#125;,
&#125;;
</script>

4、问题解决

1、使用绝对定位导致,点击图表 tooltip 提示异常

.header &#123;
  position: fixed;
  width: 100%;
  top: 0;
  height: 176px;
&#125;
.main &#123;
  // main中包含图表组件, 若此处使用margin计算点击事件坐标 会出现偏差,偏差值为magrin-top 高度, 使用padding不会出现此问题。
  // margin:176px 0 96px
  padding: 176px 0 96px;
&#125;