使用React 18、Echarts和MUI实现温度计

关键词 React 18 EchartsMUI

前言

在本文中,我们将结合使用React 18EchartsMUI(Material-UI)库,展示如何实现一个交互性的温度计。我们将使用Echarts绘制温度计的外观,并使用MUI创建一个漂亮的用户界面。
本文将详细介绍实现温度计所需的关键代码以及其他必要的步骤,本文会尽可能的提供详细的注释。

完成后的样式

温度计.jpg

关键代码

import React from 'react';
import * as echarts from 'echarts/core';
import { EChartOption } from '../../EChartOption';
import CommonChart from '../../CommonChart';
import { Box } from '@mui/material';

interface TemperatureBarProps {
  deviceData: any;
}

const MAX_TEMPERATURE_SOCPE = 120; //温度上限
const MIN_TEMPERATURE_SOCPE = -40; // 温度下限

/**
 * 温度图表组件
 */
const TemperatureChart = () => {
  // 温度数值
  let TPvalue = MAX_TEMPERATURE_SOCPE;
  // 刻度数据
  let kd = [];
  // 渐变色配置
  let Gradient = [];

  // 创建刻度数据
  for (
    let i = 0, len = MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE;
    i <= len;
    i += 1
  ) {
    if (i % 20 === 10) {
      kd.push('');
    } else if (i % 40 === 0) {
      kd.push('-48');
    } else if (i % 8 === 0) {
      kd.push('-28');
    } else {
      kd.push('');
    }
  }

  // 根据温度数值设置渐变色和文本内容
  if (TPvalue > 20) {
    Gradient.push(
      {
        offset: 0,
        color: '#93FE94'
      },
      {
        offset: 0.5,
        color: '#E4D225'
      },
      {
        offset: 1,
        color: '#E01F28'
      }
    );
  } else if (TPvalue > -20) {
    Gradient.push(
      {
        offset: 0,
        color: '#93FE94'
      },
      {
        offset: 1,
        color: '#E4D225'
      }
    );
  } else {
    Gradient.push({
      offset: 1,
      color: '#93FE94'
    });
  }

  // 温度图表配置选项
  const option = {
    animation: false, // 禁止动画效果
    title: {
      text: '  ℃',
      top: '5px',
      left: 'center',
      textStyle: {
        color: '#fff',
        fontStyle: 'normal',
        fontWeight: 'normal',
        fontSize: '16px',
        padding: 5
      }
    },
    grid: {
      left: '45', // 图表距离容器左边的距离
      bottom: 20, // 图表距离容器底部的距离
      top: 30 // 图表距离容器顶部的距离
    },
    yAxis: [
      {
        show: false, // 不显示y轴
        data: [], // y轴的数据
        min: 0, // y轴的最小值
        max: MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE + 10, // y轴的最大值
        axisLine: {
          show: false // 不显示y轴的轴线
        }
      },
      {
        show: false, // 不显示y轴
        min: 0, // y轴的最小值
        max: MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE // y轴的最大值
      },
      {
        type: 'category', // 类型为分类
        position: 'left', // y轴的位置在左边
        offset: -80, // y轴与图表的偏移量
        axisLabel: {
          fontSize: 10, // y轴标签的字体大小
          color: 'white' // y轴标签的颜色为白色
        },
        axisLine: {
          show: false // 不显示y轴的轴线
        },
        axisTick: {
          show: false // 不显示y轴的刻度线
        }
      }
    ],
    xAxis: [
      {
        show: false, // 不显示x轴
        min: -50, // x轴的最小值
        max: 80, // x轴的最大值
        data: [] // x轴的数据
      },
      {
        show: false, // 不显示x轴
        min: -48, // x轴的最小值
        max: 120 // x轴的最大值
      }
    ],
    series: [
      {
        name: '条', // 数据项名称
        type: 'bar', // 图表类型为柱状图
        xAxisIndex: 0, // 与第一个x轴关联
        data: [MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE + 10], // 柱状图的数据
        barWidth: 18, // 柱状图的宽度,
        label: {
          show: true // 显示标签
        },
        itemStyle: {
          color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
            {
              offset: 0.05,
              color: '#5087EC' // 渐变颜色的起始色
            },
            {
              offset: 0.5,
              color: '#58DBA4' // 渐变颜色的起始色
            },
            {
              offset: 0.6,
              color: '#FFF81D' // 渐变颜色的中间色
            },
            {
              offset: 0.8,
              color: '#FA9917' // 渐变颜色的中间色
            },
            {
              offset: 1,
              color: '#FF4D4F' // 渐变颜色的结束色
            }
          ]),
          borderRadius: [8, 8, 2, 2] // 柱状图的圆角样式
        },
        z: 2 // 数据系列层叠的顺序值
      },
      {
        name: '圆', // 数据项名称
        type: 'scatter', // 图表类型为散点图
        hoverAnimation: false, // 禁止散点图的Hover动画效果
        data: [0], // 散点图的数据
        xAxisIndex: 0, // 与第一个x轴关联
        symbolSize: 18, // 散点图的符号大小
        itemStyle: {
          color: '#5087EC', // 散点图的颜色
          opacity: 1 // 散点图的透明度
        },
        z: 2 // 数据系列层叠的顺序值
      },
      {
        name: '刻度', // 数据项名称
        type: 'bar', // 图表类型为柱状图
        yAxisIndex: 0, // 与第一个y轴关联
        xAxisIndex: 1, // 与第二个x轴关联
        label: {
          show: true, // 显示标签
          position: 'left', // 标签的位置在左边
          distance: 10, // 标签与柱状图的距离
          color: 'white', // 标签的颜色为白色
          fontSize: 14, // 标签的字体大小
          formatter: function (params) {
            if (
              params.dataIndex >
              MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE
            ) {
              return '';
            }
            if (params.dataIndex % 20 === 0) {
              return params.dataIndex + MIN_TEMPERATURE_SOCPE;
            }
            return '';
          } // 标签的格式化函数
        },
        barGap: '-100%', // 柱状图之间的距离
        data: kd, // 柱状图的数据
        barWidth: 0.5, // 柱状图的宽度
        itemStyle: {
          color: 'white', // 柱状图的颜色为白色
          barBorderRadius: 120 // 柱状图的圆角样式
        },
        z: 0 // 数据系列层叠的顺序值
      }
    ]
  } as EChartOption;

  // 返回渲染图表的组件
  return <CommonChart option={option} width="100%" height="100%" />;
};

export default function TemperatureBar() {
  const [maxTemperature, setMaxTemperature] = React.useState<number>(80); // 定义最大温度的状态值,默认为80
  const [minTemperature, seMinTemperature] = React.useState<number>(-20); // 定义最小温度的状态值,默认为-20

  return (
    <Box
      ref={parentRef}
      sx={{
        display: 'flex',
        height: '100%',
        alignItems: 'center',
        justifyContent: 'center',
        position: 'relative',
        color: '#fff'
      }}
    >
      {isMinHieght ?
        <Box
          sx={{
            display: 'flex',
            flexDirection: 'column',
            textAlign: 'left'
          }}
        >
          <Box
            sx={{
              display: 'flex',
              alignItems: 'center',
              mb: 2
            }}
          >
            <Box
              sx={{
                borderLeft: '10px solid transparent',
                borderRight: '10px solid transparent',
                borderBottom: '20px solid #FF4D4F',
                width: 0,
                height: 0,
                display: 'inline-block'
              }}
            ></Box>
            <span
              style={{
                paddingLeft: '4px'
              }}
            >
             最高温度
              {parseFloat(String(maxTemperature)).toFixed(1)}</span>
          </Box>
          <Box
            sx={{
              display: 'flex',
              alignItems: 'center'
            }}
          >
            <Box
              sx={{
                borderLeft: '10px solid transparent',
                borderRight: '10px solid transparent',
                borderTop: '20px solid #5087EC',
                width: 0,
                height: 0,
                display: 'inline-block'
              }}
            ></Box>
            <span
              style={{
                paddingLeft: '4px'
              }}
            >
             最低温度
              {parseFloat(String(minTemperature)).toFixed(1)}</span>
          </Box>
        </Box> :
        <Box
          sx={{
            width: 'calc(100% - 80px)',
            maxWidth: '140px',
            height: '80%',
            background: '#363636',
            borderRadius: '8px',
            position: 'relative',
            boxShadow: '2px 2px 8px 0px rgba(0, 0, 0, 0.7)'
          }}
        >
          <Box
            sx={{
              position: 'absolute',
              top: '-25px',
              right: '-30px',
              display: 'flex',
              alignItems: 'center',
              fontSize: '12px'
            }}
          >
            <Box
              sx={{
                marginRight: '10px',
                display: 'flex',
                alignItems: 'center'
              }}
            >
              <Box
                sx={{
                  borderLeft: '8px solid transparent',
                  borderRight: '8px solid transparent',
                  borderBottom: '14px solid #FF4D4F',
                  width: 0,
                  height: 0,
                  display: 'inline-block'
                }}
              ></Box>
              <span
                style={{
                  paddingLeft: '4px'
                }}
              >
                最高
              </span>
            </Box>
            <Box
              sx={{
                display: 'flex',
                alignItems: 'center'
              }}
            >
              <Box
                sx={{
                  borderLeft: '8px solid transparent',
                  borderRight: '8px solid transparent',
                  borderTop: '14px solid #5087EC',
                  width: 0,
                  height: 0,
                  display: 'inline-block'
                }}
              ></Box>
              <span
                style={{
                  paddingLeft: '4px'
                }}
              >
                最小
              </span>
            </Box>
          </Box>
          <Box
            sx={{
              position: 'absolute',
              left: '50%',
              top: '10px'
            }}
          >
            {/* <span>℃</span> */}
          </Box>

          <Box
            sx={{
              position: 'absolute',
              width: 'calc(50% + 20px)',
              margin: 0,
              left: '50%',
            top: `calc(30px + ((100% - 50px) * (${MAX_TEMPERATURE_SOCPE}  - ${maxTemperature} + 10) / ${
                MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE + 10
              }))`,
              transition: 'top 0.3s ease'
            }}
          >
            <hr
              style={{
                position: 'relative',
                margin: 0,
                color: '#FF4D4F',
                border: 'none',
                borderTop:  '1px solid #FF4D4F' 
              }}
            />
            <Box
              sx={{
                position: 'absolute',
                left: 'calc(100% - 10px)',
                top: '-26px',
                borderLeft: '10px solid transparent',
                borderRight: '10px solid transparent',
                borderBottom:  '16px solid #FF4D4F' 
                width: 0,
                height: 0,
                display: 'flex',
                justifyContent: 'center',
                paddingBottom: '18px'
              }}
            >
              {parseFloat(String(maxTemperature)).toFixed(1)}
            </Box>
          </Box>

          <Box
            sx={{
              position: 'absolute',
              margin: 0,
              width: 'calc(50% + 20px)',
              left: '50%',
              top: `calc(30px + (100% - 50px) * (${MAX_TEMPERATURE_SOCPE}  - ${minTemperature} + 10) / ${
                MAX_TEMPERATURE_SOCPE - MIN_TEMPERATURE_SOCPE + 10
              })`,
              transition: 'top 0.3s ease'
            }}
          >
            <hr
              style={{
                position: 'relative',
                margin: 0,
                border: 'none',
                borderTop:  '1px solid #5087EC' 
              }}
            />
            <Box
              sx={{
                position: 'absolute',
                left: 'calc(100% - 10px)',
                top: '-8px',
                borderLeft: '10px solid transparent',
                borderRight: '10px solid transparent',
                borderTop:  '16px solid #5087EC'
                width: 0,
                height: 0,
                display: 'flex',
                justifyContent: 'center',
                paddingTop: '3px'
              }}
            >
              {parseFloat(String(minTemperature)).toFixed(1)}
            </Box>
          </Box>
          <TemperatureChart />
        </Box>
      }
    </Box>
  );
}

后言

在本文中,我们使用React 18EchartsMUI库展示了如何实现一个交互性的温度计。我们通过创建一个温度计组件,并使用Echarts库绘制温度计的外观。使用MUI库,我们创建了一个漂亮的用户界面来容纳温度计。如果不使用MUI,只需要把MUI相关标签改成HTML标签即可。

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

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

相关文章

MySQL - InnoDB 和 MyISAM 的索引实现的区别

InnoDB 和 MyISAM 底层都是 B 树的实现&#xff0c;但是二者却完全不同 。 主键索引文件存储不同 MyISAM 引擎的索引文件和数据文件是分离的&#xff0c;而 InnoDB 引擎的索引文件和数据文件是不分离的。 MyISAM 引擎的叶子节点存储的是数据文件的地址&#xff0c;而 InnoDB 的…

textarea文本框回车enter的时候自动提交表单,根据内容自动高度

切图网近期一个bootstrap5仿chatgpt页面的项目遇到的&#xff0c;textarea文本框回车enter的时候自动提交表单&#xff0c;根据内容自动高度&#xff0c;代码如下&#xff0c;亲测可用。 <textarea placeholder"Message ChatGPT…" name"" rows"&q…

Qt之Ui样式表不影响子类的配置

Qt之Ui样式表不影响子类的配置 问题 在ui界面上布局时&#xff0c;当对容器进行样试设计时&#xff0c;会对容器内其它成员对象也进行了修改 分析 对应*.ui文件内容 从这个写法来看&#xff0c;它的样式属性会影响其成员对象样式属性。 解决方法 在容器的样式表中写时适…

离散型随机变量的分布律(也称概率质量函数:probability mass function, PMF)

设是一个离散型随机变量&#xff0c;可能的取值为&#xff0c;取各个值的概率记为&#xff1a; &#xff08;1&#xff09; 其中 并且&#xff0c; 公式&#xff08;1&#xff09;就称为离散型随机变量的分布律&#xff0c;也称概率质量函数&#xff1a;probability ma…

前端怎么调用node接口---小白

1.基于node搭建express后端脚手架&#xff1a;基于node搭建express后端脚手架 2.在node里边写一个接口 // 引入express const express require(express) // 创建实例 const app express() // 创建监听端口 const port 3000 // 定义接口 app.get(/api/getData,(req,res) &g…

java 获取泛型T的class对象

问题描述 最近在封装es方法的时候遇到一个问题,就是泛型T怎么获取对应的class对象,代码如下: /*** Author: hrd* CreateTime: 2023/11/27 15:08* Description:*/ public interface IESIndex<R, P extends BaseModel> {/**** param p* param id 唯一ID* return*/IndexResp…

C#结合JavaScript实现多文件上传

目录 需求 引入 关键代码 操作界面 ​JavaScript包程序 服务端 ashx 程序 服务端上传后处理程序 小结 需求 在许多应用场景里&#xff0c;多文件上传是一项比较实用的功能。实际应用中&#xff0c;多文件上传可以考虑如下需求&#xff1a; 1、对上传文件的类型、大小…

风险评估是什么,为什么被称为保护网络安全的重要一环!

随着互联网的普及和信息技术的快速发展&#xff0c;网络已经成为人们生活和工作中不可或缺的一部分。然而&#xff0c;网络在为我们带来便利的同时&#xff0c;也存在着各种安全风险。因此&#xff0c;进行网络风险评估是保护网络安全的重要一环。而为什么说风险评估是保护网络…

2.2 C语言之常量

2.2 C语言之常量 一、常量 一、常量 类似于1234的整数常量属于int类型。 printf("%d\n", 1234);long类型的常量以l或L结尾 printf("%d\n", 123456789l);printf("%d\n", 123456789L);如果一个整数太大&#xff0c;以至于无法用int类型表示时&…

LINUX-ROS集成安装MQTT库步骤注意事项

环境信息 roottitan-ubuntu1:/home/mogo/data/jp/paho.mqtt.cpp# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS Release: 18.04 Codename: bionic 步骤 安装doxygen sudo apt install doxygen 构…

Tomcat从认识安装到详细使用

文章目录 一.什么是Tomact?二.Tomcat的安装1.下载安装包2.一键下载3.打开Tomcat进行测试4.解决Tomcat中文服务器乱码 三.Tomcat基本使用1.启动与关闭Tomcat2.Tomcat部署项目与浏览器访问项目 四.Tomcat操作中的常见问题1.启动Tomcat后&#xff0c;启动窗口一闪而过&#xff1f…

Day15——File类与IO流

1.java.io.File类的使用 1.1 File类的理解 File 类及本章下的各种流&#xff0c;都定义在 java.io 包下。一个 File 对象代表硬盘或网络中可能存在的一个文件或者文件目录&#xff08;俗称文件夹&#xff09;&#xff0c;与平台无关。&#xff08;体会万事万物皆对象&#xf…

金山终端安全系统V9.0 update_software_info_v2.php处SQL注入漏洞分析

文章目录 金山终端安全系统V9.0 update_software_info_v2.php处SQL注入漏洞分析前言一、漏洞描述二、影响版本三、POC四、漏洞原理分析参考链接&#xff1a; 金山终端安全系统V9.0 update_software_info_v2.php处SQL注入漏洞分析 前言 免责声明&#xff1a;请勿利用文章内的相…

idea 本身快捷键ctrl+d复制 无法像eclipse快捷键ctrl+alt+上下键,自动换行格式问题解决

问题 例如我使用ctrld 想复制如下内容 复制效果如下&#xff0c;没有自动换行&#xff0c;还需要自己在进行调整 解决 让如下快捷键第一个删除 修改成如下&#xff0c;将第二个添加ctrld 提示&#xff1a;对应想要修改的item&#xff0c;直接右键&#xff0c;remove是删…

Nginx反向代理跳过国内备案(以宝塔面板为例)

需要两台服务器&#xff0c;一台已备案或者免备案&#xff0c;一台国内主力服务器放你的项目。 先把域名解析到A服务器 然后在A服务器里配置 server {listen 80;server_name 你的域名;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_…

(3)kylin系统部署weblogic项目

一、jdk迁移 1、拷贝成功后要配置环境变量 vi /etc/profile 将jdk的目录添加进去 2、将jdk安装目录拷贝后权限会发生变化&#xff0c; 要对jdk下bin目录中的所有文件修改权限&#xff1a; chmod x ./* 回车即可 ----------------------------- 环境变量 export …

ES6原生音乐播放器(有接口)

视频展示 ES6音乐播放器 项目介绍 GutHub地址&#xff1a;GitHub - baozixiangqianchong/ES6_MusicPlayer: 音乐播放器 ES6_MusicPlayer 是基于JavaScriptES6Ajax等通过原生构建的项目。能够充分锻炼JS能力。 本项目有主页、详情页、歌单页面三部分组成 ├── assets&…

多维时序 | MATLAB实现RIME-CNN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测

多维时序 | MATLAB实现RIME-CNN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现RIME-CNN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现RIME-…

编程学新要求:OS发布之前,都应该在各种虚拟机上测试

这几天在VirtualBox上安装ArchLinux&#xff0c;掌握了方法之后&#xff0c;非常顺利。进入桌面之后&#xff0c;又出问题了&#xff0c;如下图&#xff1a; 底部的那个工具条&#xff0c;空空如也。原因是显示错误。这怎么用&#xff1f; 所以编程学干脆提出一个新要求&#x…