一,安裝
安裝 3.x 版本,這是使用下載量最高的版本
"@antv/f2": "3.8.13"
5.x 版本使用 jsx ,vue3不兼容需要安裝一寫插件,但是沒好用,放棄。
4.x 版本提示theme 沒有,不好用放棄。
建議使用 3.8.13 版本,發(fā)現(xiàn)這個版本下載量是最高的。
二,使用手冊
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,標(biāo)題
// 左側(cè)標(biāo)題
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, // 旋轉(zhuǎn)角度(負(fù)值為順時針,正值為逆時針)
fill: '#8f8f8f', // 標(biāo)簽顏色
textAlign: 'end' // 標(biāo)簽對齊方式
textBaseline: 'middle', // 文本基線對齊方式
// offset: 2, // 標(biāo)簽偏移
},
line: {
stroke: '#dfdfdf' // 橫軸線顏色
},
tickLine: {
stroke: '#dfdfdf',
}
})
chart.axis(props.labelInfo.yName, {
label: {
fill: '#8f8f8f' // 縱軸標(biāo)簽顏色
}
})
- 不顯示
chart.axis(props.labelInfo.yName, false)
chart.axis(props.labelInfo.xName, false)
// 或者隱藏 X 軸的刻度線和文字
chart.axis('x', {
label: null, // 隱藏文字
line: null, // 隱藏軸線
tickLine: null // 隱藏刻度線
});
5,坐標(biāo)軸刻度顯示
// 調(diào)整 x 橫坐標(biāo)顯示
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
多條數(shù)據(jù),其中一條只有一個值時,如果只用line 是不顯示的,需要用point,但是如果使用默認(rèn)的point,折線上也會顯示點,但是如果不想在折線上顯示點,需要控制點的大?。╯ize),當(dāng)點的大小和線的大小一樣大,則看不明顯。

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 邊距調(diào)整
const chart = new F2.Chart({
el: chartContainer.value,
padding: [20, 5], // 默認(rèn)auto
pixelRatio: window.devicePixelRatio
})

image.png
11,數(shù)據(jù)為空
數(shù)據(jù)為空時,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">暫無數(shù)據(jù)</div>
</div>
<canvas v-else ref="chartContainer"></canvas>
if (!chartData || chartData.length === 0) {
console.log('暫無數(shù)據(jù)');
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">暫無數(shù)據(jù)</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) {
// 左側(cè)標(biāo)題
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)
// 無數(shù)據(jù)提示
if (chartData.value.length > 0) {
// x,y 軸是否顯示
if (props.yxShow) {
chart.axis(props.labelInfo.xName, {
label: {
fill: '#8f8f8f', // 標(biāo)簽顏色
textAlign: 'end' // 標(biāo)簽對齊方式
// offset: 2, // 標(biāo)簽偏移
},
line: {
stroke: '#dfdfdf' // 橫軸線顏色
}
})
chart.axis(props.labelInfo.yName, {
label: {
fill: '#8f8f8f' // 縱軸標(biāo)簽顏色
}
})
// 調(diào)整橫坐標(biāo)顯示
chart.scale(props.labelInfo.xName, {
type: 'timeCat',
mask: 'MM-DD',
// range: [0, 1],
tickCount: 7
})
} else {
chart.axis(props.labelInfo.xName, {
label: {
fill: '#8f8f8f', // 標(biāo)簽顏色
// rotate: -45, // 旋轉(zhuǎn)標(biāo)簽
textAlign: 'center' // 標(biāo)簽對齊方式
},
line: {
stroke: '#dfdfdf' // 橫軸線顏色
}
})
chart.axis(props.labelInfo.yName, false)
// 調(diào)整橫坐標(biāo)顯示
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()
}
}
// 設(shè)置折現(xiàn),點,面積顏色
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>