taro + 支付宝小程序 + F2 4.x 图表

428 阅读1分钟

F2官网

1.安装依赖

npm i @antv/f2 --save
# 微信小程序
npm i @antv/f2-my --save

2.拷贝组件

将node_modules里面的(@antv/f2-my),拷贝出来,到src/components下面。
然后,在 app.config.js 里面,全局引入小程序组件
或者在单独的页面里引用

usingComponents: {
    f2: '@/components/f2-my/es/index',
},

修改src/components/f2-my/es/index.js里面的onRenderrender,同时改为非函数

  props: {
    render: '',
    // width height 会作为元素兜底的宽高使用
    width: null,
    height: null,
    type: '2d', // canvas 2d, 基础库 2.7 以上支持
  },

  /**
   * 组件创建时触发
   * 注意:
   *    使用该生命周期,项目配置需启用:"component2": true
   */
  onInit: function onInit() {
    this.setCanvasId();
  },
  didMount: function didMount() {
    var _this = this;

    if (isAppX2CanvasEnv()) {
      return;
    }

    var id = this.data.id;
    var query = my.createSelectorQuery({
      page: this.$page,
    });
    query
      .select('#'.concat(id))
      .boundingClientRect()
      .exec(function (res) {
        // 获取画布实际宽高, 用props的宽高做失败兜底
        var _ref = res && res[0] ? res[0] : _this.props,
          width = _ref.width,
          height = _ref.height;

        var pixelRatio = getPixelRatio(); // 高清解决方案

        _this.setData(
          {
            width: width * pixelRatio,
            height: height * pixelRatio,
          },
          function () {
            var myCtx = my.createCanvasContext(id);
            var context = F2Context(myCtx);

            _this.canvasRender({
              width: width,
              height: height,
              context: context,
              pixelRatio: pixelRatio,
            });
          }
        );
      });
  },
  didUpdate: function didUpdate() {
    var canvas = this.canvas,
      props = this.props;
    if (!canvas) return;
    var children = props.render;
    canvas.update({
      children: children,
    });
  },
  didUnmount: function didUnmount() {
    var canvas = this.canvas;
    if (!canvas) return;
    canvas.destroy();
  },
  methods: {
    setCanvasId: function setCanvasId() {
      var pageId = (this.$page && this.$page.$id) || 0;
      var id = 'f2-canvas-'.concat(pageId, '-').concat(this.$id);
      this.setData({
        id: id,
      });
    },
    onCanvasReady: function onCanvasReady() {
      var _this2 = this;

      var id = this.data.id;
      var query = my.createSelectorQuery();
      query
        .select('#'.concat(id)) // @ts-ignore
        .node()
        .exec(function (res) {
          if (!res[0]) {
            return;
          }

          var canvas = res[0].node;
          var width = canvas.width,
            height = canvas.height;
          var pixelRatio = getPixelRatio();
          canvas.width = width * pixelRatio;
          canvas.height = height * pixelRatio;
          var context = canvas.getContext('2d');

          _this2.canvasRender({
            width: width,
            height: height,
            pixelRatio: pixelRatio,
            context: context,
          });
        });
    },
    canvasRender: function canvasRender(_ref2) {
      var width = _ref2.width,
        height = _ref2.height,
        pixelRatio = _ref2.pixelRatio,
        context = _ref2.context;

      if (!width || !height) {
        return;
      }

      var children = this.props.render;
      var canvas = new Canvas({
        pixelRatio: pixelRatio,
        width: width,
        height: height,
        context: context,
        children: children,
      });
      canvas.render();
      this.canvas = canvas;
      this.canvasEl = canvas.canvas.get('el');
    },
    click: function click(e) {
      var canvasEl = this.canvasEl;

      if (!canvasEl) {
        return;
      }

      var event = wrapEvent(e);
      var detail = e.detail,
        target = e.target;
      var x = detail.x,
        y = detail.y;
      var _target$offsetLeft = target.offsetLeft,
        offsetLeft = _target$offsetLeft === void 0 ? 0 : _target$offsetLeft,
        _target$offsetTop = target.offsetTop,
        offsetTop = _target$offsetTop === void 0 ? 0 : _target$offsetTop; // 包装成 touch 对象

      event.touches = [
        {
          x: x - offsetLeft,
          y: y - offsetTop,
        },
      ];
      canvasEl.dispatchEvent('click', event);
    },
    touchStart: function touchStart(e) {
      var canvasEl = this.canvasEl;

      if (!canvasEl) {
        return;
      }

      canvasEl.dispatchEvent('touchstart', wrapEvent(e));
    },
    touchMove: function touchMove(e) {
      var canvasEl = this.canvasEl;

      if (!canvasEl) {
        return;
      }

      canvasEl.dispatchEvent('touchmove', wrapEvent(e));
    },
    touchEnd: function touchEnd(e) {
      var canvasEl = this.canvasEl;

      if (!canvasEl) {
        return;
      }

      canvasEl.dispatchEvent('touchend', wrapEvent(e));
    },
  },
});

3.编写图表组件

新建文件 chart-box.jsx 写一个 雷达图,如下:

import { Chart, Point, Line, Area, Axis, Legend } from '@antv/f2';

const ChartBox = props => {
  const { data } = props;
  return (
    <Chart
      data={data}
      coord='polar'
      scale={{
        score: {
          min: 0,
          max: 100,
          nice: false,
          tickCount: 5,
        },
      }}
    >
      <Axis field='item' />
      <Axis field='score' />
      <Line x='item' y='score' color='#43A5F3' />
      <Area x='item' y='score' color='user' />
      <Point x='item' y='score' color='#43A5F3' />
      <Legend />
    </Chart>
  );
};

export default ChartBox;

4.引用

import { View, Text, Image } from '@tarojs/components';
import { useState, useEffect } from 'react';
import ChartBox from './chart-box';
import './index.less';

const data = [
  {
    item: '准确度',
    user: '用户 A',
    score: 70,
  },
  {
    item: '语调',
    user: '用户 A',
    score: 60,
  },

  {
    item: '流利度',
    user: '用户 A',
    score: 50,
  },
  {
    item: '完整度',
    user: '用户 A',
    score: 40,
  },
];

const RadarChart = () => {
  return (
    <View class='chart-container'>
      <f2 render={<ChartBox data={data} />}></f2>
    </View>
  );
};

export default RadarChart;