vue3 tsx 项目中使用 Antv/G2 实现多线折线图
Antv/G2 文档
Antv/G2 双折线图
安装 antV-G2
通过 npm 安装
项目中安装 antv/g2
依赖库:
npm install @antv/g2 --save
安装成功:
浏览器引入
可以将脚本下载到本地,也可以直接引入在线资源。
引入在线资源
<!-- 引入在线资源,选择需要的 g2 版本以替换 version 变量 -->
<script src="https://gw.alipayobjects.com/os/lib/antv/g2/{{version}}/dist/g2.min.js"></script>
<!-- 浏览器引入,请使用全局命名空间 G2,如 new Chart() 改为 new G2.Chart,即可运行。 -->
引入本地脚本
<!-- 引入本地脚本 -->
<script src="./g2.js"></script>
使用 script
标签引入 G2
资源时,挂载在 window
上的变量名为 G2
。所以,实例中需要加上 G2
的前缀。如下:
const chart = new G2.Chart({
})
项目使用
新建文件 IndicatorTrend.tsx
:
import { defineComponent, PropType, onMounted, ref } from 'vue'
import { useChartAutoResize } from '@/hooks/chart'
import styled from '@/styled-components'
import { Chart } from '@antv/g2';
export interface TrendListItem {
date: string
city: string
tempvalue: number
}
interface Props {
dataList?: TrendListItem[]
}
const Container = styled.div`
width: 100%;
height: 100%;
`
const TitleBox = styled.h3`
margin-bottom: 10px;
`
const ChartContainer = styled.div`
height:100%;
`
export default defineComponent({
props: {
dataList: {
type: Array as PropType<TrendListItem[]>,
default: () => []
}
},
setup() {
const dataList = ref<TrendListItem[]>([])
const canvasRef = ref<null | HTMLElement>(null)
const chartRef = ref<null | InstanceType<typeof Chart>>(null)
onMounted(() => {
if (canvasRef.value) {
const chart = new Chart({
container: canvasRef.value,
autoFit: true
})
chartRef.value = chart
}
refreshChartView()
})
useChartAutoResize(canvasRef, chartRef)
function refreshChartView(){
const chart: any = chartRef.value
chart.clear()
setTimeout(() => {
chart.data(dataList.value)
chart.scale({
date: {
range: [0, 1],
},
tempvalue: {
nice: true,
},
});
chart.tooltip({
showCrosshairs: true,
shared: true,
});
chart.axis('tempvalue', {
label: {
formatter: (val:number) => {
return val + ' °C';
},
},
});
chart
.line()
.position('date*tempvalue')
.color('city')
.shape('smooth');
chart
.point()
.position('date*tempvalue')
.color('city')
.shape('circle')
.style({
stroke: '#fff',
lineWidth: 1,
});
chart.render()
})
}
return (props: Props) => {
dataList.value = props.dataList || []
return (
<Container>
<TitleBox>总趋势</TitleBox>
<ChartContainer>
<div ref={canvasRef} />
</ChartContainer>
</Container>
)
}
}
})
其中,引用了公共方法 hooks/chart
:
import { ref, onUnmounted, watchEffect } from 'vue'
import { changeSizeAfterCanvasResize, deleteGlobalChartItem } from '@/utils/chart'
// 没找到ref的类型
export const useChartAutoResize = (canvasRef: any, chartRef: any): void => {
const queueIndex = ref<number>(-1)
const isCreated = ref(false)
function clearThisChart() {
queueIndex.value > 0 && deleteGlobalChartItem(queueIndex.value)
}
// 后续如果需要重复绑定,可以返回一个更新的方法
watchEffect(() => {
if (!isCreated.value && canvasRef.value && chartRef.value) {
clearThisChart()
isCreated.value = true
queueIndex.value = changeSizeAfterCanvasResize(canvasRef.value, chartRef.value)
}
}, {
flush: 'post'
})
onUnmounted(() => {
clearThisChart()
})
}
utils/chart
文件:
import { Chart } from '@antv/g2'
import { ChartResizeQueueItem } from '@/globalType'
const getChartIndex: () => number = createChartIndex()
export function getGlobalChartQueue(): ChartResizeQueueItem[] {
return window.chartResizeQueue
}
export function setGlobalChartQueue(arr: ChartResizeQueueItem[]): ChartResizeQueueItem[] {
window.chartResizeQueue = arr
return window.chartResizeQueue
}
export function deleteGlobalChartItem(index: number): void {
const queue = getGlobalChartQueue()
setGlobalChartQueue(queue.filter(item => item.index !== index))
}
// canvas适应父元素的大小,并刷新图表宽高
export function refreshChartSize(canvas: HTMLElement, chart: Chart): void {
let width: number = 0
let height: number = 0
if (canvas.parentNode && getComputedStyle) {
const styles = getComputedStyle(canvas.parentNode as HTMLElement)
width = Number(styles.width.split('px')[0])
height = Number(styles.height.split('px')[0])
} else if (canvas.parentNode) {
width = (canvas.parentNode as HTMLElement).offsetWidth
height = (canvas.parentNode as HTMLElement).offsetHeight
}
canvas.setAttribute('width', `${width}px`)
canvas.setAttribute('height', `${height}px`)
chart.changeSize(width, height)
}
// 添加到全局图表队列,并且自动更新宽高
export function changeSizeAfterCanvasResize(canvas: HTMLElement, chart: InstanceType<typeof Chart>): number {
const queue = getGlobalChartQueue()
const index: number = getChartIndex()
refreshChartSize(canvas, chart)
setGlobalChartQueue(queue.concat([{ index, canvas, chart }]))
return index
}
function createChartIndex() {
let index: number = 0
return (): number => {
index++
return index
}
}
globalType.ts
文件:
export interface ChartResizeQueueItem {
index: number
canvas: HTMLElement,
chart: any
}
在父组件中引用 IndicatorTrend.tsx
组件:
<IndicatorTrend dataList={totalTrendList.value}></IndicatorTrend>
数据源为:
totalTrendList.value = [{
date: '2023/8/1',
city: 'bily',
tempvalue: 4623
}, {
date: '2023/8/1',
city: 'cily',
tempvalue: 2208
}, {
date: '2023/8/1',
city: 'bill',
tempvalue: 182
}, {
date: '2023/8/2',
city: 'bily',
tempvalue: 6145
}, {
date: '2023/8/2',
city: 'cily',
tempvalue: 2016
}, {
date: '2023/8/2',
city: 'bill',
tempvalue: 257
}, {
date: '2023/8/3',
city: 'bily',
tempvalue: 508
}, {
date: '2023/8/3',
city: 'cily',
tempvalue: 2916
}, {
date: '2023/8/3',
city: 'bill',
tempvalue: 289
}, {
date: '2023/8/4',
city: 'bily',
tempvalue: 6268
}, {
date: '2023/8/4',
city: 'cily',
tempvalue: 4512
}, {
date: '2023/8/4',
city: 'bill',
tempvalue: 428
}, {
date: '2023/8/5',
city: 'bily',
tempvalue: 6411
}, {
date: '2023/8/5',
city: 'cily',
tempvalue: 8281
}, {
date: '2023/8/5',
city: 'bill',
tempvalue: 619
}, {
date: '2023/8/6',
city: 'bily',
tempvalue: 1890
}, {
date: '2023/8/6',
city: 'cily',
tempvalue: 2008
}, {
date: '2023/8/6',
city: 'bill',
tempvalue: 87
}, {
date: '2023/8/7',
city: 'bily',
tempvalue: 4251
}, {
date: '2023/8/7',
city: 'cily',
tempvalue: 1963
}, {
date: '2023/8/7',
city: 'bill',
tempvalue: 706
}, {
date: '2023/8/8',
city: 'bily',
tempvalue: 2978
}, {
date: '2023/8/8',
city: 'cily',
tempvalue: 2367
}, {
date: '2023/8/8',
city: 'bill',
tempvalue: 387
}, {
date: '2023/8/9',
city: 'bily',
tempvalue: 3880
}, {
date: '2023/8/9',
city: 'cily',
tempvalue: 2956
}, {
date: '2023/8/9',
city: 'bill',
tempvalue: 488
}, {
date: '2023/8/10',
city: 'bily',
tempvalue: 3606
}, {
date: '2023/8/10',
city: 'cily',
tempvalue: 678
}, {
date: '2023/8/10',
city: 'bill',
tempvalue: 507
}, {
date: '2023/8/11',
city: 'bily',
tempvalue: 4311
}, {
date: '2023/8/11',
city: 'cily',
tempvalue: 3188
}, {
date: '2023/8/11',
city: 'bill',
tempvalue: 548
}, {
date: '2023/8/12',
city: 'bily',
tempvalue: 4116
}, {
date: '2023/8/12',
city: 'cily',
tempvalue: 3491
}, {
date: '2023/8/12',
city: 'bill',
tempvalue: 456
}, {
date: '2023/8/13',
city: 'bily',
tempvalue: 6419
}, {
date: '2023/8/13',
city: 'cily',
tempvalue: 2852
}, {
date: '2023/8/13',
city: 'bill',
tempvalue: 689
}, {
date: '2023/8/14',
city: 'bily',
tempvalue: 1643
}, {
date: '2023/8/14',
city: 'cily',
tempvalue: 4788
}, {
date: '2023/8/14',
city: 'bill',
tempvalue: 280
}, {
date: '2023/8/15',
city: 'bily',
tempvalue: 445
}, {
date: '2023/8/15',
city: 'cily',
tempvalue: 4319
}, {
date: '2023/8/15',
city: 'bill',
tempvalue: 176
}]
页面效果: