二十(GIT3)、echarts(折线图、柱状图、饼图)、黑马就业数据平台(主页图表实现、闭包了解、学生信息渲染)

1. echarts

数据可视化:将数据转换为图形,数据特点更加突出

echarts:一个基于 JavaScript 的开源可视化图表库 

echarts官网

1.1 echarts核心使用步骤

// 1. 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(dom元素);

// 2. 指定图表的配置项和数据
const option = {
  // ...
};

// 3. 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);

1.2 折线图

// todo: 2022全学科薪资走势 折线图
// ? 折线粗细、点大小、x轴虚线、提示框(已解决)
function renderYear(year) {
  // 省略大括号 {} 和 return 关键字(适用于单行表达式)
  const months = year.map((item) => item.month);
  const salarys = year.map((item) => item.salary);
  // console.log(months, salarys);

  const myChart = echarts.init(document.querySelector("#line"));
  const option = {
    // 标题组件
    title: {
      text: "2022全学科薪资走势",
      // top、left..: 可设置title 组件离容器x侧的距离。
      top: 20,
      left: "2%",
    },
    // 直角坐标系内绘图网格
    grid: {
      top: "20%",
    },
    // 提示框组件
    tooltip: {
      // axis 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
      trigger: "axis",
    },
    // x轴
    xAxis: {
      // 坐标轴类型 value数值轴、category类目轴..
      type: "category",
      data: months,
      // 坐标轴轴线
      axisLine: {
        lineStyle: {
          color: "#9c9c9c",
          // 线的类型:实线solid、虚线、点线dotted
          type: "dashed",
        },
      },
      // x轴在 grid 区域中的分隔线
      /* splitLine: {
        show: true,
        lineStyle: {
          type: "dashed",
        },
      }, */
    },
    // y轴
    yAxis: {
      type: "value",
      // y轴在 grid 区域中的分隔线
      splitLine: {
        lineStyle: {
          // 分隔线的类型
          type: "dashed",
        },
      },
    },
    // 系列列表
    series: [
      {
        data: salarys,
        // 折线/面积图
        type: "line",
        smooth: true,
        // 区域填充样式。设置后显示成区域面积图。
        areaStyle: {
          // 线性渐变,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比,
          // 如果 globalCoord 为 `true`,则该四个值是绝对的像素位置
          color: {
            type: "linear",
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              {
                offset: 0,
                color: "#88BDF1", // 0% 处的颜色
              },
              {
                offset: 1,
                color: "rgba(255,255,255,0)", // 100% 处的颜色
              },
            ],
            global: false, // 缺省为 false
          },
        },
        // 线条样式
        lineStyle: {
          width: 7, // 线宽
          color: {
            type: "linear",
            x: 0,
            y: 0,
            x2: 1,
            y2: 0,
            colorStops: [
              {
                offset: 0,
                color: "#4897E7", // 0% 处的颜色
              },
              {
                offset: 1,
                color: "#5975EC", // 100% 处的颜色
              },
            ],
            global: false, // 缺省为 false
          },
        },
        // 标记的大小
        symbolSize: 10,
      },
    ],
  };
  myChart.setOption(option);
}

1.3 双柱状图

// todo:班级每组薪资 双柱状图
function renderGroupData(groupData) {
  // 班级平均薪资默认渲染第一组的 后面点击更换组别 多次使用 → 封装函数
  // console.log(groupData);
  // console.log(groupData instanceof Object); // true
  // console.log(groupData instanceof Array); // false
  // groupData是对象 键是数字(1到8)

  // ! 1. 直接封装函数后调用:这种方法简单直接,每次点击按钮时重新渲染整个图表。
  // ! 虽然实现起来比较方便,但可能会带来性能问题,特别是在数据量较大或图表比较复杂的情况下。

  // ! 2. 更改配置项数据,再次调用 myChart.setOption(option) 这种方法更高效,
  // ! 因为 ECharts 提供了一些 API 来更新图表的数据,而不需要完全重新初始化图表。这通常比重新创建图表要快得多,尤其是在数据量大的情况下。

  // * 对象的键可以是字符串或数字 groupData[1] 等价于 groupData["1"]
  // function renderGroup(group) {
  /* const getData = groupData[1].map((item) => {
    const { name, hope_salary, salary } = item;
    return [name, hope_salary, salary];
  }); */
  // console.log(getData);

  const myChart = echarts.init(document.querySelector("#lines"));
  const option = {
    // legend: {},
    tooltip: {},
    dataset: {
      source: [
        ["薪资", "期望薪资", "就业薪资"],
        ...groupData[1].map((item) => {
          const { name, hope_salary, salary } = item;
          return [name, hope_salary, salary];
        }),
      ],
    },
    xAxis: {
      type: "category",
      axisLine: {
        lineStyle: {
          color: "#9c9c9c",
          type: "dashed",
        },
      },
    },
    yAxis: {
      splitLine: {
        lineStyle: {
          type: "dashed",
        },
      },
    },
    series: [
      {
        type: "bar",
        itemStyle: {
          color: {
            type: "linear",
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              {
                offset: 0,
                color: "#3CD59E", // 0% 处的颜色
              },
              {
                offset: 1,
                color: "rgba(255,255,255,0.5)", // 100% 处的颜色
              },
            ],
            global: false, // 缺省为 false
          },
        },
      },
      {
        type: "bar",
        color: {
          type: "linear",
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          colorStops: [
            {
              offset: 0,
              color: "#56B1FF", // 0% 处的颜色
            },
            {
              offset: 1,
              color: "rgba(255,255,255,0.5)", // 100% 处的颜色
            },
          ],
          global: false, // 缺省为 false
        },
      },
    ],
    // color: ["#68DEB4", "#77B7F2"],
  };
  myChart.setOption(option);
  // }
  // renderGroup(1);

  document.querySelector("#btns").addEventListener("click", function (e) {
    if (e.target.nodeName === "BUTTON") {
      // console.log("button");
      // console.log(e.target.innerText);
      document.querySelector(".btn-blue").classList.remove("btn-blue");
      e.target.classList.add("btn-blue");
      // renderGroup(e.target.innerText);
      // 更改配置项数据
      option.dataset.source = [
        ["姓名", "期望薪资", "就业薪资"],
        ...groupData[e.target.innerText].map((item) => {
          const { name, hope_salary, salary } = item;
          return [name, hope_salary, salary];
        }),
      ];
      myChart.setOption(option);
    }
  });
}

1.4 饼状图

// todo: 班级薪资分布 饼图
function renderSalaryDataClass(salaryData) {
  // 箭头函数省略return简写时,返回值若为对象{},需使用小括号()包裹
  const data = salaryData.map((item) => ({
    value: item.g_count + item.b_count,
    name: item.label,
  }));
  /* const data = salaryData.map((item) => {
    return { value: item.g_count + item.b_count, name: item.label };
  }); */
  // console.log(data);

  const myChart = echarts.init(document.querySelector("#salary"));
  const option = {
    title: {
      text: "班级薪资分布",
      top: 15,
      left: 15,
    },
    // 提示框
    tooltip: {
      trigger: "item",
    },
    // 图例组件
    legend: {
      bottom: "5%",
      left: "center",
    },
    // 系列列表
    series: [
      {
        name: "班级薪资分布",
        type: "pie",
        // 饼图大小
        radius: ["50%", "70%"],
        avoidLabelOverlap: false,
        // 饼图小扇区的边框设置 圆角颜色宽度等
        itemStyle: {
          borderRadius: 10,
          borderColor: "#fff",
          borderWidth: 2,
        },
        // 饼图标签文字 默认为true 显示
        label: {
          show: false,
          // 标签文字位置
          // position: "center",
        },
        // 饼图标签文字与饼图的连接线
        /* labelLine: {
          show: false,
        }, */
        // 高亮状态的扇区和标签样式 (悬停时所处数据中间高亮)
        /* emphasis: {
          label: {
            show: true,
            fontSize: 40,
            fontWeight: "bold",
          },
        }, */
        data,
      },
    ],
    color: ["#FDA224", "#5097FF", "#3ABCFA", "#34D39A"],
  };
  myChart.setOption(option);
}

1.5 双饼图

// todo: 男女薪资分布 双饼图
function renderSalaryDataGender(salaryData) {
  const myChart = echarts.init(document.querySelector("#gender"));
  const option = {
    title: [
      {
        text: "男女薪资分布",
        left: 10,
        top: 10,
        textStyle: {
          fontsize: 16,
        },
      },
      {
        text: "男生",
        left: "45%",
        top: "45%",
        textStyle: {
          fontsize: 12,
        },
      },
      {
        text: "女生",
        left: "45%",
        top: "88%",
        textStyle: {
          fontsize: 12,
        },
      },
    ],
    tooltip: {
      trigger: "item",
    },
    series: [
      {
        type: "pie",
        radius: ["25%", "40%"],
        //  center 属性来控制每个饼图的位置
        center: ["50%", "30%"],
        avoidLabelOverlap: false,
        label: {
          show: true,
        },
        labelLine: {
          show: true,
        },
        data: salaryData.map((item) => ({
          value: item.b_count,
          name: item.label,
        })),
      },
      {
        type: "pie",
        radius: ["25%", "40%"],
        center: ["50%", "70%"],
        avoidLabelOverlap: false,
        label: {
          show: true,
        },
        labelLine: {
          show: true,
        },
        data: salaryData.map((item) => ({
          value: item.g_count,
          name: item.label,
        })),
      },
    ],
    color: ["#FDA224", "#5097FF", "#3ABCFA", "#34D39A"],
  };
  myChart.setOption(option);
}

2. 黑马就业数据平台

2.1 index.js

初始代码(不完整)

// 调用函数 判断是否有token
checkLogin();

// 渲染用户名
renderName(1);

// 退出登录
logout();

// ? 可以使用 async await 从后台只获取一次数据吗? 图表直接使用
// ? 外面套函数?
// * getRes 是一个异步函数,返回一个 Promise 对象。
// * 调用 getRes 时,如果不使用 await,会得到一个未解决的 Promise 对象。
// * 使用 await 可以等待 Promise 被解决,并将解决后的值赋给变量。
// * await 关键字只能在 async 函数内部使用。不能直接在 return 语句中使用 await
// ! 为了实现每次调用 getRes 函数时只向网络请求一次数据,并且能够根据传入的参数获取解构出来的一条数据,
// ! 可以使用一个闭包来缓存第一次请求的数据。这样,后续的调用将直接从缓存中获取数据,而不需要再次进行网络请求。
// const { groupData, overview, provinceData, salaryData, year } = res.data;
function outer() {
  let cacheData = null;
  return async function inner(name) {
    if (!cacheData) {
      const res = await axios.get("/dashboard");
      cacheData = res.data;
    }
    return cacheData[name];
  };
}
// * getRes === outer() === inner === inner(){}
const getRes = outer();

// todo:统计数据区域
(async function () {
  // const token = localStorage.getItem("token");
  // * common.js 已添加请求(统一设置token)和响应拦截器(统一处理token失效问题) → catch部分代码移除,try catch注释
  // try {
  /* const res = await axios.get("/dashboard", {
      // * 请求头参数:校验是否登录
      headers: { Authorization: token },
    }); */
  // const res = await axios.get("/dashboard");
  // console.log(res);
  // const { groupData, overview, provinceData, salaryData, year } = res.data;
  // const { overview } = res.data;
  const overview = await getRes("overview");
  // console.log(overview);

  // console.log(overview);
  Object.keys(overview).forEach((key) => {
    document.querySelector(`.${key}`).innerHTML = overview[key];
  });
  // } catch (error) {
  // console.dir(error);
  // console.log(error.response.status); // 401

  // 401 token验证失败(token过期或被恶意篡改)
  // todo:跳转到登录页面重新登陆,本地存储数据清除
  /* if (error.response.status === 401) {
      showToast("登陆失败,请重新登录");
      localStorage.removeItem("username");
      localStorage.removeItem("token");
      // 延迟跳转登陆页面
      setTimeout(() => {
        location.href = "./login.html";
      }, 1500);
    } */
  // }
})();

// * 多个图表需写入页面 → 立即执行函数,解决可能存在的变量名冲突问题
// todo: 柱状图 班级每组薪资
(async function () {
  // const res = await axios.get("/dashboard");
  // console.log(res.data);
  // const { groupData } = res.data;
  const groupData = await getRes("groupData");

  const myChart = echarts.init(document.querySelector("#lines"));
  const option = {
    tooltip: {},
    dataset: {
      source: [
        ["薪资", "期望薪资", "就业薪资"],
        ...groupData[1].map((item) => {
          const { name, hope_salary, salary } = item;
          return [name, hope_salary, salary];
        }),
      ],
    },
    xAxis: {
      type: "category",
      axisLine: {
        lineStyle: {
          color: "#9c9c9c",
          type: "dashed",
        },
      },
    },
    yAxis: {
      splitLine: {
        lineStyle: {
          type: "dashed",
        },
      },
    },
    series: [
      {
        type: "bar",
        itemStyle: {
          color: {
            type: "linear",
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              {
                offset: 0,
                color: "#3CD59E", // 0% 处的颜色
              },
              {
                offset: 1,
                color: "rgba(255,255,255,0.5)", // 100% 处的颜色
              },
            ],
            global: false, // 缺省为 false
          },
        },
      },
      {
        type: "bar",
        color: {
          type: "linear",
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          colorStops: [
            {
              offset: 0,
              color: "#56B1FF", // 0% 处的颜色
            },
            {
              offset: 1,
              color: "rgba(255,255,255,0.5)", // 100% 处的颜色
            },
          ],
          global: false, // 缺省为 false
        },
      },
    ],
  };
  myChart.setOption(option);

  document.querySelector("#btns").addEventListener("click", function (e) {
    if (e.target.nodeName === "BUTTON") {
      document.querySelector(".btn-blue").classList.remove("btn-blue");
      e.target.classList.add("btn-blue");
      // 更改配置项数据
      option.dataset.source = [
        ["姓名", "期望薪资", "就业薪资"],
        ...groupData[e.target.innerText].map((item) => {
          const { name, hope_salary, salary } = item;
          return [name, hope_salary, salary];
        }),
      ];
      myChart.setOption(option);
    }
  });
})();

2.2 getData

向服务器请求数据 解构 调用函数 传参 (后四个函数在本章1.2-1.5)

// todo:统计数据区域
async function getData() {
  const res = await axios.get("/dashboard");
  const { groupData, overview, provinceData, salaryData, year } = res.data;

  // console.log(salaryData);

  renderOverview(overview);
  renderGroupData(groupData);
  renderYear(year);
  renderSalaryDataClass(salaryData);
  renderSalaryDataGender(salaryData);
}

getData();

function renderOverview(overview) {
  Object.keys(overview).forEach((key) => {
    document.querySelector(`.${key}`).innerHTML = overview[key];
  });
}

2.3 student.js

学生信息渲染

// 调用函数 判断是否有token(登录校验)
checkLogin();

// 渲染用户名
renderName(1);

// 退出登录
logout();

// * 渲染学生信息 增删改之后需再次渲染 → 封装函数
// * 获取服务器学生列表 并渲染到页面
async function render() {
  // 已设置请求拦截器
  const res = await axios.get("/students");
  const str = res.data
    .map((item) => {
      const {
        id,
        name,
        age,
        gender,
        group,
        hope_salary,
        salary,
        province,
        city,
        area,
      } = item;
      return `
        <tr>
          <td>${name}</td>
          <td>${age}</td>
          <td>${gender === 0 ? "男" : "女"}</td>
          <td>第${group}组</td>
          <td>${hope_salary}</td>
          <td>${salary}</td>
          <td>${province + city + area}</td>
          <td>
            <a href="javascript:;" class="text-success mr-3"><i class="bi bi-pen" data-id="${id}"></i></a>
            <a href="javascript:;" class="text-danger"><i class="bi bi-trash" data-id="${id}"></i></a>
          </td>
        </tr>
      `;
    })
    .join("");
  document.querySelector(".list").innerHTML = str;
  document.querySelector(".total").innerHTML = res.data.length;
}
render();

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

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

相关文章

软考高级架构-9.4.4-双机热备技术 与 服务器集群技术

一、双机热备 1、特点&#xff1a; 软硬件结合&#xff1a;系统由两台服务器&#xff08;主机和备机&#xff09;、一个共享存储&#xff08;通常为磁盘阵列柜&#xff09;、以及双机热备软件&#xff08;提供心跳检测、故障转移和资源管理功能的核心软件&#xff09;组成。 …

【Java若依框架】RuoYi-Vue的前端和后端配置步骤和启动步骤

&#x1f399;告诉你&#xff1a;Java是世界上最美好的语言 &#x1f48e;比较擅长的领域&#xff1a;前端开发 是的&#xff0c;我需要您的&#xff1a; &#x1f9e1;点赞❤️关注&#x1f499;收藏&#x1f49b; 是我持续下去的动力&#xff01; 目录 一. 作者有话说 …

Kubernetes Nginx-Ingress | 禁用HSTS/禁止重定向到https

目录 前言禁用HSTS禁止重定向到https关闭 HSTS 和设置 ssl-redirect 为 false 的区别 前言 客户请求经过ingress到服务后&#xff0c;默认加上了strict-transport-security&#xff0c;导致客户服务跨域请求失败&#xff0c;具体Response Headers信息如下&#xff1b; 分析 n…

小程序入门学习(八)之页面事件

一、下拉刷新新事件 1. 什么是下拉刷新 下拉刷新是移动端的专有名词&#xff0c;指的是通过手指在屏幕上的下拉滑动操作&#xff0c;从而重新加载页面数据的行为。 2. 启用下拉刷新 启用下拉刷新有两种方式&#xff1a; 全局开启下拉刷新&#xff1a;在 app.json 的 window…

C++(十二)

前言&#xff1a; 本文将进一步讲解C中&#xff0c;条件判断语句以及它是如何运行的以及内部逻辑。 一&#xff0c;if-else,if-else语句。 在if语句中&#xff0c;只能判断两个条件的变量&#xff0c;若想实现判断两个以上条件的变体&#xff0c;就需要使用if-else,if-else语…

[Linux]文件属性和权限

目录 一.Linux文件的属性二.Linux用户权限分类三.文件权限的查询与修改1.修改用户的权限1).一般法2).8进制法 2.修改所属组和所属者3.如何在创建文件时权限预分配 在学习linux的时候&#xff0c;我们用ll命令显示文件的详情信息&#xff0c;难免会发现文件名前面会有一大堆其它…

ElK 8 收集 MySQL 慢查询日志并通过 ElastAlert2 告警至飞书

文章目录 1. 说明2. 启个 mysql3. 设置慢查询4. filebeat 设置5. 触发慢查询6. MySQL 告警至飞书 1. 说明 elk 版本&#xff1a;8.15.0 2. 启个 mysql docker-compose.yml 中 mysql&#xff1a; mysql:# restart: alwaysimage: mysql:8.0.27# ports:# - "3306:3306&q…

springSecurity权限控制

权限控制&#xff1a;不同的用户可以使用不同的功能。 我们不能在前端判断用户权限来控制显示哪些按钮&#xff0c;因为这样&#xff0c;有人会获取该功能对应的接口&#xff0c;就不需要通过前端&#xff0c;直接发送请求实现功能了。所以需要在后端进行权限判断。&#xff0…

力扣打卡9:重排链表

链接&#xff1a;143. 重排链表 - 力扣&#xff08;LeetCode&#xff09; 这是一道操作链表的题。按照要求&#xff0c;我们可以将解题的步骤分成三步。 1.找链表中间结点&#xff08;我使用了快慢指针寻找&#xff09;&#xff0c;并断开。 2.现在有2链表&#xff0c;将后段…

计算机键盘的演变 | 键盘键名称及其功能 | 键盘指法

注&#xff1a;本篇为 “键盘的演变及其功能” 相关几篇文章合辑。 英文部分机翻未校。 The Evolution of Keyboards: From Typewriters to Tech Marvels 键盘的演变&#xff1a;从打字机到技术奇迹 Introduction 介绍 The keyboard has journeyed from a humble mechanical…

【Appium报错】安装uiautomator2失败

目录 1、通过nmp安装uiautomator2&#xff1a;失败 2、通过 Appium 的平台直接安装驱动程序 3、通过pip 来安装 uiautomator2 1、通过nmp安装uiautomator2&#xff1a;失败 我先是通过npm安装的uiautomator2&#xff0c;也显示已经安装成功了&#xff1a; npm install -g …

SSM整合原理实战案例《任务列表案例》

一、前端程序搭建和运行: 1.整合案例介绍和接口分析: (1).案例功能预览: (2).接口分析: 学习计划分页查询 /* 需求说明查询全部数据页数据 请求urischedule/{pageSize}/{currentPage} 请求方式 get 响应的json{"code":200,"flag":true,"data&…

Chrome扩展程序开发示例

项目文件夹内文件如下&#xff1a; manifest.json文件内容&#xff1a; {"manifest_version": 3,"name": "我的法宝","description": "我的有魔法的宝贝","version": "1.0","icons": {"…

石头剪子布

石头剪子布 C语言实现C实现Java实现Python实现 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 石头剪子布&#xff0c;是一种猜拳游戏。起源于中国&#xff0c;然后传到日本、朝鲜等地&#xff0c;随着亚欧贸易的不断发展它传到了欧洲&…

RabbitMQ核心概念及工作流程 + AMQP

文章目录 一. RabbitMQ核心概念1. Producer, Consumer, Broker2. Connection和Channel3. Virtual host4. Queue5. Exchange 二. RabbitMQ的工作流程三. AMQP四. web界面操作对用户操作对虚拟机操作 一. RabbitMQ核心概念 RabbitMQ是⼀个消息中间件, 也是⼀个⽣产者消费者模型.…

js循环导出多个word表格文档

文章目录 js循环导出多个word表格文档一、文档模板编辑二、安装依赖三、创建导出工具类exportWord.js四、调用五、效果图js循环导出多个word表格文档 结果案例: 一、文档模板编辑 二、安装依赖 // 实现word下载的主要依赖 npm install docxtemplater pizzip --save// 文件操…

字节高频算法面试题:小于 n 的最大数

问题描述&#xff08;感觉n的位数需要大于等于2&#xff0c;因为n的位数1的话会有点问题&#xff0c;“且无重复”是指nums中存在重复&#xff0c;但是最后返回的小于n最大数是可以重复使用nums中的元素的&#xff09;&#xff1a; 思路&#xff1a; 先对nums倒序排序 暴力回…

windows11 实现Hyper-v ubuntu22.04 GPU虚拟化(GPU分区、GPU-P)教程

注:1、本文提到的vGPU、GPU分区都是指的微软的GPU-P技术。 2、在实操过程中,发现网上的很多文章要么记录不全,要么描述不清楚,导致的结果就是根本没法走通。希望通过该文章能解决小伙伴们在实操中遇到的一些坑。 前提说明 1、物理机需要支持SR-IOV,在主板BIOS中可以通过…

AndroidStudio-常见界面控件

一、Button package com.example.review01import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Button import android.widget.TextViewclass Review01Activity : AppCompatActivity() {override fun onCreate(savedInstanceStat…

沐风老师3DMAX摄相机阵列插件使用方法

3DMAX摄相机阵列插件&#xff0c;从网格对象或样条线的顶点法线快速创建摄相机阵列。该插件从网格的顶点或样条线的节点获取每个摄影机的位置和方向。 3DMAX摄相机阵列插件支持目前3dMax主流的物理相机、标准相机、VRay物理相机。 【版本要求】 3dMax 2015及更高版本 【安装方…