Vue使用百度地图以及实现轨迹回放 附完整代码

news2024/11/25 13:40:10

百度地图开放平台 https://lbs.baidu.com/index.php?title=%E9%A6%96%E9%A1%B5
javaScript API https://lbs.baidu.com/index.php?title=jspopularGL
百度地图实例 https://lbsyun.baidu.com/index.php?title=open/jsdemo
Vue Baidu Map文档 https://dafrok.github.io/vue-baidu-map/#/zh/index

效果图:

image.png

支持放大缩小 调动播放进度 搜索轨迹时段 调整播放速度等。

image.png

步骤1:准备工作

1.1 获取百度地图API密钥

首先,你需要在百度地图开放平台注册一个开发者账号,并创建一个应用,以获取API密钥。API密钥是用于标识你的应用身份的重要凭证。
1701942229175.png
1701942117490.png

步骤2:引入百度地图JavaScript API 在index.html添加以下代码

1.3 引入百度地图API和样式表

在项目的public/index.html文件中引入百度地图API和样式表:

<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=换成自己的API秘钥"></script>
  <script type="text/javascript" src="https://api.map.baidu.com/library/TextIconOverlay/1.2/src/TextIconOverlay_min.js"></script>
  <script type="text/javascript" src="https://api.map.baidu.com/library/MarkerClusterer/1.2/src/MarkerClusterer_min.js"></script>

常用API表格:

API描述使用示例
BMap.Map(container [, opts])创建地图实例new BMap.Map(“map-container”);
BMap.Point(lng, lat)创建地理坐标点实例new BMap.Point(114.161291, 22.644619);
BMap.Marker(point [, opts])创建标记点实例new BMap.Marker(point);
BMap.Icon(url, size [, opts])创建标记点图标实例new BMap.Icon(“marker.png”, new BMap.Size(30, 30));
BMap.Polyline(points [, opts])创建折线实例new BMap.Polyline([point1, point2]);
BMap.InfoWindow(content [, opts])创建信息窗口实例new BMap.InfoWindow(“内容”);
BMap.NavigationControl(opts)创建地图缩放控件实例new BMap.NavigationControl();
BMapLib.MarkerClusterer(map, opts)创建点聚合实例new BMapLib.MarkerClusterer(map, { markers: markers });
map.centerAndZoom(center, zoom)设置地图中心点和缩放级别map.centerAndZoom(point, 15);
map.addOverlay(overlay)添加覆盖物到地图map.addOverlay(marker);
map.clearOverlays()清除地图上的所有覆盖物map.clearOverlays();
map.enableScrollWheelZoom()启用鼠标滚轮缩放map.enableScrollWheelZoom();
map.getDistance(point1, point2)计算两点间的直线距离map.getDistance(point1, point2);
marker.addEventListener(type, handler)为标记点添加事件监听器marker.addEventListener(“click”, function() { console.log(“点击标记点”); });
polyline.getPath()获取折线的路径polyline.getPath();
InfoWindow.setContent(content)设置信息窗口的内容infoWindow.setContent(“新内容”);

注意:

  • opts 为选项参数,具体可参考官方文档。
  • 示例中的 point1point2 等是 BMap.Point 的实例。
  • 在示例中可能使用了一些虚拟的数据,具体情况根据项目实际需求来设置。

以上是一些基础的API,百度地图提供了丰富的功能,可以根据实际需求查阅百度地图JavaScript API官方文档获取更多详细信息。

步骤3:编写

父组件:BaiduMap.vue

模板部分:
<div ref="map" class="map-container"></div>:地图容器。
<a-modal>:断油电操作的模态框,包括确认按钮和输入备注的文本框。
<a-modal>:恢复油电操作的模态框,同样包括确认按钮和输入备注的文本框。
<a-modal>:轨迹回放的模态框,包含了子组件 <run-map> 来展示实际的轨迹。
数据:
map:百度地图实例。
markers:存储标记的数组。
infoWindows:存储信息窗口的数组。
markerCluster:MarkerClusterer 实例,用于标记点聚合。
devices:设备信息数据。
modalBreak和modalRestore:控制断油电和恢复油电的模态框显示。
modaldrivingTrajectory:控制轨迹回放的模态框显示。
url:包含一些后端接口的URL。
deviceNum、optRemark、numberplate:一些操作所需的参数。
方法:
initMap():初始化地图,设置中心点和缩放级别,添加控件,并加载地图标点数据。
loadRandomDevices():加载地图标点数据,清除之前的标记、信息窗口和点聚合,添加新的标记、信息窗口和点聚合。
createPopupContent(point):根据设备信息创建信息窗口内容。
handleBreakOk()和handleRestoreOk():处理断油电和恢复油电的确认事件。
cancellation():关闭轨迹回放的模态框。
<template>
  <div class="parent-container">
    <div ref="map" class="map-container"></div>
    <!-- <button @click="loadRandomDevices">加载随机设备</button> -->

    <a-modal v-model="modalBreak" title="断油电" @ok="handleBreakOk">

      <div style="font-size: 16px; font-weight: bolder;"><img src="../../assets/jingao.png" width="40px"
          height="40px"></img>您确定要下发<span style="font-size: 18px; color: red;"> 断油电</span> 指令吗?</div>
      <!-- <a-radio-group v-model="triggerType" style="margin-top: 30px;"> -->
      <!-- <a-radio :value="合同未交款断油电">合同未交款断油电</a-radio>
        <a-radio :value="违竟断油电">违竟断油电</a-radio>
        <a-radio :value="其他">其他:</a-radio> -->
      <!-- </a-radio-group> -->
      <a-input v-model="optRemark" placeholder="请输入备注" style="margin-top: 30px;">
      </a-input>
    </a-modal>
    <a-modal v-model="modalRestore" title="恢复油电" @ok="handleRestoreOk">

      <div style="font-size: 16px; font-weight: bolder;"><img src="../../assets/jingao.png" width="40px"
          height="40px"></img>您确定要执行<span style="font-size: 18px; color: red;"> 恢复油电</span> 指令吗?</div>
      <a-input v-model="optRemark" placeholder="请输入备注" style="margin-top: 30px;">
      </a-input>
    </a-modal>
    
    
    <a-modal   width="100%" height="100%" v-model="modaldrivingTrajectory" title="轨迹回放" >
        <run-map :deviceNum="deviceNum"></run-map>
      <template slot="footer">
        <a-button @click="cancellation">关闭</a-button>
       
      </template>
    </a-modal>
   
  
  </div>
</template>

<script>
  import Vue from 'vue'
  import {
    getAction,
    httpAction,
    postAction
  } from '../../api/manage'
  
       import RunMap from './GjMap.vue'

  export default {
    props: {
      gpsInfo: {
        type: Object,
      }
    },
    components: {
      RunMap
    },
    data() {
      return {
        map: null,
        markers: [], // 存储标记
        infoWindows: [], // 存储信息窗口
        markerCluster: null, // MarkerClusterer 实例
        devices: [],
        modalBreak: false, // 模态框可见状态
        modaldrivingTrajectory:false,//轨迹回放
        modalRestore: false,
        url: {
          //断油电 恢复油电
          executeCmd: '/jeecg-customers/car/carCheXiaoGpsController/executeCmd',
          //获取轨迹url
          trajectory: '/jeecg-customers/ car/carCheXiaoGpsController/trajectory',
         
        },
        //设备编号
        deviceNum: null,
        optRemark: null,
        numberplate: null,
      };
    },
    mounted() {
      this.initMap();
    },
    methods: {
      initMap() {
        // 创建地图实例
        this.map = new BMap.Map(this.$refs.map);

        // 设置地图中心点和缩放级别
        const point = new BMap.Point(114.16129136801659, 22.64461948509109);
        this.map.centerAndZoom(point, 10);

        // 添加地图缩放控件
        const navigationControl = new BMap.NavigationControl();
        this.map.addControl(navigationControl);

        // 启用鼠标滚轮缩放
        this.map.enableScrollWheelZoom();

        //加载地图点数据
        this.loadRandomDevices();
      },
      createPopupContent(point) {
        // 创建信息窗口内容,包括设备属性
        return `
       <div class="popup-container">
         <div class="popup-header">设备信息</div>
         <div class="popup-content">
         <p>设备号:<spen id="deviceNum"> ${point.deviceNum}</spen></p>
          <p>车牌号码:<spen id="licenseName"> ${point.licenseName}</spen></p>
          <p>最近定位位置: ${point.address}</p>
          
          <p>经度: ${point.lng}</p>
          <p>纬度: ${point.lat}</p>
           <p>设备状态: ${point.deviceState}</p>
         <span id="handleBreak" style="color: red; font-size: 15px;" οnmοuseοver="this.style.backgroundColor='lightgray'" οnmοuseοut="this.style.backgroundColor='initial'">断油电</span>
         <span id="handleRestore" style="color: blue; font-size: 15px;" οnmοuseοver="this.style.backgroundColor='lightgray'" οnmοuseοut="this.style.backgroundColor='initial'">恢复油电</span>
         <span id="drivingTrajectory" style="color: green; font-size: 15px;" οnmοuseοver="this.style.backgroundColor='lightgray'" οnmοuseοut="this.style.backgroundColor='initial'">行驶轨迹</span>

         </div>
       </div>
      `;
      },
      /**
       * 加载地图标点数据
       */
      loadRandomDevices() {
        // 清除之前的标记、信息窗口和点聚合
        this.map.clearOverlays();
        this.markers = [];
        this.infoWindows = [];
        if (this.markerCluster) {
          this.markerCluster.clearMarkers();
        }
        // 定义自定义图标的样式
        // const myIcon = new BMap.Icon(require("@/assets/car.png"), new BMap.Size(32, 32), {
        //   anchor: new BMap.Size(16, 32), // 图标的定位点相对于图标左上角的偏移
        //   imageSize: new BMap.Size(32, 32) // 图标的大小
        // });
        // 根据 gpsInfo 的经纬度设置地图中心点
        const gpsInfo = this.gpsInfo;
        const centerPoint = new BMap.Point(gpsInfo.lng, gpsInfo.lat);
        this.map.setCenter(centerPoint);
        // 设置缩放级别
        this.map.setZoom(18);

        const point = new BMap.Point(gpsInfo.lng, gpsInfo.lat);
        // const marker = new BMap.Marker(point, {
        //   icon: myIcon
        // });

        const marker = new BMap.Marker(point);
        //创建信息窗口
        const infoWindow = new BMap.InfoWindow(this.createPopupContent(gpsInfo));
        //添加单击事件侦听器以打开信息窗口

        marker.addEventListener("click", () => {
          this.map.openInfoWindow(infoWindow, point);

          const deviceIdElement = document.getElementById("deviceNum");
          const deviceNum = deviceIdElement.textContent.trim();

          const licenseNameElement = document.getElementById("licenseName");
          const licenseName = licenseNameElement.textContent.trim();

          this.deviceNum = deviceNum;
          this.numberplate = licenseName

          // 获取按钮元素并添加点击事件
          const handleBreak = document.getElementById("handleBreak");
          handleBreak.addEventListener("click", () => {
            this.modalBreak = true; // 打开模态框
            // console.log("执行断油电操作");
            console.log("设备编号:", deviceNum);
          });

          const handleRestore = document.getElementById("handleRestore");
          handleRestore.addEventListener("click", () => {
            console.log("执行恢复油电操作");
            this.modalRestore=true;
          })
          
          const drivingTrajectory = document.getElementById("drivingTrajectory");
          drivingTrajectory.addEventListener("click", () => {
            console.log("行驶轨迹执行事件");
              this.modaldrivingTrajectory=true
          })
        });
        // 将标记和信息窗口添加到各自的数组中
        this.markers.push(marker);
        this.infoWindows.push(infoWindow);

        // 添加标记到地图
        this.map.addOverlay(marker);

        // });
        // 点聚合
        this.markerCluster = new BMapLib.MarkerClusterer(this.map, {
          markers: this.markers,
          gridSize: 80, // 根据需要进行调整
          maxZoom: 18,
        });
      },
      cancellation(){
        this.modaldrivingTrajectory=false
        
      },
      /**
       * 确定断油电事件
       */
      handleBreakOk() {
        if (this.optRemark == null) {
          this.$message.info("备注不能为空")
          return
        }
        httpAction(this.url.executeCmd, {
          "deviceNum": this.deviceNum,
          "switchKey": "14",
          "remark": this.optRemark,
          "numberplate": this.numberplate
        }, 'post').then((res) => {
          if (res) {
            console.log(res)
            this.$message.info(res.result)
          }
        })
        this.modalBreak = false; // 关闭模态框
      },
      /**
       * 确定恢复油电事件
       */
      handleRestoreOk() {
        if (this.optRemark == null) {
          this.$message.info("备注不能为空")
          return
        }
        httpAction(this.url.executeCmd, {
          "deviceNum": this.deviceNum,
          "switchKey": "15",
          "remark": this.optRemark,
          "numberplate": this.numberplate,
        }, 'post').then((res) => {
          if (res) {
            console.log(res)
            this.$message.info(res.result)
          }
        })
        this.modalRestore = false; // 关闭模态框
      },
    },
  };
</script>

<style scoped>
  .parent-container {
    width: 100%;
    height: 800px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  .map-container {
    width: 100%;
    height: 100%;
  }

  button {
    margin-top: 10px;
  }
</style>

轨迹回放组件:RunMap.vue

模板部分:
<div ref="mapContainer" style="width: 100%; height: 100vh;"></div>:地图容器。
控制面板:包含轨迹时段选择、搜索、播放、暂停、进度调节等功能。
数据:
dateData:轨迹时段的日期数据。
startDate和endDate:选择的开始和结束日期时间。
map:百度地图实例。
pathData:轨迹点的数据。
marker:地图上的标记点。
currentIndex:当前轨迹点索引。
speed:轨迹播放速度。
isPlaying:是否正在播放。
progressPercent:轨迹播放进度百分比。
url:包含后端接口的URL。
totalPoints:轨迹点总数。
方法:
handleDateFilterChange():处理日期范围变化。
searchData():执行搜索轨迹数据的操作。
decreaseProgress()和increaseProgress():调整轨迹播放进度。
updateMarkerPosition():更新标记的位置。
pauseAnimation()和startAnimation():暂停和播放轨迹动画。
generatePathData():生成轨迹点数据。
initMap():初始化地图,添加标记、标点、路径等,并开始动画。
animateMarker():播放轨迹动画的主要逻辑。
calculateZoomLevel():根据距离计算新的缩放级别。
clearMap()和clearMapAndSearch():清除地图上的标记和地图实例。
<template>
  <div>
    <div ref="mapContainer" style="width: 100%; height: 100vh;"></div>

    <!-- 包含轨迹时段和控制按钮的浮动层 -->
    <div class="control-panel">
      轨迹时段: <a-range-picker :value="dateData" @change="handleDateFilterChange" :show-time="true"
        :disabledDate="disabledDate">
      </a-range-picker>

      <!-- 搜索按钮 -->
      <a-button @click="clearMapAndSearch">搜索</a-button>

      <a-button @click="startAnimation">播放</a-button>

      <a-button @click="pauseAnimation">暂停</a-button>

      <a-button @click="decreaseProgress" style="margin-left: 20px;">-</a-button>
      <a-button @click="increaseProgress">+</a-button>

      <a-row>
        <a-col :span="12">
          播放速度:
          <a-radio-group v-model="speed">
            <a-radio :value="100">慢速</a-radio>
            <a-radio :value="500">正常</a-radio>
            <a-radio :value="1000">快速</a-radio>
            <a-radio :value="1500">最快速</a-radio>
          </a-radio-group>
        </a-col>
      </a-row>

      <a-slider v-model="progressPercent" :min="0" :max="100" />
    </div>
  </div>
</template>

<script>
  import Vue from 'vue';
  import {
    getAction,
    httpAction,
    postAction
  } from '../../api/manage';
  import moment from 'dayjs'


  export default {
    props: {
      deviceNum: {
        type: String, // 参数的数据类型
        required: true // 参数是否必需
      },

    },
    watch: {
      progressPercent(newProgress) {
        // 在进度变化时更新标记的位置
        this.updateMarkerPosition();
      },
    },

    data() {

      return {
        dateData: [],

        startDate: null, // 开始日期时间
        endDate: null, // 结束日期时间

        map: null,
        pathData: [],
        marker: null,
        currentIndex: 0,
        speed: 100,

        //是否播放
        isPlaying: false,
        progressPercent: 0,
        url: {
          trajectory: '/jeecg-customers/car/carCheXiaoGpsController/trajectory',
        },
        totalPoints: 0,
      };
    },
    mounted() {



      const startDate = moment().subtract(5, 'hours').format('YYYY-MM-DD HH:mm:ss');
      console.log(startDate, '开始时间');

      const endDate = moment().format('YYYY-MM-DD HH:mm:ss');
      console.log(endDate, '结束时间');


      this.dateData = [startDate, endDate]
      this.startDate = startDate
      this.endDate = endDate

      this.searchData();
    },
    methods: {
      disabledDate(current) {
        // 禁用日期的函数
        if (!this.startDate || !this.endDate) {
          // 如果没有选择日期范围,不禁用任何日期
          return false;
        }

        const maxDate = moment(this.startDate).add(3, 'days'); // 允许选择日期范围的最大结束日期

        return current && (current < this.startDate || current > maxDate);
      },

      handleDateFilterChange(dates, dateString) {
        this.dateData = dates;
        this.startDate = dateString[0]
        this.endDate = dateString[1]
        console.log(this.startDate, this.endDate)
      },
      searchData() {
        // 获取开始日期时间和结束日期时间
        if (!this.startDate || !this.endDate) {
          // 显示错误消息或进行其他处理
          this.$message.warning('请选择时间');
        }

        this.generatePathData().then((res) => {
          if (res) {
            this.initMap();
          }
        });

      },

      decreaseProgress() {
        if (this.progressPercent > 0) {
          this.progressPercent -= 1;
          this.updateMarkerPosition();
        }
      },

      increaseProgress() {
        if (this.progressPercent < 100) {
          this.progressPercent += 1;
          this.updateMarkerPosition();
        }
      },
      updateMarkerPosition() {
        const newIndex = Math.round((this.progressPercent / 100) * (this.totalPoints - 1));
        if (newIndex !== this.currentIndex) {
          this.currentIndex = newIndex;
          const point = this.pathData[newIndex];
          const position = new BMap.Point(point.lng, point.lat);
          this.marker.setPosition(position);
          this.map.panTo(position);
        }
      },

      pauseAnimation() {
        this.isPlaying = false;
      },
      startAnimation() {
        this.isPlaying = true;
        this.animateMarker();
      },
      generatePathData() {
        console.log(this.startDate)
        console.log(this.endDate)
        return new Promise((resolve) => {
          getAction(this.url.trajectory, {
            // deviceNum: "10213134933",
            deviceNum: this.deviceNum,
            baseStateLBS: "1",
            startTime: this.startDate,
            endTime: this.endDate,
            stopPoint: "0",
            stopPointTime: "10",
          }).then((res) => {
            resolve(res);
            this.pathData = res.result;
            this.totalPoints = this.pathData.length; // Set totalPoints
          });
        });
      },
      initMap() {
        this.map = new BMap.Map(this.$refs.mapContainer);

        const firstPoint = this.pathData[0];

        // 添加缩放控件        
        this.map.addControl(new BMap.NavigationControl());
        this.map.centerAndZoom(new BMap.Point(firstPoint.lng, firstPoint.lat), 15);

        // 启用鼠标滚轮缩放
        this.map.enableScrollWheelZoom();

        // 遍历pathData添加图标覆盖物
        for (let i = 0; i < this.pathData.length; i++) {
          const point = this.pathData[i];
          const myIcon = new BMap.Icon(require("@/assets/stop.png"), new BMap.Size(20, 20), {
            // anchor: new BMap.Size(25, 25), // 图标的定位点相对于图标左上角的偏移
            imageSize: new BMap.Size(20, 20) // 图标的大小
          });
          const marker = new BMap.Marker(new BMap.Point(point.lng, point.lat), {
            icon: myIcon,
          });

          // 根据sp的值判断是否添加覆盖物
          if (point.sp === "0.0") {
            this.map.addOverlay(marker);
          }
        }

        const myIcon = new BMap.Icon(require("@/assets/carrun.png"), new BMap.Size(50, 50), {
          anchor: new BMap.Size(25, 25), // 图标的定位点相对于图标左上角的偏移
          imageSize: new BMap.Size(50, 50) // 图标的大小
        });

        // const myIcon = new BMap.Icon("https://webapi.amap.com/images/car.png", new BMap.Size(60, 30), {
        //   // anchor: new BMap.Size(25, 25), // 图标的定位点相对于图标左上角的偏移
        //   imageSize: new BMap.Size(60, 30) // 图标的大小
        // });

        this.marker = new BMap.Marker(new BMap.Point(firstPoint.lng, firstPoint.lat), {
          icon: myIcon

        });

        this.map.addOverlay(this.marker);

        const polyline = new BMap.Polyline(
          this.pathData.map((point) => new BMap.Point(point.lng, point.lat)), {
            enableEditing: false,
            enableClicking: true,
            strokeWeight: '8',
            strokeOpacity: 0.8,
            strokeColor: "#18a45b",
          }
        );
        this.map.addOverlay(polyline);

        // 开始动画
        this.animateMarker();
      },
      animateMarker() {
        if (this.currentIndex < this.totalPoints - 1 && this.isPlaying) {
          const currentPoint = this.pathData[this.currentIndex];
          const nextPoint = this.pathData[this.currentIndex + 1];
          const startPosition = new BMap.Point(currentPoint.lng, currentPoint.lat);
          const endPosition = new BMap.Point(nextPoint.lng, nextPoint.lat);

          const distance = this.map.getDistance(startPosition, endPosition);

          // 基于速度和两个点之间的距离来计算时长
          const duration = (distance / this.speed) * 1000;

          const angle = this.calculateAngle(startPosition, endPosition);

          this.marker.setRotation(angle);

          // 调整地图的缩放级别以使标点可见
          // const newZoomLevel = this.calculateZoomLevel(distance); // 自定义函数来计算缩放级别
          // this.map.centerAndZoom(endPosition, newZoomLevel);

          this.progressPercent = Math.round((this.currentIndex / (this.totalPoints - 1)) * 100);

          if (this.isPlaying) {
            setTimeout(() => {
              this.marker.setPosition(endPosition);
              this.currentIndex++;
              requestAnimationFrame(this.animateMarker);
            }, duration);
          }
        }
      },

      calculateZoomLevel(distance) {
        // 根据距离或其他条件来计算新的缩放级别
        if (distance < 1000) {
          return 19;
        } else {
          return 14;
        }
      },

      clearMap() {
        if (this.map) {
          this.map.clearOverlays(); // 清除地图上的所有标记点
          this.map = null; // 销毁地图实例
        }
      },

      clearMapAndSearch() {
        // 清除地图上的标点和地图实例
        this.clearMap();

        // 执行搜索并加载标点的逻辑
        this.searchData();
      },


      /**根据点位旋转角度
       * @param {Object} point1
       * @param {Object} point2
       */
      calculateAngle(point1, point2) {
        // 计算两点之间的方向(角度)
        const lat1 = point1.lat * (Math.PI / 180);
        const lng1 = point1.lng * (Math.PI / 180);
        const lat2 = point2.lat * (Math.PI / 180);
        const lng2 = point2.lng * (Math.PI / 180);

        const y = Math.sin(lng2 - lng1) * Math.cos(lat2);
        const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lng2 - lng1);
        let angle = Math.atan2(y, x);

        angle = (angle * 180) / Math.PI;

        // 调整角度以匹配图标朝向
        angle -= 90;

        return angle;
      }
    },
  };
</script>

<style>
  .control-panel {
    position: absolute;
    top: 10px;
    /* 调整 bottom 属性来控制浮动层距离底部的距离 */
    left: 10px;
    /* 调整 left 属性来控制浮动层距离左侧的距离 */
    background-color: white;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
  }
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构与算法:红黑树

目录 什么是红黑树 ​编辑 红黑树的性质 红黑树的辨析 红黑树实现 红黑树的结构 红黑树的插入 红黑树的调试 红黑树平衡判断 什么是红黑树 这里引入一下NIL节点的概念&#xff1a; NIL节点也称为空节点或外部节点&#xff0c;是红黑树中一种特殊的节点类型。NIL节点不…

DeepIn,UOS统信专业版安装运行Java,JavaFx程序

因为要适配国产统信UOS系统&#xff0c;要求JavaFx程序能简便双击运行&#xff0c;由于网上UOS开发相关文章少&#xff0c;多数文章没用&#xff0c;因此花了不少时间&#xff0c;踩了不少坑&#xff0c;下面记录一些遇到的问题&#xff0c;我的程序环境是jdk1.8&#xff0c;为…

应用程序中实现用户隐私合规和数据保护合规的处理方案及建议

随着移动互联网的发展&#xff0c;用户隐私合规和数据保护合规已经成为应用开发过程中不可忽视的重要环节。为了帮助开发者实现隐私和数据保护合规&#xff0c;本文将介绍一些处理方案和建议。 图片来源&#xff1a;应用程序中实现用户隐私合规和数据保护合规的处理方案及建议 …

720度vr虚拟家居展厅提升客户的参观兴致

VR虚拟展厅线上3D交互展示的优势有以下几点&#xff1a; 打破了场馆的展示限制&#xff0c;可展示危险性制品、珍贵稀有物品、超大型设备等&#xff0c;同时提供了更大的展示空间和更丰富的展示内容。 可提供企业真实环境的实时VR全景参观&#xff0c;提升潜在客户信任度。 提供…

【附源码】完整版,Python+Selenium+Pytest+POM自动化测试框架封装

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试框架简介 …

【S2ST】Direct Speech-to-Speech Translation With Discrete Units

【S2ST】Direct Speech-to-Speech Translation With Discrete Units AbstractIntroductionRelated workModelSpeech-to-unit translation (S2UT) modelMultitask learningUnit-based vocoder ExperimentsDataSystem setupBaselineASRMTTTSS2TTransformer Translatotron Evaluat…

【广州华锐互动】VR沉浸式体验铝厂安全事故让伤害教育更加深刻

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为我们的生活带来了前所未有的便捷和体验。在安全生产领域&#xff0c;VR技术的应用也日益受到重视。 VR公司广州华锐互动就开发了多款VR安全事故体验系统&#xff0c…

大数据技术2:大数据处理流程

前言&#xff1a;下图是一个简化的大数据处理流程图&#xff0c;大数据处理的主要流程包括数据收集、数据存储、数据处理、数据应用等主要环节。 1.1 数据收集 大数据处理的第一步是数据的收集。现在的中大型项目通常采用微服务架构进行分布式部署&#xff0c;所以数据的采集需…

如何使用Docker本地搭建开源CMF Drupal并结合内网穿透公网访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

【目标检测算法】IOU、GIOU、DIOU、CIOU

目录 参考链接 前言 IOU(Intersection over Union) 优点 缺点 代码 存在的问题 GIOU(Generalized Intersection over Union) 来源 GIOU公式 实现代码 存在的问题 DIoU(Distance-IoU) 来源 DIOU公式 优点 实现代码 总结 参考链接 IoU系列&#xff08;IoU, GIoU…

Java程序员,你掌握了多线程吗?(文末送书)

目录 01、多线程对于Java的意义02、为什么Java工程师必须掌握多线程03、Java多线程使用方式04、如何学好Java多线程送书规则 摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流…

Java API接口强势对接:构建高效稳定的系统集成方案

文章目录 1. Java API接口简介2. Java API接口的优势2.1 高度可移植性2.2 强大的网络通信能力2.3 多样化的数据处理能力 3. 实战&#xff1a;Java API接口强势对接示例3.1 场景描述3.2 用户管理系统3.3 订单处理系统3.4 系统集成 4. 拓展&#xff1a;Java API接口在微服务架构中…

麒麟信安系统下的硬盘分区情况说明

目前飞腾平台上面麒麟信安系统分区情况如下&#xff1a; Tmpfs为内存文件系统&#xff0c;可以不考虑&#xff0c;真正使用的是两个分区 两个分区加起来为51G 查看cat /etc/fstab可以看到/data这个分区下包含了home opt root等常用文件夹 再加上这个分区容量只有17G&#xff0c…

基于Browscap对浏览器工具类优化

项目背景 原有的启动平台公共组件库comm-util的浏览器工具类BrowserUtils是基于UserAgentUtils的&#xff0c;但是该项目最后一个版本发布于 2018/01/24&#xff0c;之至今日23年底&#xff0c;已有5年没有维护更新&#xff0c;会造成最新版本的部分浏览器不能正确获取到浏览器…

嵌入式工程师校招经验与学习路线总结

前言&#xff1a;不知不觉2023年秋招已经结束&#xff0c;作者本人侥幸于秋招中斩获数十份大差不差的OFFER&#xff0c;包含&#xff1a;Top级的AIGC&#xff0c;工控龙头&#xff0c;国产MCU原厂&#xff0c;医疗器械&#xff0c;新能源车企等。总而言之&#xff0c;秋招总体情…

NR重写console.log 增加时间格式

如题&#xff0c;默认console.log输出的日志是13位的时间戳&#xff0c;然后不方便查查看与对比代码运行点的耗时&#xff0c;我们可以简单的重写 console.log方法&#xff0c;增加自定义时间戳格式&#xff0c;如下是增加时间&#xff08;时&#xff0c;分&#xff0c;秒&…

苍穹外卖+git开源

搁置了很久重新开始学 为了学习方便&#xff0c;苍穹外卖的前后端代码已放至git开源。前端源代码请看给i他-->sky-take-out: 苍穹外卖 git学习-->Git基础使用-CSDN博客 后端接口员工管理和分类管理模块 添加员工&#xff0c;添加的表单账号、手机号、身份证都…

netty07-粘包半包以及解决方案

粘包指的是发送方在发送数据时&#xff0c;多个数据包被合并成一个大的数据包发送到接收方&#xff0c;接收方在接收时无法准确地区分各个数据包的边界&#xff0c;从而导致数据粘在一起。 半包指的是发送方发送的数据包被拆分成了多个小的数据包&#xff0c;在接收方接收时&a…

使用VS Code远程开发MENJA小游戏并通过内网穿透分享本地游戏到公网

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 推荐一个人工智能学习网站 点击跳转学习 前言 本篇教程&#xff0c;我们将通过VS Code实现远程开发MENJA小游戏&#xff0c;并通…

11月榜单亮点:单场直播GMV超过5亿,30+达人粉丝增长100万人

11月&#xff0c;在双11好物节的加持下&#xff0c;品牌商家业绩再创新高。 数据报告显示&#xff0c;10月20日至11月11日&#xff0c;抖音商城GMV同比增长119%&#xff0c;直播间累计时长达到5827万小时&#xff0c;越来越多的用户正通过抖音参与双11购物狂潮&#xff0c;而越…