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

news/2024/11/18 16:38:51/

前言

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

前置知识: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) // 获取地球渲染的targetconst slider = document.createElement('div')const sliderWidth = '5px' // 分割线的宽度slider.id = 'slider'slider.style.width = sliderWidthslider.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.LEFTright.splitDirection = Cesium.SplitDirection.RIGHT// 依据滑动条的默认位置设置场景的分割位置,值为0到1之间viewer.scene.splitPosition = slider.offsetLeft / slider.parentElement.offsetWidthlet moveActive = false// 滑动事件: 修改滑动条的位置以及视图分割的位置function moveEvnet (movement) {if (!moveActive) {return}const relativeOffset = movement.endPosition.xconst splitPosition = (slider.offsetLeft + relativeOffset) / slider.parentElement.offsetWidthslider.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) // 获取地球渲染的targetthis.slider = document.createElement('div')this.sliderWidth = '5px' // 分割线的宽度this.slider.id = 'slider'this.slider.style.width = this.sliderWidththis.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) // 移除所有 ImageryLayerfor (let i = 0; i < this.imageryLayers.length; i++) {layers.add(this.imageryLayers[i]);}}

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

  _moveEvnet(movement) {if (!this.moveActive) {return}const relativeOffset = movement.endPosition.xconst splitPosition = (this.slider.offsetLeft + relativeOffset) / this.slider.parentElement.offsetWidththis.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.offsetWidththis.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) // 获取地球渲染的targetif (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.ppmy.cn/news/258148.html

相关文章

《C++高级编程》读书笔记(四:设计专业的C++程序)

1、参考引用 C高级编程&#xff08;第4版&#xff0c;C17标准&#xff09;马克葛瑞格尔 2、建议先看《21天学通C》 这本书入门&#xff0c;笔记链接如下 21天学通C读书笔记&#xff08;文章链接汇总&#xff09; 1. 程序设计概述 在启动新程序&#xff08;或已有程序的新功能&…

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

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

触屏笔哪个牌子好用?高性价比的电容笔推荐

事实上&#xff0c;苹果原本的电容笔和普通的电容笔最大的区别就是重力压感&#xff0c;市面上还没有一款能像apple pencil这样拥有着独特重力压感的电容笔。但是因为苹果的pencil太贵&#xff0c;很多人都把注意力都放在平替电容笔一边&#xff0c;平替电容笔的性能也在不断提…

哪个牌子的电容笔好,电容笔牌子排行

电容笔作为现在当下热销的数码配件&#xff0c;由于原装的价格太高了&#xff0c;所以市面上出现许多品牌的平替&#xff0c;在无数品牌商加入其中&#xff0c;导致许多小伙伴购选时难度加大&#xff0c;而大部分的品牌都是大同小异&#xff0c;看得眼花缭乱&#xff0c;更不知…

哪个牌子集成灶好用,这款登上《消费主张》栏目的集成灶品牌火了

如今&#xff0c;随着集成灶行业的发展&#xff0c;集成灶品牌众多&#xff0c;产品也比较多样化。因此市场上也出现了十大集成灶排名等供广大消费者参考的权威榜单。那么在这些知名品牌中&#xff0c;哪个牌子集成灶好用&#xff1f;集成灶有哪些功能是值得重点关注的呢&#…

Python time 模块

time 是python的内置模式,使用的时候需要import time 引入 time 的几个主要函数如下 import time# 当前时间戳 print("time:", time.time()) # 打印结果time: 1686107990.798039 # 返回可读形式的时间 print("ctime:", time.ctime()) # 打印结果ctime:…

PWA:Service Worker实现离线访问、域名失效启用备用域名......

介绍下Service Worker service worker 运行在独立的线程&#xff0c;可以拦截和处理网络请求&#xff0c;以实现离线缓存、推送通知和后台同步等功能。具体可以看MDN的介绍 怎么使用Service Worker 1、注册脚本 // useServiceWorker.ts navigator.serviceWorker?.register…

美敦力PB560呼吸机设计图纸 源代码分享

美敦力PB560呼吸机设计图纸 源代码分享 全套资料下载&#xff1a;一牛网论坛