点线图
: 不知道怎么命名
数据: 初始化三条数据, 中间的为显示数据
使用折线图,隐藏折线,隐藏显示数据之外的所有点
X轴:隐藏X轴坐标内容
Y轴:设置y轴内容,y轴标题
注释:添加注释,线条,描述内容
// 1、导入Chart图表
import { Chart } from "@antv/g2";
// 2、初始化图表
useEffect(() => {
(async () => {
const chartBox = new Chart({
container: 'c3',
autoFit: true,
width: width,
height: height,
title: true
})
await setChartBox(chartBox) // 设置图表 chart
const newData = cloneDeep(cData) // 复制数据 useState引用数据用新的地址替换
newData.splice(1,1, data) // props接收到的显示的那条数据内容
await setData(() => newData) // 设置新数据
})()
}, [])
// 3、图表渲染
const setChart = () => {
const margin = 1 / 3 // 3为数据列表长度
chart.clear()
chart.data(cData);
chart.scale({
date: {
// 坐标轴起始位置修改 一般[0 , 1]
range: [margin / 2, 1 - margin / 2],
},
num: {
// 起始位置不变 末尾位置留白 给标题挤出空间
range: [0, 1 - margin / 2],
min: 0, // 设置坐标轴最小值
max: max,// 设置坐标轴最大值
nice: true, // 不设置最大值最小值的时候 会根据数据内容自动变化
},
});
chart.tooltip(false); // 关闭提示
// 坐标轴 X
chart.axis('date', {
label: {
// 返回空字符串 隐藏横坐标文字内容
formatter: (text) => ""
}
})
// 坐标轴 Y
chart.axis('num', {
title: {
text: cTitle, // 标题内容
autoRotate: false,
position: "end",
offset: -10,
textStyle: {
textAlign: 'start', // 文本对齐方向,可取值为: start middle end
fontSize: '12', // 文本大小
fontWeight: 'bold', // 文本粗细
textBaseline: 'top' // 文本基准线,可取 top middle bottom,默认为middle
},
},
label: {
formatter: (text) => text
}
})
// 隐藏折线
chart.line().style({
stroke: "transparent" // 设置透明颜色
}).position('date*num');
// 隐藏点
chart
.point()
.size(2) // 控制点的大小
.position('date*num')
.label("name", (val) => {
// 关联文字 设置样式
if (val) {
// 吐槽文本内容字段 一会text 一会content 全是试出来的
return {
content: val, // 格式化文字 不给默认显示关联字段的值
offsetX: 12, // 距离设置点的X偏移量
offsetY: 12, // 距离设置点的Y偏移量
style: {
fill: dataColor,
fontSize: 12,
},
}
}
})
.style("num*name", ((val, name) => {
// 只显示有名字的那个点 其他点隐藏
if (name) {
return {
stroke: dataColor,
fill: dataColor
}
}
// 其他点 隐藏
return {
stroke: "transparent",
lineWidth: 0
}
}))
// 注释
chart.annotation().line({
top: true,
start: [-0.5, averageNum], // 起始位置 第一个参数为X起始位置 第二个为Y
end: [2.5, averageNum], // 结束位置 第一个参数为X起始位置 第二个为Y
// 上面X轴通过 改变了起始位置 range: [margin / 2, 1 - margin / 2]
// 现在又想要注释的横线横穿整个图表 所以向左右扩展
// -0.5 向左扩展 2.5向右扩展 数字可以想成是数据列表的索引
style: {
stroke: contentColor,
lineWidth: 1,
lineDash: [3, 3],
},
text: {
position: 'start',
style: {
fill: contentColor,
fontSize: 12,
fontWeight: 500,
},
content: content,
offsetY: -5,
},
});
chart.render();
}
import React, { useState, useEffect, useRef } from "react";
import "./chart.less"
import { Chart } from "@antv/g2";
import { cloneDeep } from "lodash"
import PropTypes from 'prop-types';
const Charts = (props) => {
const {
width,
height,
max,
content,
contentColor,
dataColor,
cTitle,
data,
averageNum
} = props
const initData = [
{ date: "a", num: 0 },
{ date: "b", num: 0 },
{ date: "c", num: 0 }
]
const [cData, setData] = useState(initData)
const [chart, setChartBox] = useState(null)
const chartRef = useRef()
useEffect(() => {
(async () => {
const chartBox = new Chart({
container: 'c3',
autoFit: true,
width: width,
height: height,
title: true
})
await setChartBox(chartBox)
const newData = cloneDeep(cData)
newData.splice(1,1, data)
await setData(() => newData)
})()
}, [])
// 下面两个useEffect 根据传入内容改变 进行修改
// 原来写法是这样的 不过现在根据react的dom diff的逻辑 在父组件使用时候传入个key值
// 要更新的时候 修改下那个key就行了 少量操作问题不大
// 大量的话 对性能不友好
useEffect(() => {
// initData 初始固定三条数据 修改中间的即可
if (cData[1].name && chart) {
chart.clear()
setChart()
}
}, [chart, cData])
useEffect(() => {
if (cTitle && chart) {
chart.clear()
setChart()
}
}, [chart, cTitle])
useEffect(() => {
(async () => {
const newData = cloneDeep(cData)
newData.splice(1,1, data)
await setData(() => newData)
if (data && chart) setChart()
})()
}, [chart, data])
const setChart = () => {
const margin = 1 / 3
chart.clear()
chart.data(cData);
chart.scale({
date: {
range: [margin / 2, 1 - margin / 2],
},
num: {
range: [0, 1 - margin / 2],
min: 0,
max: max,
nice: true,
},
});
chart.tooltip(false);
// 坐标轴
chart.axis('date', {
label: {
// 返回空字符串 隐藏横坐标文字内容
formatter: (text) => ""
}
})
chart.axis('num', {
title: {
text: cTitle,
autoRotate: false,
position: "end",
offset: -10,
textStyle: {
textAlign: 'start', // 文本对齐方向,可取值为: start middle end
fontSize: '12', // 文本大小
fontWeight: 'bold', // 文本粗细
textBaseline: 'top' // 文本基准线,可取 top middle bottom,默认为middle
},
},
label: {
formatter: (text) => text
}
})
// 隐藏折线
chart.line().style({
stroke: "transparent"
}).position('date*num');
// 隐藏点
chart
.point()
.size(2)
.position('date*num')
.label("name", (val) => {
// 关联文字 设置样式
if (val) {
return {
content: val,
offsetX: 12,
offsetY: 12,
style: {
fill: dataColor,
fontSize: 12,
},
}
}
})
.style("num*name", ((val, name) => {
// 只显示有名字的那个点 其他点隐藏
if (name) {
return {
stroke: dataColor,
fill: dataColor
}
}
return {
stroke: "transparent",
lineWidth: 0
}
}))
// 没找到清空annotation的方法 不用key触发更新的话
// 再次渲染的时候会叠加出现上次的线
chart.annotation().line({
top: true,
start: [-0.5, averageNum],
end: [2.5, averageNum],
style: {
stroke: contentColor,
lineWidth: 1,
lineDash: [3, 3],
},
text: {
position: 'start',
style: {
fill: contentColor,
fontSize: 12,
fontWeight: 500,
},
content: content,
offsetY: -5,
},
});
chart.render();
}
return (
<div className={"chart"}>
<div id="c3" ref={chartRef} />
</div>
)
}
Charts.defaultProps = {
max: 150,
data: { date: "c", num: 60, name: "我" },
width: 300,
height: 200,
dataColor: "#fe8140", // 文字 点颜色
contentColor: "#f4a240", // 横线颜色
cTitle: "单位: 小时", // 纵坐标轴标题
content: "团队均值: 75",// 均值说明
averageNum: 75,// 均值说明
}
Charts.propTypes = {
max: PropTypes.number,
data: PropTypes.object.isRequired,
width: PropTypes.number,
height: PropTypes.number,
dataColor: PropTypes.string,
contentColor: PropTypes.string,
cTitle: PropTypes.string,
content: PropTypes.string,
averageNum: PropTypes.number,
}
export default Charts;
import React from 'react';
import { Button } from "antd"
import Chart3 from "./components/chart3"
class Charts extends React.Component {
constructor(props) {
super(props);
this.state = {
cTitle: "单位: 小时",
data: { date: "b", num: 120, name: "我" },
averageNum: 75
}
}
change = () => {
const { cTitle } = this.state
const flag = cTitle === "单位: 个"
const title = flag ? "单位: 小时" : "单位: 个"
const data = flag ?
{ date: "b", num: 120, name: "我" } :
{ date: "b", num: 55, name: "你" }
const averageNum = flag ? 75 : 55
this.setState({
cTitle: title,
data: data,
averageNum: averageNum,
})
}
render () {
const { cTitle, data, averageNum } = this.state
// 组件通过key值变化可以触发更新
return (
<div className={"chartBox"}>
<Chart3
cTitle={cTitle}
data={data}
key={data.num}
averageNum={averageNum}
/>
<Button onClick={this.change}>切换</Button>
</div>
)
}
}
export default Charts;