Antv G2(bizCharts) 点线图 实现

名字

点线图: 不知道怎么命名

效果图

在这里插入图片描述

思路

数据: 初始化三条数据, 中间的为显示数据
使用折线图,隐藏折线,隐藏显示数据之外的所有点
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;


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本系统的研发具有重大的意义,在安全性方面,用户使用浏览器访问网站时,采用注册和密码等相关的保护措施,提高系统的可靠性,维护用户的个人信息和财产的安全。在方便性方面,促进了校园失物招领网站的信息化建设,极大的方便了相关的工作人员对校园失物招领网站信息进行管理。 本系统主要通过使用Java语言编码设计系统功能,MySQL数据库管理数据,AJAX技术设计简洁的、友好的网址页面,然后在IDEA开发平台中,编写相关的Java代码文件,接着通过连接语言完成与数据库的搭建工作,再通过平台提供的Tomcat插件完成信息的交互,最后在浏览器中打开系统网址便可使用本系统。本系统的使用角色可以被分为用户和管理员,用户具有注册、查看信息、留言信息等功能,管理员具有修改用户信息,发布寻物启事等功能。 管理员可以选择任一浏览器打开网址,输入信息无误后,以管理员的身份行使相关的管理权限。管理员可以通过选择失物招领管理,管理相关的失物招领信息记录,比如进行查看失物招领信息标题,修改失物招领信息来源等操作。管理员可以通过选择公告管理,管理相关的公告信息记录,比如进行查看公告详情,删除错误的公告信息,发布公告等操作。管理员可以通过选择公告类型管理,管理相关的公告类型信息,比如查看所有公告类型,删除无用公告类型,修改公告类型,添加公告类型等操作。寻物启事管理页面,此页面提供给管理员的功能有:新增寻物启事,修改寻物启事,删除寻物启事。物品类型管理页面,此页面提供给管理员的功能有:新增物品类型,修改物品类型,删除物品类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值