echarts 实现签到记录日历组件

以下笔记来源:编程导航

分析

有三种基本图表可以选择:

  1. 基础日历图:https://echarts.apache.org/examples/zh/editor.html?c=calendar-simple
  2. 日历热力图:https://echarts.apache.org/examples/zh/editor.html?c=calendar-heatmap

跟上一个图的区别就是鼠标放上去可以展示具体的热力值,热力值越高,图块的颜色越深。

  1. 日历图:https://echarts.apache.org/examples/zh/editor.html?c=calendar-charts

当我们只需要实现签到功能的时候,不涉及热力数值的区分(只有 0 和 1 签到 / 未签到的区别)。

官方生成数据的循环代码如下:

for (let time = date; time <= end; time += dayTime) {
  data.push([
    echarts.time.format(time, '{yyyy}-{MM}-{dd}', false),
    Math.floor(Math.random() * 10000)
  ]);
}

得到的数据是一个二维数组,每个元素表示一个日期和对应的数值(也正是后端需要返回的结构):

[
  ['2017-01-01', 3456],
  ['2017-01-02', 8975],
  ...
]

调整热力值的范围,从而控制颜色深浅。还支持调整颜色:

visualMap: {
  show: false,
    min: 0,
    max: 1,
    inRange: {
    color: ['#efefef', 'lightgreen']  // 颜色从灰色到浅绿色
  },
},

在这里插入图片描述

实现

安装 ECharts:https://echarts.apache.org/zh/index.html

和 React ECharts 可视化库:https://github.com/hustcc/echarts-for-react

npm install --save echarts
npm install --save echarts-for-react

安装失败的话,在命令后加 --force

封装日历图组件:

1)参考 React ECharts 的 官方文档 来使用 ECharts 组件,把 Demo 代码复制到新建的组件文件中。

2)定义签到日期数组变量,将数组转换为图表需要的数据。其中,对日期的处理需要用到 dayjs 库:

tsx
复制代码
// 签到日期列表([1, 200],表示第 1 和第 200 天有签到记录)
const [dataList, setDataList] = useState<number[]>([]);

// 计算图表需要的数据
const year = new Date().getFullYear();
const optionsData = dataList.map((dayOfYear, index) => {
  // 计算日期字符串
  const dateStr = dayjs(`${year}-01-01`)
    .add(dayOfYear - 1, "day")
    .format("YYYY-MM-DD");
  return [dateStr, 1];
});

4)参考 Echarts 的官方 Demo 开发前端日历图:https://echarts.apache.org/examples/zh/editor.html?c=calendar-simple

先在 Demo 页面里调整好效果,得到 options 选项。

💡 小技巧:可以通过配置项或者询问 AI 得到需要的配置

import React, {useEffect, useState} from "react";
import ReactECharts from "echarts-for-react";
import "./index.css";
import dayjs from "dayjs";
import {getUserSignInRecordUsingGet} from "@/api/userController";
import {message} from "antd";

/**
 * 日历图组件
 * @constructor
 */
export default function CalendarChart() {
  // 签到日期列表([1, 200],表示第 1 和第 200 天有签到记录)
  const [dataList, setDataList] = useState<number[]>([1, 200]);

  const fetchDataList =  async  () => {
    try {
      // 请求后端获取数据
      const res = await getUserSignInRecordUsingGet({
        year
      });
      setDataList(res.data);
    } catch (e) {
      message.error(`获取刷题签到记录失败: ${e.message}`);
    }
  }

  useEffect(() => {
    fetchDataList();
  }, []);

  // 计算图表需要的数据
  // 当前年份
  const year = new Date().getFullYear();
  const optionsData = dataList.map((dayOfYear, index) => {
    // 计算日期字符串
    const dateStr = dayjs(`${year}-01-01`)
      .add(dayOfYear - 1, "day")
      .format("YYYY-MM-DD");
    return [dateStr, 1];
  });

  // 图表配置
  const options = {
    visualMap: {
      show: false,
      min: 0,
      max: 1,
      inRange: {
        // 颜色从灰色到浅绿色
        color: ["#efefef", "lightgreen"],
      },
    },
    calendar: {
      range: year,
      left: 20,
      // 单元格自动宽度,高度为 16 像素
      cellSize: ['auto', 16],
      yearLabel: {
        position: "top",
        formatter: `${year} 年刷题记录`,
      }
    },
    series: {
      type: "heatmap",
      coordinateSystem: "calendar",
      data: optionsData,
    },
  };

  return <ReactECharts option={options} />;
}

执行签到:

这里单独封装了一个钩子,因为进入详情页面时才会执行自动签到,而详情页面是在服务端渲染(本项目),获取不到登录态,所以我们需要单独封装一个钩子,在客户端额外发送请求来执行签到。

import { useEffect, useState } from "react";
import { message } from "antd";
import { addUserSignInUsingPost } from "@/api/userController";

/**
 * 添加用户签到记录钩子
 */
const useAddUserSignInRecord = () => {
  const [loading, setLoading] = useState(false);

  // 请求后端执行签到
  const doFetch = async () => {
    setLoading(true);
    try {
      await addUserSignInUsingPost();
    } catch (e) {
      message.error("添加刷题签到记录失败," + e.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    doFetch();
  }, []);

  return { loading };
};

export default useAddUserSignInRecord;

该钩子需要在客户端组件中执行,因为用到了 useEffect 防止重复请求、并且还需要获取到用户登录态。

todo: 签到成功,可以保存到 LocalStorage 等位置,防止每次刷题都重复发送签到请求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/873502.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用paddlerocr识别固定颜色验证码

1 引言 本文使用opencv和paddlerocr识别出固定颜色的验证码&#xff0c;原理不解释&#xff0c;安装包的方法自行查找&#xff0c;只提供代码和思路。 1 使用opencv对特定颜色区域进行提取2 使用paddlerocr识别并输出验证码 2 代码 2.1 读取图片&#xff0c;提取蓝色区域 …

C语言深入理解指针4

1.回调函数 回调函数是通过函数指针调用的函数 将函数指针作为参数传递给另一个函数&#xff0c;当这个函数指针被用来调用其所指向的函数时&#xff0c;被调用的函数就是回调函数&#xff0c;回调函数不是应该由该函数的实现方直接调用&#xff0c;而是在特定的事件或条件发生…

ASIO网络调试助手之一:简介

多年前&#xff0c;写过几篇《Boost.Asio C网络编程》的学习文章&#xff0c;一直没机会实践。最近项目中用到了Asio&#xff0c;于是抽空写了个网络调试助手。 开发环境&#xff1a; Win10 Qt5.12.6 Asio(standalone) spdlog 支持协议&#xff1a; UDP TCP Client TCP Ser…

JavaWeb【day11】--(SpringBootWeb案例)

SpringBootWeb案例 前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能&#xff0c;还有两个需要实现&#xff1a; 新增员工 修改员工 首先我们先完成"新增员工"的功能开发&#xff0c;再完成"修改员工"的功能开发。而在&quo…

【C++】STL学习——priority_queue(了解仿函数)

目录 priority_queue介绍迭代器种类priority_queue实现仿函数仿函数的使用 priority_queue介绍 优先队列是一种容器适配器&#xff0c;根据严格的弱排序标准&#xff0c;它的第一个元素总是它所包含的元素中最大的。此上下文类似于堆&#xff0c;在堆中可以随时插入元素&#x…

SQL 编程基础

SQL&#xff08;结构化查询语言&#xff09;广泛应用于数据库操作&#xff0c;是每个程序员都需要掌握的技能之一。这篇文章将带你从基础入门&#xff0c;了解SQL编程中的常量、变量及流程控制语句。我们将采用简单易懂的语言&#xff0c;结合实际示例&#xff0c;帮助你轻松理…

uniapp scroll-view滚动页面

页面滚动固定距离&#xff08;scrollTop&#xff09; <template><view><button click"Test">测试</button><scroll-view style"height: 100px;" :scroll-top"scrollTop" scroll-y"true" class"scrol…

7系列FPGA HR/HP I/O区别

HR High Range I/O with support for I/O voltage from 1.2V to 3.3V. HP High Performance I/O with support for I/O voltage from 1.2V to 1.8V. UG865&#xff1a;Zynq-7000 All Programmable SoC Packaging and Pinout

基于tesseract实现文档OCR识别

导入环境 导入必要的库 numpy: 用于处理数值计算。 argparse: 用于处理命令行参数。 cv2: OpenCV库&#xff0c;用于图像处理。 import numpy as np import argparse import cv2设置命令行参数 ap argparse.ArgumentParser() ap.add_argument("-i", "--imag…

Codeforces Round 970 (Div. 3)(ABCDEF)

Codeforces Round 970 (Div. 3) A:Sakurakos Exams 签到 题意:给定1,2的数量,判断是否能用加减符号使得这些1,2计算出0 void solve() {cin>>n>>m;if(n%2)cout<<"NO\n";else{if(m%20||n)cout<<"YES\n";else cout<<"…

如何在docker容器中导入.sql文件

一、准备工作 确保容器运行&#xff1a; 首先确认包含 MySQL 服务的 Docker 容器正在运行。可以通过 docker ps 命令查看正在运行的容器列表。如果容器未运行&#xff0c;使用 docker start [container_id] 命令启动容器。 准备数据库文件&#xff1a; 将需要导入的数据库文件&…

用户画像的人群圈选

背景 用户画像的人群圈选一般涉及到bitmap的运算&#xff0c;我们可以使用java中的RoaringBitmap进行运算&#xff0c;也可以直接使用ck的bitmap进行运算&#xff0c;本文就来看一下这两种方式 人群圈选 使用java的RoaringBitmap进行运算&#xff1a; 使用clickhouse的bit…

145-Linux权限维持Rootkit后门Strace监控Alias别名Cron定时任务

参考 【权限维持】Linux&Rootkit后门&Strace监控&Alias别名&Cron定时任务_alias lsalerts(){ ls $* --colorauto;python -c "-CSDN博客 参考 FlowUs 息流 - 新一代生产力工具 权限维持-Linux-定时任务-Cron后门 利用系统的定时任务功能进行反弹Shell 1…

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物&#xff0c;今天我们实现一下人物实现移动和跳起&#xff0c;依次点击&#xff0c;我们准备创建一个C#文件 创建好我们点击进去&#xff0c;就会跳转到我们的Vision Studio&#xff0c;然后输入这些代码 using UnityEngine;public class M…

java基础概念21-权限修饰符、代码块

一、权限修饰符 1-1、作用 权限修饰符&#xff0c;是用来控制一个成员能够被访问的范围的。 可以修饰&#xff1a;成员变量&#xff0c;方法&#xff0c;构造方法&#xff0c;内部类。 1-2、权限修饰符的分类 二、代码块 局部代码块构造代码块静态代码块 2-1、局部代码块 …

IM即时通讯,稳定可靠的即时通讯服务-WorkPlus

在现代企业日常工作中&#xff0c;即时通讯已成为了一种不可或缺的沟通工具。为了满足企业对稳定可靠的即时通讯服务的需求&#xff0c;WorkPlus提供了一款优秀的IM即时通讯平台&#xff0c;以满足企业高效沟通和协作的要求。本文将深入探讨IM即时通讯服务的重要性以及WorkPlus…

navigator.mediaDevices.getUserMedia检查用户的摄像头是否可用,虚拟摄像头问题

在Web开发中&#xff0c;检查用户的摄像头是否可用是一个常见的需求&#xff0c;尤其是在需要视频聊天或录制视频的应用程序中。navigator.mediaDevices.getUserMedia() API 提供了这一功能&#xff0c;它允许你请求访问用户的媒体设备&#xff0c;如摄像头和麦克风。虽然这个A…

数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树

文章目录 树与二叉树的应用1.哈夫曼树与哈夫曼曼编码1.1 带权路径长度1.2 哈夫曼树1.2.1 哈夫曼树的构造1.3 哈夫曼编码 2.并查集2.1 并查集的三要素2.1.1 并查集的逻辑结构2.1.2 并查集的存储结构 2.2 并查集的优化2.2.1 初步优化&#xff08;并操作优化&#xff09;2.2.2 终极…

【优选算法】---前缀和

前缀和 一、【模板】一维前缀和二、【模板】二维前缀和三、寻找数组的中心下标四、除自身以外数组的乘积五、和为K子数组六、和可被 K 整除的子数组七、连续数组八、矩阵区域和 一、【模板】一维前缀和 一维前缀和&#xff0c;链接 1、预处理出来一个前缀和数组 注意&#xf…

消息中间件 --Kafka

一、 Kafka 1.kafka介绍 Kafka 是一个分布式流媒体平台,类似于消息队列或企业消息传递系统。 生产者发送消息&#xff0c;多个消费者只能有一个消费者接收到消息 生产者发送消息&#xff0c;多个消费者都可以接收到消息 producer&#xff1a;发布消息的对象称之为主题生产者…