【VUE3+AntV-G2Plot】封装象四限图组件(含选择坐标轴数据实时更新方法)
一些废话
默默做前端,分享一些自己在项目需求实现中遇到的奇妙问题
(主要是网上搜索不到解决办法自己解决后的总结方法和解决办法但不全面,自己整理总结的存档)。
事发背景
项目中需要前端展示四象限气泡图于是采用了G2Plot的四象限气泡图。
从官方文档总结的方法,记录一下。
如图,这是官方文档给出的示例
实现效果
初始完成效果:
调整后完成效果:
实现效果所使用的数据都是自己瞎编的,然后还未进行接口联调,所呈现的样式和效果都是默认滴,后续大家根据自己的想法或者项目需求慢慢调整即可。
安装和引入
首先要在项目文件安装antv G2Plot
1.通过 npm 安装
$ npm install @antv/g2plot
成功安装完成之后,即可使用 import
或 require
进行引用。
import { Line } from '@antv/g2plot';
2.浏览器引入
既可以通过将脚本下载到本地也可以直接引入在线资源:
<!-- 引入在线资源 -->
<script type="text/javascript" src="https://unpkg.com/@antv/g2plot@latest/dist/g2plot.min.js"></script>
<script>
const { Line } = G2Plot;
</script>
<!-- 下载到本地 引入本地脚本 -->
<script src="./g2plot.min.js"></script>
<script>
const { Line } = G2Plot;
</script>
3.创建并渲染图表
const line = new Line('container', {
data,
xField: 'year',
yField: 'value',
});
line.render();
实现思路
-
分析图表构成。框架是不显示横纵轴的轴线和刻度线,但是显示刻度数值,并且辅助线垂直相交于(1,1)点(后期如果是两轴数据的中位数也可以使用变量进行数据替换),图例、网格线原型没要求,之后样式再细调,所以我们轴样式使用图二,气泡样式使用图一。
-
pop-chart容器
在template内创建div图表容器
<div id='scatterPlot' style="width:100%;height:366px"></div>
然后在state里定义图表对象和图表中显示的数据
const state = reactive({
scatterPlot: null,//图表对象
showData:[
{
"统计时间": '2022-01',
"指标系数x": 1.08,
"指标系数y": 1.09,
"气泡大小展示的指标": 21,
"气泡主标签指标": "ICU",
},
]//图表中将要显示的数据
})
创建chart
const getPopChart = (data) => {
const scatterPlot = new Scatter('scatterPlot', {
appendPadding: 10,
data,
xField: state.xdataField,
yField: state.ydataField,
sizeField: '入组病例数',
colorField: '统计科室', // 设置多色
color: ['#ffd500', '#82cab2', '#193442', '#d18768', '#7e827a'], // 自定义泡泡颜色
size: [4, 30],
shape: 'circle',
pointStyle: { // 更改辅助数据点大小及样式
fillOpacity: 0.8,
stroke: '#bbb',
},
xAxis: { // 格式化 x 轴标签加单位,自定义 labal 样式
grid: {
line: {
style: {
stroke: '#eee',
},
},
},
line: {
style: {
stroke: '#aaa',
},
},
},
yAxis: { // 格式化 y 轴标签加单位,自定义 labal 样式
line: {
style: {
stroke: '#aaa',
},
},
},
quadrant: {
xBaseline: 0,
yBaseline: 0,
labels: [ // 添加 labal
{
content: 'Male decrease,\nfemale increase',
},
{
content: 'Female decrease,\nmale increase',
},
{
content: 'Female & male decrease',
},
{
content: 'Female &\n male increase',
},
],
},
legend: {
flipPage: true,
// 两行分页
maxRow: 2,
pageNavigator: {
marker: {
style: {
fill: 'rgba(0,0,0,0.65)',
},
},
},
},
});
scatterPlot.render(); // 渲染图表
state.scatterPlot = scatterPlot // 赋予全局变量为图表属值
}
- 选坐标系数值change方法
const handleXChange = (v) => {
const scatterPlot = state.scatterPlot;
if (scatterPlot) {
scatterPlot.update({ xField: v }); // 更新图表x轴值
}
}
const handleYChange = (v) => {
const scatterPlot = state.scatterPlot;
if (scatterPlot) {
scatterPlot.update({ yField: v }); // 更新图表y轴值
}
}
总结和完整代码
<template>
<div class="ground-box">
<div class="flex line-box">
<div>x轴:
<el-select v-model="state.xdataField" placeholder="请选择数据范围" class="mr-10" style="width:130px;" @change="handleXChange">
<el-option v-for="(item, index) in state.rangeList" :key="index" :label="item.name" :value="item.value"/>
</el-select>
</div>
<div>y轴:
<el-select v-model="state.ydataField" placeholder="请选择数据范围" class="mr-10" style="width:130px;" @change="handleYChange">
<el-option v-for="(item, index) in state.rangeList" :key="index" :label="item.name" :value="item.value"/>
</el-select>
</div>
</div>
<el-card class="box-card">
<span class="flex justify-content-end" style="font-size: 10px; color: #b9b7b7;">气泡大小:为入组病例数</span>
<div id='scatterPlot ' style="width:100%; height:366px;"></div>
</el-card>
</div>
</template>
<script setup>
import { reactive,getCurrentInstance, onMounted } from 'vue';
import { Scatter } from '@antv/g2plot';
import { ApiConstant } from '@/constants/ApiConstant/index.js'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router';
const { proxy } = getCurrentInstance();
const props = defineProps({
isDip: { // 是否是dip
type: Boolean,
default: false
}
})
const state = reactive({
xdataField: '时间消耗指数',
ydataField: '费用消耗指数',
rangeList: [
{ name: `统计时间`, value: '统计时间' },
{ name: `入组病例数`, value: '入组病例数' },
{ name: `时间消耗指数`, value: '时间消耗指数' },
{ name: `费用消耗指数`, value: '费用消耗指数' },
{ name: `统计科室`, value: '统计科室' },
],
scatterPlot: null, // 图表对象
showData: [ // 图表中将要显示的数据
{
"统计时间": '2022-01',
"时间消耗指数": 1.08,
"费用消耗指数": 1.09,
"入组病例数": 21,
"统计科室": "ICU",
},
],
})
const getData = () => {
getPopChart(state.showData)
}
const getPopChart = (data) => {
const scatterPlot = new Scatter('scatterPlot ', {
appendPadding: 10,
data,
xField: state.xdataField,
yField: state.ydataField,
sizeField: '入组病例数',
colorField: '统计科室', // 设置多色
color: ['#ffd500', '#82cab2', '#193442', '#d18768', '#7e827a'], // 自定义泡泡颜色
size: [4, 30],
shape: 'circle',
pointStyle: { // 更改辅助数据点大小及样式
fillOpacity: 0.8,
stroke: '#bbb',
},
xAxis: { // 格式化 x 轴标签加单位,自定义 labal 样式
grid: {
line: {
style: {
stroke: '#eee',
},
},
},
line: {
style: {
stroke: '#aaa',
},
},
},
yAxis: { // 格式化 y 轴标签加单位,自定义 labal 样式
line: {
style: {
stroke: '#aaa',
},
},
},
quadrant: {
xBaseline: 0,
yBaseline: 0,
labels: [ // 添加 labal
{
content: 'Male decrease,\nfemale increase',
},
{
content: 'Female decrease,\nmale increase',
},
{
content: 'Female & male decrease',
},
{
content: 'Female &\n male increase',
},
],
},
legend: {
flipPage: true,
// 两行分页
maxRow: 2,
pageNavigator: {
marker: {
style: {
fill: 'rgba(0,0,0,0.65)',
},
},
},
},
});
scatterPlot.render();
state.scatterPlot = scatterPlot // 赋予全局变量为图表属值
}
const handleXChange = (v) => {
const scatterPlot = state.scatterPlot;
if (scatterPlot) {
scatterPlot.update({ xField: v }); // 更新图表x轴值
}
}
const handleYChange = (v) => {
const scatterPlot = state.scatterPlot;
if (scatterPlot) {
scatterPlot.update({ yField: v }); // 更新图表y轴值
}
}
const init = () => {
// getPopChart();//创建chart
getData();//设置字段和数据
}
onMounted(() => {
init()
})
</script>
参考资料
转载自:https://juejin.cn/post/7207340436648853562