一,安装
安装 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>