用three.js+echarts给公司写了一个站点数据大屏系统经验总结


时间过的好快,参加公司的新项目研发快一年了,五一机器人项目首秀,我们遇到了高并发集中下单情景,然后海量数据处理场景来了,给我在后端领域的高并发实践业务上画上了漂亮的一笔经验。人都是在磨练中成长,我很感谢这次给我的机会,虽然有点累,但也有点小成就。正好现在有空,我先聊聊首秀后给领导们做的大屏数据展示吧,领导等着看漂亮数据呢!

大屏重点是贼啦炫酷的动态特效加持

业务核心运营场景:各大地上地下停车场

这里我用的是three.js去实现的实际业务场景的场站模拟三维图,废话不多说,直接上图吧!先说一下,这里截图是看起来像2维,但实际是3维的,可以滑动翻转地图的。

截屏2024-05-07 18.35.07.png

如图所示,这是p4停车场的全景图,整个停车场的鸟瞰图一览无余,可以滚动鼠标放大看====》

这是我用three.js渲染的每个停车位的车位标记,这里记录了这个车场的每个车位的坐标点,方便后期,观察我们投放的100台机器人智能驾驶实时模拟。听起来是不是很牛逼plus?我告诉你,事情没那么简单!由于数据太多,既要有3D-map,也要有实时动态数据滚动展示和各种echarts图表,比如:

4A71FC88-CCB1-4DD4-82B9-612DE98328B8.png
ps:不好意思,本人还要严格遵守劳动合同执行公司数据保密,相关数据已经打码。

然后一堆实时数据数据和图上来后,不出意外的意外来了,性能出现了问题,我遇到了内存泄漏的情况。这还怎么继续二期的机器人动态运行场景研发呢?别慌,一步一步排查代码。

1.先介绍下大屏顶部的总数统计动态数字翻牌器

这里我用了第三方插件:动态数字翻牌器vue-count-to,只要有数据变化,就会实时看到动态增长的效果

首先要在框架中安装npm install vue-count-to,并在项目入口文件中引入

import CountTo from 'vue-count-to';
Vue.use(CountTo)
new Vue({
   
  el: '#app',
  router,
  store,
  render: h => h(App)
})

实际业务开发模块中代码:

                <count-to
                    class="count-to"
                    :startVal="0" //开始数值
                    :endVal="687573.74" //结束数值
                    :duration="500000" //动态变化的时间设定
                    :decimals="1"  //每次动态增长的数量
                ></count-to>

2.然后在大屏的左侧,我写了一个实时从下到上无限滚动的动态订单列表,可以让领导看到最新的订单情况。


<template>
    <div class="scrolling-list" :style="{ transform: `translate(0px,-${scrollTop}px)` }">
      <ul ref="scrollItemBox">
        <li v-for="(item, index) in items" :key="index" class="item-li">
            <div><span class="name">订单编号:</span><span class="content"><i class="el-icon-receiving">  {
   {
    item.order_id }}</i></span></div>
            <div><span class="name">订单金额:</span><span class="content"><i class="el-icon-s-finance" style="color:#1989fa" >  {
   {
    item.pre_total_amount }}</i></span><span class="name">手机号:</span><span class="content"><i class="el-icon-mobile-phone" style="color:#1989fa">  {
   {
    item.phone }}</i></span></div>
            <div><span class="name">车牌号:</span><span class="content"> <i class="el-icon-truck" style="color:#1989fa">  {
   {
    item.vehicle_no }}</i></span><span class="name">车位号:</span><span class="content"><i class="el-icon-map-location" style="color:#1989fa">  {
   {
    item.target_slot_no }}</i></span></div>
            <div><span class="name">订单来源:</span><span class="content">{
   {
    item.order_from == 1 ? '小程序' : 'APP' }}</span><span class="name">下单时间:</span><span class="content"><i class="el-icon-time">  {
   {
    item.created_at }}</i></span></div>
        </li>
      </ul>
      <div v-html="copyHtml"></div>
    </div>
</template>
<script>
  
  export default {
   
    
  data() {
   
      return {
   
        name: "InfiniteScroll",
        scrollTop: 0, //列表滚动高度
        speed: 15, //滚动的速度
        copyHtml: '',
        items:[],
        intervalId: null
      };
    },
  mounted() {
   
    this.initScroll()
  },
  beforeDestroy() {
   
    // 清除定时任务
      clearInterval(this.intervalId);
    },
  methods: {
   
     initScroll() {
   
            this.$nextTick(() => {
   
                this.copyHtml = this.$refs.scrollItemBox.innerHTML
                this.startScroll()
            })
      },
      // 开始滚动
      startScroll() {
   
          setInterval(this.scroll, this.speed);
      },
      // 滚动处理方法
      scroll() {
   
            this.scrollTop++
            // 获取需要滚动的盒子的高度
            let scrollItemBox = this.$refs.scrollItemBox?.offsetHeight || 1000
            // 当判断滚动的高度大于等于盒子高度时,从头开始滚动
            if (this.scrollTop >= scrollItemBox) {
   
                this.scrollTop = 0
            }
      }
    }
  };
  </script>

3.然后在大屏的右侧,用echarts写了两个饼图和折线图表,可以直观的的看到数据统计


export const timeStaticsOption = (xData,tipsArr) => {
   
  return {
   
    title: {
   
      text: '',
      subtext:'当天时间段充电订单数',
      subtextStyle:{
   
        color:'#fff',
      }
    },
    tooltip: {
   
      trigger: 'axis',
      axisPointer: {
   
        type: 'cross'
      }
    },
    xAxis: {
   
      type: 'category',
      data: xData,
      boundaryGap: false,
      axisLine: {
   
        show: false,
        lineStyle: {
   
          color: '#73B131',
          type: 'dashed'
        }
      },
    },
    yAxis: {
   
      type: 'value',
      axisPointer: {
   
        snap: true
      }
    },
    series: [
      {
   
        name: '时间段充电订单数',
        type: 'line',
        smooth: true,
        data: tipsArr,
      }
    ]
  }
}
export const botDataPieEcharts = (total,a,b)=>{
   
  console.log(total,a,b)
  return {
   
    title: {
   
      text: '',
      subtext: "Bot总数:"+ total+ '台',
      left: 'center',
      subtextStyle:{
   
        color:'#fff',
      }
    },
    tooltip: {
   
      trigger: 'item'
    },
    // legend: {
   
    //   orient: 'vertical',
    //   left: 'left'
    // },
    series: [
      {
   
        name: 'Bot数量',
        type: 'pie',
        radius: '50%',
        data: [
          {
    value: a, name: '在线:'+ a +'台' },
          {
    value: b, name: '空闲:'+ b +'台'},
        ],
        emphasis: {
   
          itemStyle: {
   
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)'
          }
        }
      }
    ]
  }
}

4.最后也是最耗性能的部分,用three.js写的停车场模拟实景鸟瞰图,3d-map

这里我直接把相关的方法和类,全部封装好,单独引入文件,用到以下文件,

import '../public/threejs/controls/OrbitControls.js'; 
import '../public/threejs/lines/LineSegmentsGeometry.js';
import '../public/threejs/lines/LineGeometry.js';
import '../public/threejs/lines/LineMaterial.js';
import '../public/threejs/lines/LineSegments2.js';
import '../public/threejs/lines/Line2.js';

在业务中相关代码写好工具方法,

import myWorker from './map.worker';
import FONT_JSON_DATA from './helvetiker_bold.typeface.json';
class basicThree {
   
    constructor(props) {
   
        this.from = props.from
        this.callbackSlotNo = props.callback
        console.log(props, 'props')
        this.LineGeometry
        // three 3要素
        this.renderer; //渲染器
        this.camera; //摄像头
        this.scene; //场景
        //光源
        this.ambientLight; //环境光
        this.pointLight; //平行光
        this.DirectionalLight
        //触屏开始时间
        this.touchTime = 0
        //摄像头控制
        this.controls;
        this.init()
        this.onmousedbclick = this.onMouseDblclick.bind(this);
        this.selectObject
        this.rawOption
        this.materialLine = Object()
        this.box = document.createElement("div")

        this.donX
        this.donY
        this.dataNumber
        this.originX; // 偏移量x坐标
        this.originZ; // 偏移量z坐标
        this.thinLine;
        this.wideLine;

        // 定义模型组
        this.initModalGroup();

        this.mapParams;

        this.drawModalFunc = {
   
            '0': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 0
            },
            '1': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 0
            },
            '2': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 2
            },
            '3': {
   
                'func': this.initNoAndArea.bind(this),
                'group': null,
                'z': 3
            },
            '4': {
   
                'func': this.basicWall.bind(this),
                'group': 'barrier_group',
                'z': 3
            },
            '5': {
   
                'func': this.initSlotLine.bind(this),
                'group': 'initSlotLine_group',
                'z': 3
            },
            '6': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 3
            },
            '7': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 3
            },
            '8': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 3
            },
            '9': {
   
                'func': this.initSlotLine.bind(this),
                'group': 'initSlotLine_group',
                'z': 3
            },
            '10': {
   
                'func': this.initSlotLine.bind(this),
                'group': 'initSlotLine_group',
                'z': 3
            },
            '11': {
   
                'func': this.RoadLineSigns.bind(this),
                'group': 'RoadLineSigns_group',
                'z': 3
            },
            '13': {
   
                'func': this.initSlotLine.bind(this),
                'group': 'initSlotLine_group',
        

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

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

相关文章

基于RK3568核心板的雷视融合一体机,助力交通管理智能化升级

随着5G网络与智慧交通车路协同系统在全国各点的落地&#xff0c;作为提升交通安全的前沿技术方案也愈发受到重视。 在交通信控领域&#xff0c;以往的感知技术、无论是地磁、线圈还是摄像头&#xff0c;功能都仅仅局限于数清经过了多少车辆&#xff0c;无法满足交通数字化管理…

aosp14的分屏接口ISplitScreen接口获取方式更新-学员疑问答疑

背景&#xff1a; 有学员朋友在学习马哥的分屏pip自由窗口专题时候&#xff0c;做相关分屏做小桌面项目时候&#xff0c;因为原来课程版本是基于android 13进行的讲解的&#xff0c;但是现在公司已经开始逐渐进行相关的android 14的适配了&#xff0c;但是android 14这块相比a…

挖矿宝藏之系统日志

什么是日志&#xff1f; 日志是指系统或应用程序在运行过程中产生的记录文件&#xff0c;这些文件记录了系统或应用程序的运行情况、错误信息、用户操作等。 日志的主要作用 记录信息&#xff1a;日志可以记录系统或应用程序的启动、运行、停止等状态信息&#xff0c;以及用户的…

sourcetree推送到git上面

官网&#xff1a;Sourcetree | Free Git GUI for Mac and Windows 下载到1次提交 下载后打开 点击跳过 下一步 名字邮箱 点击clone 把自己要上传的代码粘贴到里面去 返回点击远程->点击暂存所有 加载完毕后&#xff0c;输入提交内容提交 提交完成了 2次提交 把文件夹内的…

java方法负载问题

先介绍一下方法的重载 下面是例子 方法名都为sum而形参是不同的 记住&#xff01; 是否为重载关系 1在同一个类里面 2形参不同&#xff08;与返回值无关&#xff09; 3方法名一样 第一个图为什么错&#xff1f; 答案&#xff1a;虽然在同一个类里面&#xff0c;并且方法名…

Istio ICA考试之路---5-2

Istio ICA考试之路---5-2 1. 题目2. 解题3. 容易遇见的错误3.1 错误13.2 错误2 1. 题目 Using Kubernetes context cluster-2 The httpbin workload is running with a client named sleep in the troubleshoot-1 namespace. Issue a service call from the sleep client.ku…

单条16g和双条8g哪个好

单条16g和双条8g各有优劣,具体选择要根据个人需求和电脑配置来决定。 以下是一些参考信息: •单条16g内存的价格比双条8g内存的价格低,而且16g的内存容量大,一条内存十分的方便。 •两条8g内存可以组成双通道,电脑运行速度要快一些。 •对于普通使用电脑的人群与热衷于…

ubuntu安装Stable Video Diffusion(SVD)让图片动起来

目录 写在前面 一、克隆或下载项目 二、下载预训练模型 三、创建环境 四、安装依赖 五、启动项目 六、解决报错 1.预训练模型下不来 2.TiffWriter.write() got an unexpected keyword argument fps 3.安装ffmpeg 4.No module named scripts 七、测试 写在前面 Stab…

一、Servlet和JSP技术概述

注&#xff1a;该系列笔记是用于我在 《Servlet 与 JSP 核心编程》这本书中的学习笔记&#xff0c;无其他意思&#xff0c;侵权请联系2082045221qq.com删除。 ​ 第一章内容较少&#xff0c;所以暂时有用的笔记也不多。 1.1、Servlet 的功用&#xff1a; ​ Servlet 是运行在…

ClickHouse架构概览 —— Clickhouse 架构篇(一)

文章目录 前言Clickhouse 架构简介Clickhouse 的核心抽象列和字段数据类型块表 Clickhouse 的运作过程数据插入过程数据查询过程数据更新和删除过程 前言 本文介绍了ClickHouse的整体架构&#xff0c;并对ClickHouse中的一些重要的抽象对象进行了分析。然后此基础上&#xff0…

【面试】PWM(脉冲宽度调制)相关问题 ——长期更新

1、PWM调节原理 答&#xff1a;通过改变信号的高电平和低电平的持续时间比例来控制输出信号的平均功率或电压。 2、PWM占空比定义 答&#xff1a;在一个脉冲周期内&#xff0c;高电平的时间占整个周期时间的比例。 3、PWM波形的周期和调节精度由谁决定 答&#xff1a;当计数…

防止CSRF攻击

防止CSRF攻击 跨站点请求伪造&#xff08;Cross-Site Request Forgery&#xff0c;简称CSRF&#xff09;是一种常见的网络攻击类型。当用户在受信任的站点上通过身份验证后&#xff0c;访问攻击者精心准备的恶意网站、电子邮件、博客、即时消息或程序时&#xff0c;可能会导致…

软考 系统架构设计师系列知识点之SOME/IP与DDS(1)

本文内容参考&#xff1a; 车载以太网 - SOME/IP简介_someip-CSDN博客 https://zhuanlan.zhihu.com/p/369422441 什么是SOME/IP?_someip-CSDN博客 SOME/IP 详解系列&#xff08;1&#xff09;—— 概述_some ip-CSDN博客 深入浅出SOME/IP协议&#xff1a;基本概念和原理-…

Node.js笔记(万字总结)

目录 前言 1.node介绍与使用 1.1 Node介绍 1.2 node.js的优势 1.3 node的安装 1.4 检验是否成功安装 1.5 第一个应用 1.5.1 服务器代码 server.js 1.5.2 完整代码 1.5.3 运行 1.5.4 测试 2.获取参数 3.模块系统 1.模块介绍 2.xiaoyu.js 3.xiaoyu.js完整代码 4…

单兵组网设备+指挥中心:集群系统技术详解

一、单兵设备功能特点 单兵组网设备是现代通信技术的重要成果&#xff0c;旨在为单个作战或工作单元提供高效的通信和数据传输能力。其主要功能特点包括&#xff1a; 1. 便携性&#xff1a;设备轻巧&#xff0c;便于单兵携带和使用&#xff0c;适应各种复杂环境。 2. 通信能…

Python爬虫实战:利用代理IP获取电商数据

文章目录 1.电商数据介绍2.爬取目标3.代理IP推荐4.准备工作4.1 模块安装4.2 代理IP获取 5.爬虫代码实战5.1分析网页5.1.1 获取cookie5.1.2 关键词分析5.1.3 翻页分析5.1.4 数据获取分析 5.2 发送请求5.3 提取数据5.4 保存数据5.5 完整源码5.6 数据分析六、总结 1.电商数据介绍 …

海山数据库(He3DB)代理ProxySQL使用详解:(二)功能实测

读写分离实测 ProxySQL官方demo演示了三种读写分离的方式&#xff1a;使用不同的端口进行读写分离、使用正则表达式进行通用的读写分离、使用正则和digest进行更智能的读写分离。最后一种是针对特定业务进行的优化调整&#xff0c;也可将其归结为第二种方式&#xff0c;下边分…

紫光展锐突破创新终端品类,搭载展锐芯的全球首款二合一5G云电脑正式发布

近日&#xff0c;搭载紫光展锐5G芯片T760的中兴云电脑逍遥系列正式发布&#xff0c;亮点&#xff1a; 全球首款二合一5G云电脑&#xff0c;支持本地/云端双模式&#xff0c;一键切换&#xff0c;用户可同时享有Android平板和Windows云电脑两种形态&#xff1b;支持5G蜂窝网络&…

【OceanBase诊断调优】—— 排查 IO 问题的方法

本文主要介绍 OceanBase 数据库 V4.x 版本中排查 IO 问题的方法以及 IO 相关的日志和视图。 IO 相关问题 -4013 内存爆、IoControl 模块内存泄漏 目前 IO 内存爆可能的原因如下&#xff0c;及相应的排查方法。 其他模块使用 IO 内存后未释放导致泄漏。 日志分析。 通过关键词…

视频批量剪辑神器:一键合并多个视频,轻松添加音频,高效创作无极限!

视频已经成为我们生活中不可或缺的一部分。无论是工作汇报、生活记录&#xff0c;还是创意表达&#xff0c;视频都扮演着至关重要的角色。然而&#xff0c;对于很多非专业剪辑师来说&#xff0c;视频剪辑却是一项既繁琐又耗时的工作。别担心&#xff0c;今天我要给大家介绍一款…