ArcGIS API 4.x实现SceneView的卷帘功能

mac2024-03-29  28

本篇博客主要是在ArcGIS API 4.12的环境下, 实现卷帘功能

话不多说, 上代码

<!DOCTYPE html> <html> <head> <style> html, body { padding: 0; margin: 0; height: 100%; } /* 垂直分割线 */ .vertical_line{ position: absolute; top: 12%; left: 45%; bottom: 4.2%; z-index: 1; float:left; width: 10px; background-color: rgba(50,50,50,0.75); user-select: none; } /* 设置存放地图div的样式 */ #esri_view_div { position: absolute; top: 12%; bottom: 4.5%; left: 2.4%; right: 2.4%; } /* 圆按钮 */ .circle { width: 30px; height: 30px; background-color: rgba(50,50,50,0.75); border-radius: 50%; position: absolute; top: 40%; left: 40%; bottom: 4.2%; z-index: 2; margin-left: -10px; user-select: none; } #esri_view_div_swipe { position: absolute; top: 12%; bottom: 4.5%; left: 2.4%; right: 2.4%; z-index: -1; } /* 左箭头 */ .triangle-left { width: 0; height: 0; border-top: 4px solid transparent; border-right: 7px solid white; border-bottom: 4px solid transparent; position: absolute; top: 40%; margin-left: -8px; margin-top: 12px; z-index: 3; user-select: none; } /* 右箭头 */ .triangle-right { width: 0; height: 0; border-top: 4px solid transparent; border-left: 7px solid white; border-bottom: 4px solid transparent; position: absolute; top: 40%; margin-left: 10px; margin-top: 12px; z-index: 3; user-select: none; } </style> <link rel="stylesheet" href="https://js.arcgis.com/4.12/esri/themes/light/main.css" /> <script src="https://js.arcgis.com/4.12/"></script> <script> require([ "esri/Map", "esri/views/SceneView", "esri/core/watchUtils", 'dojo/dom-style', ], function(Map, SceneView, watchUtils, EsriDomStyle) { var esriContainerDiv = 'esri_view_div' var esriSwipeContainerDiv = 'esri_view_div_swipe' var map = new Map({ basemap: "satellite" }); var map2 = new Map({ basemap: "osm" }); var view1 = new SceneView({ container: "esri_view_div", map: map }); var view2 = new SceneView({ container: esriSwipeContainerDiv, map: map2, }); view1.ui.remove(['attribution', 'zoom', 'navigation-toggle', 'compass']) view2.ui.remove(['attribution', 'zoom', 'navigation-toggle', 'compass']) var isSlitLineDragging = false // 分割线移动状态 document.getElementById('swipe_split_box').onmousedown = function () { isSlitLineDragging = true } document.getElementById('swipe_split_box').onmouseup = function() { isSlitLineDragging = false } /** * 分割线移动事件 * @param {Object} e 分割线移动事件对象 */ function pointMove(e) { e.stopPropagation() updateMapSwipeLocation(e.x) }; /** * 更新卷帘地图容器展开位置 * @param {Number} location 当前的位置 * @param {Boolean} isInit 是否是初始化 */ function updateMapSwipeLocation(location, isInit) { const swipeMap = document.getElementById(esriSwipeContainerDiv).getBoundingClientRect() const offsetX = location if (isSlitLineDragging || isInit) { EsriDomStyle.set(esriSwipeContainerDiv, 'z-index', '1') EsriDomStyle.set(esriSwipeContainerDiv, 'clip', 'rect(0px,' + offsetX + 'px, ' + swipeMap.height + 'px,0px)') EsriDomStyle.set('vertical_line', 'left', (offsetX - 5 + (swipeMap.width * 0.024)) + 'px ') EsriDomStyle.set('swipe_circle', 'left', (offsetX - 5 + (swipeMap.width * 0.024)) + 'px ') EsriDomStyle.set('swipe_triangle_left', 'left', (offsetX - 5 + (swipeMap.width * 0.024)) + 'px ') EsriDomStyle.set('swipe_triangle_right', 'left', (offsetX - 5 + (swipeMap.width * 0.024)) + 'px ') } }; /** * 同步两个视图容器 * @param {Object} view 视图容器 * @param {Object} others 其它的视图容器 * @return {Object} 监听事件 */ function synchronizeView(view, others) { others = Array.isArray(others) ? others : [others] let viewpointWatchHandle let viewStationaryHandle let otherInteractHandlers let scheduleId const clear = function() { if (otherInteractHandlers) { otherInteractHandlers.forEach(function(handle) { handle.remove() }) } viewpointWatchHandle && viewpointWatchHandle.remove() viewStationaryHandle && viewStationaryHandle.remove() scheduleId && clearTimeout(scheduleId) otherInteractHandlers = viewpointWatchHandle = viewStationaryHandle = scheduleId = null } const interactWatcher = view.watch('interacting, animation', (newValue) => { if (!newValue) { return } if (viewpointWatchHandle || scheduleId) { return } // start updating the other views at the next frame scheduleId = setTimeout(function() { scheduleId = null viewpointWatchHandle = view.watch('viewpoint', (newValue) => { others.forEach(function(otherView) { otherView.viewpoint = newValue }) }) }, 0) const that = this // stop as soon as another view starts interacting, like if the user starts panning otherInteractHandlers = others.map(function(otherView) { return watchUtils.watch(otherView, 'interacting,animation', (value) => { if (value) { clear() } } ) }) // or stop when the view is stationary again viewStationaryHandle = watchUtils.whenTrue(view, 'stationary', clear) }) return { remove: function() { this.remove = function() {} clear() interactWatcher.remove() }, } }; /** * 同步两个视图容器入口函数 * @param {Object} views 多个视图容器 * @return {Object} 移除事件 */ function synchronizeViews(views) { let handles = views.map(function(view, idx, views) { const others = views.concat() others.splice(idx, 1) return synchronizeView(view, others) }) return { remove: function() { this.remove = function() {} handles.forEach(function(h) { h.remove() }) handles = null }, } }; view1.on('pointer-move', (e) => { pointMove(e) }) view2.on('pointer-move', (e) => { pointMove(e) }) // 设置初始位置 const swipeMap = document.getElementById(esriSwipeContainerDiv).getBoundingClientRect() updateMapSwipeLocation(swipeMap.width * 0.5, true) // 同步视图 synchronizeViews([view1, view2]) }) </script> </head> <body> <div id='esri_view_div'></div> <div id='esri_view_div_swipe'></div> <div id="swipe_split_box"> <div id="vertical_line" class="vertical_line"></div> <div id="swipe_circle" class="circle"></div> <div id="swipe_triangle_left" class="triangle-left"></div> <div id="swipe_triangle_right" class="triangle-right"></div> </div> </body> </html>

总结

卷帘实现主要分为两个部分    1. 视图容器Div的Clip       1) 开始卷帘, 即使用最关键的功能: css的clip属性, 将视图容器的div进行切分以实现卷帘       2) 初始化视图容器esriSceneView和地图分割线的位置, 使之出现在中间       3) 在按下分割线的时候, 使之进入拖动状态, 拖动状态时计算当前鼠标位置, 以及根据计算到的位置进行设置视图容器的clip: rect属性       关于clip: rect的几个参数说明https://www.zhangxinxu.com/study/201103/css-rect-demo.html       4) 结束拖动, 关闭拖动状态   2. 两个视图容器的联动       1) 通过两个view互相监听interacting, animation两个属性,            当着两个属性变化的时候获得该视图容器的viewpoint, 同步设置另一个视图容器的viewpoint       注: interacting : boolean, 指示是否与视图交互(例如平移时)。             animation: ViewAnimation, 表示由goTo()初始化的正在进行的视图动画。

最新回复(0)