AntVF2 图表使用

一,安装

安装 3.x 版本,这是使用下载量最高的版本

"@antv/f2": "3.8.13"

5.x 版本使用 jsx ,vue3不兼容需要安装一写插件,但是没好用,放弃。
4.x 版本提示theme 没有,不好用放弃。
建议使用 3.8.13 版本,发现这个版本下载量是最高的。

二,使用手册

1,vue引用

// 必须写高
<canvas ref="chartContainer" style="height: 200"></canvas>

import * as F2 from '@antv/f2'

const chartData = [
    {
        "subProjectKey": "BPDIA",
        "dataValue": "69.00",
        "startTime": "2025-03-10"
    },
    {
        "subProjectKey": "BPDIA",
        "dataValue": "95.00",
        "startTime": "2025-03-11"
    },
    {
        "subProjectKey": "BPDIA",
        "dataValue": "10.00",
        "startTime": "2025-03-12"
    },
    {
        "subProjectKey": "BPSYS",
        "dataValue": "136.00",
        "startTime": "2025-03-10"
    },
    {
        "subProjectKey": "BPSYS",
        "dataValue": "100.00",
        "startTime": "2025-03-11"
    },
    {
        "subProjectKey": "BPSYS",
        "dataValue": "10.00",
        "startTime": "2025-03-12"
    }
]
onMounted(()=> {
    const chart = new F2.Chart({
      el: chartContainer.value,
      pixelRatio: window.devicePixelRatio
    })
    // 正常绘制图表
    chart.source(chartData.value)
    chart
      .line()
      .position(`${chartData.value.startTime}*${chartData.value.dataValue}`)
      .shape('smooth')  // 平滑曲线
    chart.render()
})

2,标题

// 左侧标题
chart.guide().text({
  position: ['min', 'max'],
  content: '血压',
  style: {
    fill: '#8f8f8f',
    fontSize: 12,
    textAlign: 'left'
  },
  offsetX: -40,
  offsetY: -20
})

3,图例是否显示

const legend: any = props.legend
    ? {
        position: 'bottom'  // 显示位置,top、left、right、bottom
      }
    : false
  chart.legend(legend)
image.png

4,x、y 轴是否显示

  • 显示
chart.axis(props.labelInfo.xName, {
    label: {
      rotate: -45, // 旋转角度(负值为顺时针,正值为逆时针)
      fill: '#8f8f8f', // 标签颜色
      textAlign: 'end' // 标签对齐方式
      textBaseline: 'middle', // 文本基线对齐方式
      // offset: 2, // 标签偏移
    },
    line: {
      stroke: '#dfdfdf' // 横轴线颜色
    },
    tickLine: {
      stroke: '#dfdfdf',
    }
  })
  chart.axis(props.labelInfo.yName, {
    label: {
      fill: '#8f8f8f' // 纵轴标签颜色
    }
  })
  • 不显示
chart.axis(props.labelInfo.yName, false)
chart.axis(props.labelInfo.xName, false)

// 或者隐藏 X 轴的刻度线和文字
chart.axis('x', {
  label: null, // 隐藏文字
  line: null,  // 隐藏轴线
  tickLine: null // 隐藏刻度线
});

5,坐标轴刻度显示

// 调整 x 横坐标显示
chart.scale(props.labelInfo.xName, {
    type: 'timeCat',  // 日期类型  cat: 分类类型
    mask: 'MM-DD',  // 日期格式
    // range: [0, 1], // 范围,不超过 1
    tickCount: 7  // 刻度
})
  
// y轴
chart.scale(props.labelInfo.yName, {
  type: 'linear'  // 线性类型
})
image.png

6,折线图

// 折线图
chart
  .line()
  .position(`${props.labelInfo.xName}*${props.labelInfo.yName}`)
  .shape('smooth') // 曲线类型:line、smooth、dash、dot
image.png

7,折线的点显示

// 折线点图
chart
  .point()
  .position(`${props.labelInfo.xName}*${props.labelInfo.yName}`)
  .color(props.labelInfo.type, setColors)
  .size(props.labelInfo.type, (type) => {
    if (chartData.value.filter((el) => el.subProjectKey === type).length === 1) {
      // 单个值时点大小
      return 2
    } else {
      // 折线上的点大小, 1 和折线一样大,这样折线上不会突出点
      return 1
    }
  })
  
// 折线图
chart
  .line()
  .position(`${props.labelInfo.xName}*${props.labelInfo.yName}`)
  .shape('smooth') // 曲线类型:line、smooth、dash、dot

多条数据,其中一条只有一个值时,如果只用line 是不显示的,需要用point,但是如果使用默认的point,折线上也会显示点,但是如果不想在折线上显示点,需要控制点的大小(size),当点的大小和线的大小一样大,则看不明显。

image.png
image.png

8,面积图

chart.area()
    .position(`${props.labelInfo.xName}*${props.labelInfo.yName}`)
    .color(props.labelInfo.type, setColors)
image.png

9,柱状图

chart.interval().position('x*y'); // 柱状图

10,echarts 边距调整

const chart = new F2.Chart({
    el: chartContainer.value,
    padding: [20, 5], // 默认auto
    pixelRatio: window.devicePixelRatio
  })
image.png

11,数据为空

数据为空时,Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'getXScale') 报错。
解决 如下:

<div v-if="chartData.length == 0" class="empty">
  <div v-if="titleShow" class="title">{{ props.title + '(' + props.unit + ')' }}</div>
  <div class="emptyText">暂无数据</div>
</div>
<canvas v-else ref="chartContainer"></canvas>


if (!chartData || chartData.length === 0) {
    console.log('暂无数据');
    return;
}
chart.source(chartData);
chart.render();

三,完整代码

<template>
  <div class="line" :style="canvasStyle">
    <div v-if="chartData.length == 0" class="empty">
      <div v-if="titleShow" class="title">{{ props.title + '(' + props.unit + ')' }}</div>
      <div class="emptyText">暂无数据</div>
    </div>
    <canvas v-else ref="chartContainer"></canvas>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import * as F2 from '@antv/f2'

interface Props {
  lineData: any[]
  labelInfo?: any
  title?: string
  unit?: string
  colors?: any
  titleShow?: boolean
  lineArea?: boolean
  yxShow?: boolean
  legend?: boolean
  height?: string | number
  rotate?: number
}

const props = withDefaults(defineProps<Props>(), {
  colors: () => ['#ff5828', '#235FFA', '#00CCBA'],
  labelInfo: {
    xName: 'startTime',
    yName: 'dataValue',
    type: 'subProjectKey'
  },
  title: '',
  unit: '',
  titleShow: true,
  lineArea: false,
  yxShow: true,
  legend: true,
  height: 200,
  rotate: 0
})

const chartData = computed(() => {
  initData()
  return props.lineData || []
})

const colorTypes = computed(() => {
  let lists = {}

  chartData.value.forEach((item: any) => {
    if (!lists[item[props.labelInfo.type]]) {
      lists[item[props.labelInfo.type]] = props.colors[Object.keys(lists).length]
    }
  })
  return lists
})

const canvasStyle = computed(() => {
  return {
    height: props.height + 'px'
  }
})

const chartContainer = ref<HTMLDivElement | null>(null)

const initData = () => {
  if (!chartContainer.value) return
  const chart = new F2.Chart({
    el: chartContainer.value,
    padding: props.yxShow ? 'auto' : [20, 5],
    pixelRatio: window.devicePixelRatio
  })

  if (props.titleShow) {
    // 左侧标题
    chart.guide().text({
      position: ['min', 'max'],
      content: props.title + (props.unit ? ` (${props.unit})` : ''),
      style: {
        fill: '#8f8f8f',
        fontSize: 12,
        textAlign: 'left'
      },
      offsetX: -40,
      offsetY: -20
    })
  }

  // 图例
  const legend: any = props.legend
    ? {
        position: 'bottom'
      }
    : false
  chart.legend(legend)
  // 无数据提示
  if (chartData.value.length > 0) {
    // x,y 轴是否显示
    if (props.yxShow) {
      chart.axis(props.labelInfo.xName, {
        label: {
          fill: '#8f8f8f', // 标签颜色
          textAlign: 'end' // 标签对齐方式
          // offset: 2, // 标签偏移
        },
        line: {
          stroke: '#dfdfdf' // 横轴线颜色
        }
      })
      chart.axis(props.labelInfo.yName, {
        label: {
          fill: '#8f8f8f' // 纵轴标签颜色
        }
      })
      // 调整横坐标显示
      chart.scale(props.labelInfo.xName, {
        type: 'timeCat',
        mask: 'MM-DD',
        // range: [0, 1],
        tickCount: 7
      })
    } else {
      chart.axis(props.labelInfo.xName, {
        label: {
          fill: '#8f8f8f', // 标签颜色
          // rotate: -45, // 旋转标签
          textAlign: 'center' // 标签对齐方式
        },
        line: {
          stroke: '#dfdfdf' // 横轴线颜色
        }
      })
      chart.axis(props.labelInfo.yName, false)
      // 调整横坐标显示
      chart.scale(props.labelInfo.xName, {
        type: 'timeCat',
        mask: 'MM-DD',
        tickCount: 3
      })
    }

    chart.scale(props.labelInfo.yName, {
      type: 'linear',
      nice: true
    })

    // 正常绘制图表
    chart.source(chartData.value)

    // 是否面积图
    if (props.lineArea) {
      chart.area().position(`${props.labelInfo.xName}*${props.labelInfo.yName}`).color(props.labelInfo.type, setColors)
    }

    // 折线点图
    chart
      .point()
      .position(`${props.labelInfo.xName}*${props.labelInfo.yName}`)
      .color(props.labelInfo.type, setColors)
      .size(props.labelInfo.type, (type) => {
        if (chartData.value.filter((el) => el.subProjectKey === type).length === 1) {
          // 单个值时点大小
          return 2
        } else {
          // 折线上的点大小, 1 和折线一样大,这样折线上不会突出点
          return 1
        }
      })

    // 折线图
    chart
      .line()
      .position(`${props.labelInfo.xName}*${props.labelInfo.yName}`)
      .color(props.labelInfo.type, setColors)
      .shape('smooth')
    chart.render()
  }
}

// 设置折现,点,面积颜色
const setColors = (type: string) => {
  return type != colorTypes.value ? colorTypes.value[type] : '#ff5828'
}

onMounted(() => {
  nextTick(() => {
    initData()
  })
})
</script>
<style lang="scss" scoped>
.line {
  width: 100%;

  canvas {
    width: 100%;
    height: 100%;
  }
  .empty {
    display: flex;
    align-items: center;
    width: 100%;
    height: 100%;
    position: relative;
    .title {
      position: absolute;
      top: 0;
      left: 0;
      color: #8f8f8f;
      @extend .font-size-12;
    }
  }
  .emptyText {
    text-align: center;
    height: 40px;
    width: 50%;
    margin: 0 auto;
    line-height: 40px;
    background: #f7f8fa;
    border-radius: 8px 8px 8px 8px;
    color: #8f8f8f;
    @extend .font-size-14;
  }
}
</style>
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容