【Cesium】卷帘对比

卷帘对比,是在同一个三维场景里通过拖拽分割线查看左右/上下两边图层的效果。使用Cesium实现卷帘对比,最关键是设置图层的splitDirection属性。

官网中的【卷帘对比】例子:

1. 创建场景

const viewer = new Cesium.Viewer("cesiumContainer");

2. 自定义分割线样式,监听鼠标/控制器的动作

(1)根据UI设计稿完成分割线的渲染,利用Vue3的Teleport将分割线穿插到body页面中。

<Teleport to="body">
   <div id="slider" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
     <div id="optionOne" class="option">方案一</div>
     <div id="optionTwo" class="option">方案二</div>
     <div id="sliderButton"></div>
   </div>
</Teleport>

(2)由于设计中分割线的不同状态是不同的样式,因此仅利用原生鼠标监听事件不足以完成需求,还需要使用Cesium的事件监听。其中:鼠标左键动作:LEFT_UP、LEFT_DOWN;鼠标移动动作:MOUSE_MOVE;触摸板两指动作:PINCH_START、PINCH_END。

    const slider = document.getElementById('slider')
    const sliderButton = document.getElementById('sliderButton')
    viewer.scene.splitPosition = slider.offsetLeft / slider.parentElement.offsetWidth
    const handler = new Cesium.ScreenSpaceEventHandler(slider)

    let moveActive = false
    let left = '0' // 分割线 left 位置
    function move(movement) {
      if (!moveActive) {
        return
      }
      const relativeOffset = movement.endPosition.x
      const splitPosition = (slider.offsetLeft + relativeOffset) / slider.parentElement.offsetWidth
      left = `${100.0 * splitPosition}%`
      slider.style.left = left
      sliderButton.style.top = movement.endPosition.y - 30 + 'px'
      viewer.scene.splitPosition = splitPosition
    }

    handler.setInputAction(function () {
      moveActive = true
      slider.style.backgroundColor = '#fff'
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN)
    handler.setInputAction(function () {
      moveActive = true
      slider.style.backgroundColor = '#fff'
    }, Cesium.ScreenSpaceEventType.PINCH_START)

    handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    handler.setInputAction(move, Cesium.ScreenSpaceEventType.PINCH_MOVE)

    handler.setInputAction(function () {
      moveActive = false
      slider.style.backgroundColor = '#3953ff'
      sliderButton.style.display = 'none'
    }, Cesium.ScreenSpaceEventType.LEFT_UP)
    handler.setInputAction(function () {
      moveActive = false
      slider.style.backgroundColor = '#3953ff'
      sliderButton.style.display = 'none'
    }, Cesium.ScreenSpaceEventType.PINCH_END)

3. 加载不同类型图层资源,设置卷帘分屏

由于本次需求是在目录树中勾选方案一/方案二图层资源,因此需判断是将图层加载到分割线的左侧还是右侧。本次动图例子中,是左右两边加载相同图层,左侧透明度设置为0.7。

const splitDirection =
        state.currentRollerType === 'left' ? Cesium.SplitDirection.LEFT : Cesium.SplitDirection.RIGHT

三维图层:

tileset.splitDirection = splitDirection

影像图层: 

imageryLayer.splitDirection = splitDirection

4. 总结

以上就是基于Cesium卷帘对比的实现, ^-^  在进行卷帘对比功能的开发时,还需注意一些细节部分,如分割线拖拽到视图边缘时的处理。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要在Cesium中创建两个图层,一个用于底图,另一个用于覆盖层。然后,可以使用Cesium的Primitive API来创建一个矩形,作为卷帘特效的控制器。 接下来,需要添加一个鼠标事件监听器,当用户拖动卷帘控制器时,更新覆盖层的位置和大小,以产生卷帘特效。 最后,可以使用Tween.js等库来实现平滑的动画效果,使卷帘特效更加生动。 下面是一个示例代码,实现了一个基本的卷帘特效: ```javascript var viewer = new Cesium.Viewer('cesiumContainer'); // 创建底图图层和覆盖层 var imageryProvider = new Cesium.UrlTemplateImageryProvider({ url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', credit: 'OpenStreetMap contributors', subdomains: ['a', 'b', 'c'] }); var baseLayer = viewer.imageryLayers.addImageryProvider(imageryProvider); var overlayLayer = viewer.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url: 'https://www.gstatic.com/webp/gallery3/1.png' })); // 创建卷帘控制器 var controller = new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: new Cesium.RectangleGeometry({ rectangle: Cesium.Rectangle.fromDegrees(-100, 40, -90, 50), vertexFormat: Cesium.VertexFormat.POSITION_ONLY }), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE) } }), appearance: new Cesium.PerInstanceColorAppearance({ flat: true, translucent: true, renderState: { depthTest: { enabled: true }, lineWidth: Math.min(2.0, viewer.scene.context.maximumAliasedLineWidth) } }) }); viewer.scene.primitives.add(controller); // 添加鼠标事件监听器 var dragging = false; var startX, endX; var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); handler.setInputAction(function(event) { startX = endX = event.position.x; dragging = true; }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(function(event) { endX = event.position.x; }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function() { dragging = false; }, Cesium.ScreenSpaceEventType.LEFT_UP); // 更新覆盖层的位置和大小 viewer.clock.onTick.addEventListener(function() { if (dragging) { var controllerWidth = controller.geometryInstances.geometry.rectangle.width; var overlayWidth = overlayLayer.imageryProvider.rectangle.width; var ratio = (endX - startX) / controllerWidth; var newOverlayWidth = overlayWidth * ratio; var newOverlayWest = overlayLayer.imageryProvider.rectangle.west + overlayWidth * (ratio - 1) / 2; var newOverlayEast = newOverlayWest + newOverlayWidth; overlayLayer.imageryProvider.rectangle = Cesium.Rectangle.fromDegrees(newOverlayWest, overlayLayer.imageryProvider.rectangle.south, newOverlayEast, overlayLayer.imageryProvider.rectangle.north); } }); ``` 注意,这只是一个简单的示例,实际实现中还需要考虑一些细节问题,比如边界检查、性能优化等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值