【CesiumJS入门】(3)ImageryLayer之图层卷帘

news2025/2/26 3:06:17

前言

上一篇博客简单得介绍了影像图层并成功在视图上加载出来了,而今天我们来实现一个简单的可视化效果,影像图层卷帘。

前置知识:Cesium 事件详解(鼠标事件、相机事件、键盘事件、场景触发事件)_cesium点击事件_GISer小辉的博客-CSDN博客

请添加图片描述

代码

参考沙盒示例:Cesium Sandcastle

实现步骤

  1. 创建卷帘分割线的div元素
  2. 加载2个影像图层并分别设置切割的方向(Cesium.SplitDirection)
  3. 为分割线div绑定鼠标事件
  4. 在鼠标位移时修改分割线的位置和场景的分割位置
import * as Cesium from 'cesium'
import { map as viewer } from '@/utils/createCesium.js'

export function ImagerySplit (target = 'cesiumContainer') {
  const cesiumCon = document.getElementById(target) // 获取地球渲染的target
  const slider = document.createElement('div')
  const sliderWidth = '5px' // 分割线的宽度
  slider.id = 'slider'
  slider.style.width = sliderWidth
  slider.style.height = '100%'
  slider.style.position = 'fixed'
  slider.style.left = '50%'
  slider.style.top = '0'
  slider.style.backgroundColor = '#3370FF'
  slider.style.zIndex = '10'
  slider.style.cursor = 'col-resize'

  // 将滑动条添加到页面中的某个元素内
  if (cesiumCon) {
    cesiumCon.appendChild(slider) // 将slider元素添加到father元素的子元素列表中
  } else {
    document.querySelector('body').appendChild(slider)
  }

  // 左边的图层,標準風格
  const left = viewer.imageryLayers.addImageryProvider(
    new Cesium.UrlTemplateImageryProvider({
      url: 'https://tile-{s}.openstreetmap.fr/hot/{z}/{x}/{y}.png',
      subdomains: ['a', 'b', 'c', 'd']
    })
  )
  // 右边的图层,黑夜風格
  const right = viewer.imageryLayers.addImageryProvider(
    new Cesium.UrlTemplateImageryProvider({
      url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
      subdomains: ['a', 'b', 'c', 'd']
    })
  )

  // 设置切割的方向
  left.splitDirection = Cesium.SplitDirection.LEFT
  right.splitDirection = Cesium.SplitDirection.RIGHT

  // 依据滑动条的默认位置设置场景的分割位置,值为0到1之间
  viewer.scene.splitPosition = slider.offsetLeft / slider.parentElement.offsetWidth

  let moveActive = false

  // 滑动事件: 修改滑动条的位置以及视图分割的位置
  function moveEvnet (movement) {
    if (!moveActive) {
      return
    }

    const relativeOffset = movement.endPosition.x
    const splitPosition = (slider.offsetLeft + relativeOffset) / slider.parentElement.offsetWidth

    slider.style.left = `${100.0 * splitPosition}%`
    viewer.scene.splitPosition = splitPosition
  }

  // 中間那個分割綫的句柄
  const handler = new Cesium.ScreenSpaceEventHandler(slider)

  handler.setInputAction(() => {
    moveActive = true
  }, Cesium.ScreenSpaceEventType.LEFT_DOWN) // 未适配PINCH、PINCH_START等操作

  handler.setInputAction(moveEvnet, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

  handler.setInputAction(() => {
    moveActive = false
    // 不要让分割线超出界面了
    if (parseFloat(slider.style.left.replace('%', '')) > 100) {
      slider.style.left = `calc(100% - ${sliderWidth})`
    } else if (parseFloat(slider.style.left.replace('%', '')) < 0) {
      slider.style.left = '0%'
    }
  }, Cesium.ScreenSpaceEventType.LEFT_UP)
}

写完整一点

代码提交参考: feat: 新增影像卷帘方法及组件 · 4bb13cb · ReBeX/cesium-tyro-blog - Gitee.com

ok,结合我们项目已有的方法,让我来写一个完整点的影像图层卷帘方法。

先写一个类

export class splitImagery {
  // !属性
  slider // 滑动分割线的div元素
  sliderWidth // 分割线的宽度
  target // 渲染cesium场景的元素
  leftImagery // 左边的影像
  rightImagery // 右边的影像
  moveActive = false // 开启分割线位移
  imageryLayers = [] // 当前场景已有的影像图层
  
  constructor(target = 'cesiumContainer') {
    this.target = target
  }

  // !方法
  ......
}

然后我们往这个类里头加入方法

创建分割线的div元素

  spilitElement() {
    const cesiumCon = document.getElementById(this.target) // 获取地球渲染的target

    this.slider = document.createElement('div')
    this.sliderWidth = '5px' // 分割线的宽度

    this.slider.id = 'slider'
    this.slider.style.width = this.sliderWidth
    this.slider.style.height = '100%'
    this.slider.style.position = 'fixed'
    this.slider.style.left = '50%'
    this.slider.style.top = '0'
    this.slider.style.backgroundColor = '#3370FF'
    this.slider.style.zIndex = '10'
    this.slider.style.cursor = 'col-resize'

    // 将滑动条添加到页面中的元素内
    if (cesiumCon) {
      cesiumCon.appendChild(this.slider)
    } else {
      document.querySelector('body').appendChild(this.slider)
    }
  }

设置分割线左侧展示的影像

  setLeftImagery(layer = loadImagery.ion('', 3812)) {
    if (this.leftImagery) { // 如果已经有图层了则销毁旧的加载新的
      viewer.imageryLayers.remove(this.leftImagery, true); // 移除图层
    }
    this.leftImagery = layer
    // viewer.imageryLayers.add(layer)
    this.leftImagery.splitDirection = Cesium.SplitDirection.LEFT // 分割方向
    console.log('this.leftImagery: ', this.leftImagery);
  }

设置分割线右侧展示的影像

  setRightImagery(layer = loadImagery.ion('', 3845)) {
    if (this.rightImagery) {
      viewer.imageryLayers.remove(this.rightImagery, true); // 移除图层
    }
    this.rightImagery = layer
    // viewer.imageryLayers.add(layer)
    this.rightImagery.splitDirection = Cesium.SplitDirection.RIGHT // 分割方向
  }

获取当前场景中所有的影像图层并保存到数组中

  saveImageryLayers() {
    const layers = viewer.imageryLayers;
    for (let i = 0; i < layers.length; i++) {
      console.log('layers.get(i): ', layers.get(i));

      this.imageryLayers.push(layers.get(i));
    }

    layers.removeAll(false) // 移除所有 ImageryLayer
  }

重新加载之前保存的影像图层

  reloadImageryLayers() {
    const layers = viewer.imageryLayers;
    layers.removeAll(false) // 移除所有 ImageryLayer
    for (let i = 0; i < this.imageryLayers.length; i++) {
      layers.add(this.imageryLayers[i]);
    }
  }

滑动事件: 修改滑动条的位置以及视图分割的位置

  _moveEvnet(movement) {
    if (!this.moveActive) {
      return
    }

    const relativeOffset = movement.endPosition.x
    const splitPosition = (this.slider.offsetLeft + relativeOffset) / this.slider.parentElement.offsetWidth

    this.slider.style.left = `${100.0 * splitPosition}%`
    viewer.scene.splitPosition = splitPosition
  }

开始卷

  actionSplit() {
    this.saveImageryLayers()
    this.spilitElement()
    this.setLeftImagery()
    this.setRightImagery()
    // 依据滑动条的默认位置设置场景的分割位置,值为0到1之间
    viewer.scene.splitPosition = this.slider.offsetLeft / this.slider.parentElement.offsetWidth

    this.handler = new Cesium.ScreenSpaceEventHandler(this.slider)

    this.handler.setInputAction(() => {
      this.moveActive = true
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN) // 未适配PINCH、PINCH_START等操作

    this.handler.setInputAction(this._moveEvnet.bind(this), Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    this.handler.setInputAction(() => {
      this.moveActive = false
      // 不要让分割线超出界面了
      if (parseFloat(this.slider.style.left.replace('%', '')) > 100) {
        this.slider.style.left = `calc(100% - ${this.sliderWidth})`
      } else if (parseFloat(this.slider.style.left.replace('%', '')) < 0) {
        this.slider.style.left = '0%'
      }
    }, Cesium.ScreenSpaceEventType.LEFT_UP)

  }

不卷了

  stopSplit() {
    if (!this.slider) {
      return
    }
    this.reloadImageryLayers()
  
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP)

    const cesiumCon = document.getElementById(this.target) // 获取地球渲染的target
    if (cesiumCon) {
      cesiumCon.removeChild(this.slider)
    } else {
      document.querySelector('body').removeChild(this.slider)
    }
  }

调用

import {splitImagery}from '@/utils/ImageryLayer/splitImagery.js'

const splitInstance = new splitImagery() // 声明实例

splitInstance.actionSplit() // 开启卷帘功能
splitInstance.stopSplit() // 关闭卷帘功能
splitInstance.setLeftImagery(loadImagery.osm()) // 修改卷帘左侧的影像,loadImagery.osm()是上一篇博客写的方法,会加载并返回影像图层

请添加图片描述

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

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

相关文章

OPT CST 慕藤光

OPT 波特率 数据长度 停止位 奇偶校验 9600 bps 8 bits 1 bit 无 所有通讯字节都采用ASCII码 特征字 &#xff1d; $命令字 &#xff1d; 1&#xff0c;2&#xff0c;3&#xff0c;4 打开对应通道电源关闭对应通道电源设置对应通道电源参数读出对应通道电…

【论文阅读】Twin Neural Network Regression

论文下载 GitHub bib: ARTICLE{SebastianKevin2022Twin,title {Twin neural network regression},author {Sebastian Johann Wetzel and Kevin Ryczko and Roger Gordon Melko and Isaac Tamblyn},journal {Applied AI Letters},year {2022},volume {3},number …

SpringBoot整合邮箱验证码实现用户注册

唠嗑部分 今天我们来分享一下在系统开发过程中&#xff0c;如何使用验证码来验证用户并完成用户注册 首先来看一下成品界面展示 说一下以上注册功能的设计&#xff1a; 用户手动输入用户名(全数据库唯一)、密码、确认密码、邮箱地址(单个邮箱最多可注册3个用户)、正确的邮箱…

Arm 推出 2023 全面计算解决方案,加速终端 AI 应用开发和部署

在当今数字化时代&#xff0c;人们对移动端计算能力的要求已经上升到了前所未有的高度。他们需要移动设备具有更快、更先进、更持久的计算能力&#xff0c;以提高生产力和生活质量。而科技厂商在满足人们对移动端计算能力的需求的同时&#xff0c;还需要从整个生态系统的角度出…

通过python封装接口seller_nick获取京东店铺所有商品数据,京东店铺所有商品数据接口,京东API接口

目的&#xff1a; 通过python封装接口seller_nick获取京东店铺所有商品数据&#xff0c;方法如下&#xff1a; 使用京东开放平台提供的API接口文档&#xff0c;找到seller_nick接口的具体参数及请求方式。 使用Python中的requests库发送请求&#xff0c;获取接口返回的数据。 …

nuxt3.0学习-三、nuxt.config.ts配置、跨域处理以及浏览器适配处理

nuxt官方对于nuxt.config.ts配置的介绍在Nuxt3.0 nuxt.config.ts配置 关于如何配置本人只能给出一点点启发&#xff0c;具体的配置需要根据个人需求去配置 nuxt.config.ts配置、跨域处理 import { prismjsPlugin } from "vite-plugin-prismjs"; export default de…

CompletableFuture异步和线程池

一、线程回顾 1、初始化线程的 4 种方式 1&#xff09;、继承 Thread 2&#xff09;、实现 Runnable 接口 3&#xff09;、实现 Callable 接口 FutureTask &#xff08;可以拿到返回结果&#xff0c;可以处理异常&#xff09; 4&#xff09;、线程池 方式 1 和方式 2&am…

《精通特征工程》学习笔记(1):数值特征处理

不进行多余的解释&#xff0c;想看原文直接下载pdf查看&#xff0c;本文是精简提炼了重要的方法写进来。 1.二值化 在百万歌曲数据集中&#xff0c;原始的收听次数并不是衡量用户喜好的强壮指标。&#xff08;在统计学术语 中&#xff0c;“强壮”意味着该方法适用于各种情况…

【2611. 老鼠和奶酪】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 有两只老鼠和 n 块不同类型的奶酪&#xff0c;每块奶酪都只能被其中一只老鼠吃掉。 下标为 i 处的奶酪被吃掉的得分为&#xff1a; 如果第一只老鼠吃掉&#xff0c;则得分为 reward1[i] 。如果第二…

Hive之HPLSQL安装手册

软件版本信息&#xff1a; CDH&#xff1a; cdh5.14.0 Hive: 1.1.0 Impala&#xff1a;2.11.0一&#xff1a;下载地址 Hplsql官网&#xff1a; http:www.hplsql.org/download 下载的是&#xff1a;hplsql-0.3.31.tar.gz版本 二&#xff1a;安装步骤 解压下载的hplsql-0.3.…

kafka 02

4.API开发 准备&#xff1a; 创建项目 &#xff0c; 添加依赖 XML <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <depen…

如何评价编程语言 Reason?

Reason编程语言的设计目标是为开发人员提供一种易于理解和学习的工具&#xff0c;同时提供静态类型检查和高效的代码执行。Reason基于OCaml语言&#xff0c;并引入了JavaScript的语法和工具链&#xff0c;使得开发者能够在现有的JavaScript生态系统中更好地开发和维护代码。Rea…

2023,数据库国产替代走到哪了?

如今&#xff0c;战场不仅银行&#xff0c;参战者也不仅单独的一家。对中国的国产数据库而言&#xff0c;机会和挑战都在加速涌来。 作者|思杭 编辑|皮爷 出品|产业家 2023&#xff0c;数据库格局正在变化&#xff0c;愈演愈烈。 如果说哪个环节是如今国产替代的最火热…

chatgpt赋能python:Python中如何输出两个数

Python中如何输出两个数 对于任何一种编程语言来说&#xff0c;输出两个数都是非常基础的知识点&#xff0c;Python也不例外。在Python中&#xff0c;我们可以使用print()函数来输出两个数。本篇文章将会介绍如何在Python中输出两个数。 介绍 在Python中&#xff0c;输出两个…

Python让文档处理变得轻松:如何快速替换Word文档中的关键字

应用场景&#xff1a; Python自动化处理Word文档的功能可以应用于许多场景&#xff0c;以下是其中一些常见的应用场景&#xff1a; 批量处理文档&#xff1a;如果您需要处理大量的Word文档&#xff0c;例如替换文本、添加文本、修改格式等&#xff0c;手动完成这些任务将非常耗…

驱动LSM6DS3TR-C实现高效运动检测与数据采集(4)----上报匿名上位机实现可视化

概述 LSM6DS3TR-C是单芯片“3轴陀螺仪 3轴加速度计”的惯性 测量单元(IMU)&#xff0c; 五种种可选满量程的陀螺仪(125/250/500/1000/2000 dps)和加速度计(2/4/8/16 g)。 上述工程中选择的加速度和陀螺仪对应的量程为2g和2000dps&#xff0c;对应的灵敏度如下所示&#xff0c…

具有更多存储空间和带宽的亚马逊云科技Snowball Edge存储优化型设备

亚马逊云科技AWS Snow Family系列设备用于将数据经济高效地迁移到云端并在边缘进行处理。增强型Snowball Edge存储优化型设备专为PB级数据迁移项目而设计&#xff0c;具有210TB的NVMe存储空间&#xff0c;每秒可传输高达1.5千兆字节的数据。这些设备还包括10GBASE-T、SFP48和QS…

缩略图加密学习总结

一、缩略图加密概述 完全加密为噪声图像后&#xff0c;密文图像的文件扩展&#xff0c;传输存储消耗更多的资源。完全加密的噪声图像的可用性建立在对密文进行解密的基础上&#xff0c;耗费大量的计算代价。原始图像中精细的视觉信息被抹去以保护隐私,而粗略的视觉信息被保留以…

Vue+element UI实现列表全部数据排序

element ui 表格中的sortable属性只能实现当前页数据的排序&#xff0c;无法实现整张表全部数据的排序&#xff0c;所以需要采取自定义的排序方式重新触发接口&#xff0c;获取排序好的全部列表 Java后端的分页列表有这两个字段需要前端去传递&#xff1a; el-table 上加上so…

springboot 2.6.12 自定义解析 yaml 加密数据

文章目录 一、简介二、yaml 默认解析简单说明三、自定义 yaml 解密解析器四、配置 PropertySourceLoader五、简单测试 一、简介 为了保证项目的配置文件的安全性&#xff0c;需要对第三方组件 mysql、redis、es、mq 等用户名密码进行加密处理&#xff0c;可以使用现成的三方包…