03多层级聚合及可视域.html 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>分层聚合可视域</title>
  7. <script src="../assets/vue@2.7.14.js"></script>
  8. <script src="../../dist/index.js"></script>
  9. <style>
  10. body {
  11. margin: 0
  12. }
  13. #map {
  14. height: 100vh;
  15. }
  16. .control {
  17. position: absolute;
  18. top: 20px;
  19. left: 40px;
  20. padding: 10px 10px 0;
  21. background: #fff;
  22. }
  23. </style>
  24. </head>
  25. <body>
  26. <div id="app">
  27. <div id="map"></div>
  28. <div class="control">
  29. <button @click="toggleViewShedVisible">展示/隐藏可视域</button>
  30. <button @click="toggleCluster">{{disableCluster ? '已禁用' : '已启用'}}聚合</button>
  31. <button @click="setPointsData">设置第三层点位数据</button>
  32. <button @click="locationById">根据Id定位</button>
  33. <button @click="deSelect">取消选中</button>
  34. <button @click="getPointsInView">获取屏幕内非聚合点</button>
  35. <button @click="setSelectedCameraState">(单可视域)更改选中摄像头状态</button>
  36. <button @click="setCameraStateById">(单可视域)根据Id更改摄像头状态</button>
  37. <button @click="zoomToViewShed">缩放地图到点位可视域</button>
  38. <br>
  39. <button @click="addViewShedVisibleById">(多可视域)根据Id新增/修改可视域</button>
  40. <button @click="removeViewShedVisibleById">(多可视域)根据Id移除可视域</button>
  41. <button @click="clearViewShedVisibleById">根据Id清空可视域</button>
  42. <p>此工具兼容EPSG:3857和EPSG:4326投影,只需要传入View投影对应坐标即可</p>
  43. <p>注意:Vue项目中<b>不要</b>将地图相关实例对象赋值给响应式变量,单/多可视域方法不要混用</p>
  44. </div>
  45. </div>
  46. </body>
  47. <script>
  48. function makeRandomData(count) {
  49. return Array(count).fill('').map((item, index) => {
  50. return {
  51. id: `id${index}`, // id0,id1,id2... id属性名可自定义,locationById 方法中使用
  52. longitude: Math.random() / 2 + 116.15,
  53. latitude: Math.random() / 2 + 39.61,
  54. distance: Math.random() * 30 + 100, // 半径,单位 米
  55. heading: Math.random() * 360, // 朝向,顺时针旋转
  56. angle: Math.random() * 20 + 80, // 角度范围
  57. isWarning: Math.random() > 0.5 // 是否报警状态
  58. }
  59. })
  60. }
  61. // 将经纬度坐标转换为墨卡托投影坐标
  62. function transformProj(data) {
  63. data.forEach(item => {
  64. const coords = CTMapOl.proj.fromLonLat([item.longitude, item.latitude])
  65. item.longitude = coords[0]
  66. item.latitude = coords[1]
  67. })
  68. return data
  69. }
  70. const data1 = [
  71. { longitude: 116.05, latitude: 39.7, count: 50 },
  72. { longitude: 116.39, latitude: 39.8, count: 113 },
  73. { longitude: 116.53, latitude: 39.99, count: 88 },
  74. ]
  75. const data2 = [
  76. { longitude: 116.01, latitude: 39.5, count: 12 },
  77. { longitude: 116.12, latitude: 39.95, count: 16 },
  78. { longitude: 116.23, latitude: 39.6, count: 6 },
  79. { longitude: 116.34, latitude: 39.85, count: 6 },
  80. { longitude: 116.45, latitude: 39.7, count: 3 },
  81. { longitude: 116.56, latitude: 39.75, count: 12 },
  82. { longitude: 116.67, latitude: 39.98, count: 3 },
  83. { longitude: 116.78, latitude: 39.89, count: 12 }
  84. ]
  85. let data3 = makeRandomData(3000)
  86. // 由于 InitMap 的地图投影已改为EPSG:3857,需要将经纬度坐标转换为墨卡托投影坐标
  87. const layers = [
  88. { data: transformProj(data1), maxZoom: 10, onClick: data => { console.log(data) } },
  89. { data: transformProj(data2), minZoom: 10, maxZoom: 12, onClick: data => { console.log(data) } },
  90. { data: transformProj(data3), minZoom: 12, onClick: data => { console.log(data) } }
  91. ]
  92. new Vue({
  93. el: '#app',
  94. data() {
  95. return {
  96. guid:88,
  97. viewShedVisible: true,
  98. disableCluster: false
  99. }
  100. },
  101. mounted() {
  102. this.map = new CTMapOl.extend.InitMap({
  103. domId: 'map',
  104. zoom: 9
  105. })
  106. this.initLayers()
  107. },
  108. methods: {
  109. initLayers() {
  110. // 不要在 data 中定义 lcvs 变量,无需响应式
  111. // LayeredClusterViewShed 兼容EPSG:3857和EPSG:4326投影,只需要传入View投影对应坐标即可
  112. this.lcvs = new CTMapOl.extend.LayeredClusterViewShed(this.map.map, layers, {
  113. minViewShed: 12
  114. })
  115. },
  116. toggleViewShedVisible() {
  117. this.viewShedVisible = !this.viewShedVisible
  118. this.lcvs.setViewShedVisible(this.viewShedVisible)
  119. },
  120. toggleCluster() {
  121. this.disableCluster = !this.disableCluster
  122. this.lcvs.disableCluster(this.disableCluster)
  123. },
  124. locationById() {
  125. const feature = this.lcvs.locationById('id', 'id0')
  126. console.log('点位数据:', feature.get('data'))
  127. },
  128. deSelect() {
  129. this.lcvs.deSelectCamera()
  130. },
  131. getPointsInView() {
  132. const cameras = this.lcvs.getUnClusteredItems()
  133. console.log(cameras)
  134. },
  135. setPointsData() {
  136. data3 = transformProj(makeRandomData(3000))
  137. // 上面重新赋值data3只是为了demo 根据Id更改摄像头状态 时移动地图中心点
  138. this.lcvs.setLayerData(2, data3)
  139. },
  140. setSelectedCameraState() {
  141. this.lcvs.setSelectedCameraState({
  142. distance: Math.random() * 200 + 100,
  143. heading: Math.random() * 360,
  144. angle: Math.random() * 120,
  145. isWarning: Math.random() > 0.5
  146. })
  147. },
  148. setCameraStateById() {
  149. const index = Math.floor(Math.random() * 100)
  150. // 移动地图到目标摄像头
  151. this.map.map.getView().animate({
  152. center: [data3[index].longitude, data3[index].latitude],
  153. zoom: 17.1,
  154. duration: 200
  155. }, _ => {
  156. setTimeout(_ => {
  157. // 更新状态
  158. this.lcvs.setCameraStateById('id', `id${index}`, {
  159. heading: Math.random() * 360,
  160. angle: Math.random() * 120,
  161. isWarning: Math.random() > 0.5
  162. })
  163. }, 600)
  164. })
  165. },
  166. zoomToViewShed () {
  167. this.lcvs.zoomToViewShed('id', 'id88')
  168. },
  169. // 以下3个方法为多可视域模式方法
  170. // 请勿与 setSelectedCameraState、setCameraStateById 两个方法同时混用
  171. addViewShedVisibleById() {
  172. const index = 88
  173. // 移动地图到目标点位
  174. this.map.map.getView().animate({
  175. center: [data3[index].longitude, data3[index].latitude],
  176. zoom: 17.1,
  177. duration: 200
  178. }, _ => {
  179. setTimeout(_ => {
  180. // 新增/更新可视域
  181. this.lcvs.addViewShedVisibleById('id', `id${index}`, {
  182. guid: this.guid,
  183. distance: 200,
  184. heading: Math.random() * 360,
  185. angle: Math.random() * 120,
  186. // isWarning: Math.random() > 0.5,
  187. ishalf: Math.random() > 0.8,
  188. viewDistanceColor: 'rgba(255, 0, 6, 0.2)',
  189. viewAngleColor: 'rgba(0, 236, 6, 0.8)'
  190. })
  191. this.guid++
  192. }, 400)
  193. })
  194. },
  195. removeViewShedVisibleById(){
  196. this.lcvs.removeViewShedVisibleById('id', `id${index}`, {
  197. guid: --this.guid,
  198. })
  199. },
  200. clearViewShedVisibleById() {
  201. const index = 88
  202. this.lcvs.clearViewShedVisibleById('id', `id${index}`)
  203. }
  204. }
  205. })
  206. </script>
  207. </html>