index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. <template>
  2. <div>
  3. <a-card :bordered="false" style="margin-bottom: 10px;">
  4. <div class="table-page-search-wrapper" style="height: 8vh; width: 100%">
  5. <a-steps
  6. type="navigation"
  7. :current="stepArr.length"
  8. >
  9. <a-step v-for="(item, index) in stepArr" :key="index" :title="item.title" :status="item.status" >
  10. <a-icon slot="icon" type="interation" />
  11. </a-step>
  12. </a-steps>
  13. </div>
  14. </a-card>
  15. <a-card :bordered="false" class="table-card">
  16. <div style="height: 80vh; width: 100%" id="container"></div>
  17. <div id="toolControl">
  18. <!-- <div class="toolItem" id="markers" title="开始" @click="beginMove"></div>-->
  19. <div class="toolItem active" id="marker" title="点标记" @click="selectDragType('marker')"></div>
  20. <div class="toolItem" id="polyline" title="折线" @click="selectDragType('polyline')"></div>
  21. <div class="toolItem" id="polygon" title="多边形" @click="selectDragType('polygon')"></div>
  22. <div class="toolItem" id="circle" title="圆形" @click="selectDragType('circle')"></div>
  23. <div class="toolItem" id="rectangle" title="矩形" @click="selectDragType('rectangle')"></div>
  24. <div class="toolItem" id="ellipse" title="椭圆" @click="selectDragType('ellipse')"></div>
  25. </div>
  26. <div class="control">
  27. <button @click="beginMove" class="beginMove" :disabled="moved">航线模拟</button>
  28. <button @click="stopMove" class="stopMove">终止模拟</button>
  29. <button @click="pauseMove" class="pauseMove">暂停模拟</button>
  30. <button @click="resumeMove" class="resumeMove">恢复模拟</button>
  31. <button @click="resetMap" class="resumeMove">重置</button>
  32. </div>
  33. </a-card>
  34. </div>
  35. </template>
  36. <script>
  37. /* eslint-disable */
  38. import { getAllSysWharf } from '@/api/system/sysWharf'
  39. import { getRouteLine, addRouteLine } from '@/api/system/line'
  40. export default {
  41. name: 'RouterLine',
  42. data() {
  43. return {
  44. open: false,
  45. model: null,
  46. path: [],
  47. roation: null,
  48. center: null,
  49. map: null,
  50. editor: null,
  51. activeType: 'marker',
  52. sysWharfList: [],
  53. stepArr: [],
  54. markerLayer: null,
  55. customPath:[],
  56. moved: true
  57. }
  58. },
  59. filters: {
  60. },
  61. mounted() {
  62. // 确保腾讯地图SDK已加载
  63. /*const script = document.createElement('script')
  64. script.type = 'text/javascript'
  65. script.src = 'https://map.qq.com/api/gljs?libraries=tools,geometry,model&v=1.exp&key=A7PBZ-WLKKC-XW52U-A5BML-XLALT-2DF2Q'
  66. document.body.appendChild(script)*/
  67. this.initMap()
  68. // this.initMap2()
  69. // this.getListSysWharf()
  70. },
  71. created() {
  72. },
  73. methods: {
  74. addLine() {
  75. addRouteLine(this.customPath).then((response) => {
  76. this.customPath = []
  77. this.getLinePath()
  78. })
  79. },
  80. getLinePath() {
  81. this.path = []
  82. getRouteLine().then((response) => {
  83. this.path = response.data
  84. // 添加路径 开始 结束 图标
  85. if (this.path.length > 1) {
  86. this.markRoutePath(this.path)
  87. }
  88. })
  89. },
  90. getListSysWharf() {
  91. this.sysWharfList = []
  92. this.stepArr = []
  93. getAllSysWharf().then((response) => {
  94. this.sysWharfList = response.data
  95. // 显示码头数据
  96. this.stepArr = this.sysWharfList.map((item) => {
  97. return {
  98. title: item.wharfNanme,
  99. status: 'finish'
  100. }
  101. })
  102. // 标记码头点
  103. this.markPoint(this.sysWharfList)
  104. })
  105. },
  106. selectDragType(type) {
  107. document.getElementById(this.activeType).className = 'toolItem'
  108. document.getElementById(type).className = 'toolItem active'
  109. this.activeType = type
  110. this.editor.setActiveOverlay(type)
  111. this.editor.enable()
  112. },
  113. beginMove() {
  114. const paths = this.path.map((item) => {
  115. return {
  116. position: new TMap.LatLng(item.lat, item.lng)
  117. }
  118. })
  119. this.model.moveAlong({
  120. // 移动过程中每个节点的坐标
  121. path: paths,
  122. duration: 15000, // 完成移动所需的时间 单位毫秒
  123. degreeToNorth: 180 // 把模型正方向旋转至正北方向所需的角度 默认为0
  124. })
  125. },
  126. stopMove() {
  127. if (this.model){
  128. this.model.stopMove();
  129. }
  130. },
  131. pauseMove() {
  132. if (this.model){
  133. this.model.pauseMove();
  134. }
  135. },
  136. resumeMove() {
  137. if (this.model){
  138. this.model.resumeMove();
  139. }
  140. },
  141. resetMap() {
  142. this.$router.go(0)
  143. },
  144. markPoint(pointArr) {
  145. const geometries = pointArr.map((item) =>{
  146. return {
  147. "id": item.id, //点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
  148. "position": new window.TMap.LatLng(Number(item.lat), Number(item.lng)), //点标记坐标位置
  149. styleId: 'small',
  150. content: item.wharfNanme
  151. }
  152. })
  153. this.markerLayer = new window.TMap.MultiMarker({
  154. map: this.map, //指定地图容器
  155. styles: {
  156. small: new window.TMap.MarkerStyle({
  157. // 点标注的相关样式
  158. width: 34, // 宽度
  159. height: 46, // 高度
  160. anchor: { x: 17, y: 23 }, // 标注点图片的锚点位置
  161. color: '#333', // 标注点文本颜色
  162. size: 16, // 标注点文本文字大小
  163. direction: 'bottom', // 标注点文本文字相对于标注点图片的方位
  164. strokeColor: '#fff', // 标注点文本描边颜色
  165. strokeWidth: 2, // 标注点文本描边宽度
  166. }),
  167. big: new window.TMap.MarkerStyle({
  168. width: 58,
  169. height: 76,
  170. anchor: { x: 36, y: 32 },
  171. color: '#333',
  172. size: 22,
  173. direction: 'bottom',
  174. strokeColor: '#fff',
  175. offset: { x: 0, y: 10 },
  176. strokeWidth: 2,
  177. }),
  178. },
  179. //点标记数据数组
  180. geometries: geometries
  181. });
  182. },
  183. markRoutePath(pathArr) {
  184. const _this = this
  185. // 添加起点和终点 - 开始
  186. const startPosition = new window.TMap.LatLng(pathArr[0].lat, pathArr[0].lng) // 路线规划起点
  187. const endPosition = new window.TMap.LatLng(pathArr[pathArr.length -1].lat, pathArr[pathArr.length -1].lng) // 路线规划终点
  188. new window.TMap.MultiMarker({
  189. // 创造MultiMarker显示起终点标记
  190. id: 'marker-layer',
  191. map: _this.map,
  192. styles: {
  193. start: new TMap.MarkerStyle({
  194. width: 25,
  195. height: 35,
  196. anchor: { x: 16, y: 32 },
  197. src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/start.png'
  198. }),
  199. end: new TMap.MarkerStyle({
  200. width: 25,
  201. height: 35,
  202. anchor: { x: 16, y: 32 },
  203. src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/end.png'
  204. })
  205. },
  206. geometries: [
  207. {
  208. id: 'start',
  209. styleId: 'start',
  210. position: startPosition
  211. },
  212. {
  213. id: 'end',
  214. styleId: 'end',
  215. position: endPosition
  216. }
  217. ]
  218. })
  219. // 添加起点和终点 - 结束
  220. // 创建 MultiPolyline显示路径折线
  221. new window.TMap.MultiPolyline({
  222. id: 'polyline-layer',
  223. map: _this.map,
  224. styles: {
  225. style_blue: new TMap.PolylineStyle({
  226. color: '#3777FF',
  227. width: 8,
  228. borderWidth: 5,
  229. borderColor: '#FFF',
  230. lineCap: 'butt',
  231. showArrow: true
  232. })
  233. },
  234. geometries: [
  235. {
  236. id: 'pl_1',
  237. styleId: 'style_blue',
  238. paths: _this.path
  239. }
  240. ]
  241. })
  242. // 创建 MultiPolyline显示路径折线 结束
  243. this.model = new window.TMap.model.GLTFModel({
  244. // url: 'http://127.0.0.1:18080/profile/upload/2024/03/16/scene.gltf',
  245. url: 'https://mapapi.qq.com/web/jsapi/jsapi-gl/assets/car.gltf',
  246. map: _this.map,
  247. id: 'model',
  248. position: startPosition, // 模型初始位置
  249. rotation: [0, 130, 0], // 模型XYZ三轴上的旋转角度
  250. scale: 10 // 模型在XYZ三轴上的缩放比例
  251. })
  252. // model资源加载完成回调
  253. this.model.on('loaded', () => {
  254. console.log('模型加载成功')
  255. // 启用模型沿线移动演示
  256. // MoveButton.disabled = false
  257. _this.moved = false
  258. })
  259. this.model.on('moving', function (e) {
  260. if (!e.passedPath) return
  261. // geometry文档地址:https://lbs.qq.com/webApi/javascriptGL/glDoc/glDocGeometry
  262. _this.roation = TMap.geometry.computeHeading(
  263. // 计算两点之间的航向
  264. e.passedPath[e.passedPath.length - 2].position,
  265. e.passedPath[e.passedPath.length - 1].position
  266. )
  267. _this.center = TMap.geometry.computeDestination(
  268. // 根据起点、朝向和距离计算终点
  269. e.passedPath[e.passedPath.length - 1].position,
  270. _this.roation,
  271. 60
  272. )
  273. _this.map.easeTo(
  274. // 平滑过渡到指定状态
  275. {
  276. center: _this.center,
  277. rotation: e.rotation[1] + 180,
  278. zoom: 20,
  279. pitch: 70
  280. },
  281. {
  282. duration: 300
  283. }
  284. )
  285. })
  286. },
  287. initMap() {
  288. // 设置地图中心点
  289. const center = new TMap.LatLng(36.092574, 103.728268)
  290. // 定义工厂模式函数
  291. const myOptions = {
  292. zoom: 17, // 设置地图缩放级别
  293. center: center
  294. }
  295. // 初始化重新定位
  296. this.map = new TMap.Map('container', myOptions)
  297. // 初始化几何图形及编辑器
  298. const marker = new TMap.MultiMarker({
  299. map: this.map
  300. })
  301. const polyline = new TMap.MultiPolyline({
  302. map: this.map
  303. })
  304. const polygon = new TMap.MultiPolygon({
  305. map: this.map
  306. })
  307. const circle = new TMap.MultiCircle({
  308. map: this.map
  309. })
  310. const rectangle = new TMap.MultiRectangle({
  311. map: this.map
  312. })
  313. const ellipse = new TMap.MultiEllipse({
  314. map: this.map
  315. })
  316. this.editor = new TMap.tools.GeometryEditor({
  317. // TMap.tools.GeometryEditor 文档地址:https://lbs.qq.com/webApi/javascriptGL/glDoc/glDocEditor
  318. map: this.map, // 编辑器绑定的地图对象
  319. overlayList: [
  320. // 可编辑图层 文档地址:https://lbs.qq.com/webApi/javascriptGL/glDoc/glDocEditor#4
  321. {
  322. overlay: marker,
  323. id: 'marker'
  324. },
  325. {
  326. overlay: polyline,
  327. id: 'polyline'
  328. },
  329. {
  330. overlay: polygon,
  331. id: 'polygon'
  332. },
  333. {
  334. overlay: circle,
  335. id: 'circle'
  336. },
  337. {
  338. overlay: rectangle,
  339. id: 'rectangle'
  340. },
  341. {
  342. overlay: ellipse,
  343. id: 'ellipse'
  344. }
  345. ],
  346. actionMode: TMap.tools.constants.EDITOR_ACTION.DRAW, // 编辑器的工作模式
  347. activeOverlayId: 'marker', // 激活图层
  348. snappable: true // 开启吸附
  349. })
  350. this.editor.on('draw_complete', (geometry) => {
  351. // 判断当前处于编辑状态的图层id是否是overlayList中id为rectangle(矩形)图层
  352. // 判断当前处于编辑状态的图层id是否是overlayList中id为rectangle(矩形)图层
  353. const id = geometry.id
  354. if (this.editor.getActiveOverlay().id === 'rectangle') {
  355. // 获取矩形顶点坐标
  356. const geo = rectangle.geometries.filter(function (item) {
  357. return item.id === id
  358. })
  359. console.log('绘制的矩形定位的坐标:', geo[0].paths)
  360. }
  361. if (this.editor.getActiveOverlay().id === 'polygon') {
  362. // 获取多边形顶点坐标
  363. const geo = polygon.geometries.filter(function (item) {
  364. return item.id === id
  365. })
  366. console.log('绘制的多边形坐标:', geo[0].paths)
  367. }
  368. const _this = this
  369. if (this.editor.getActiveOverlay().id === 'polyline') {
  370. // 获取折线路径坐标
  371. console.log('绘制的多边形坐标:', geometry.paths)
  372. this.customPath.push(...geometry.paths)
  373. console.log('当前路径Path:', this.customPath)
  374. // 开始添加 路线规划的覆盖层
  375. this.$confirm({
  376. title: '是否继续设置航线?',
  377. zIndex:1002,
  378. onOk () {
  379. _this.editor.enable()
  380. },
  381. onCancel () {
  382. _this.editor.disable()
  383. _this.$confirm({
  384. title: '是否保存航线?',
  385. zIndex:1003,
  386. onOk () {
  387. _this.addLine()
  388. },
  389. onCancel () {
  390. console.log('取消保存航线')
  391. }
  392. })
  393. }
  394. })
  395. }
  396. })
  397. this.editor.disable()
  398. this.getListSysWharf()
  399. this.getLinePath()
  400. }
  401. }
  402. }
  403. </script>
  404. <style scoped lang="less">
  405. #toolControl {
  406. position: absolute;
  407. top: 10px;
  408. left: 0px;
  409. right: 0px;
  410. margin: auto;
  411. width: 380px;
  412. z-index: 1001;
  413. }
  414. .toolItem {
  415. width: 42px;
  416. height: 42px;
  417. float: left;
  418. margin: 1px;
  419. padding: 4px;
  420. border-radius: 3px;
  421. background-size: 30px 30px;
  422. background-position: 4px 4px;
  423. background-repeat: no-repeat;
  424. box-shadow: 0 1px 2px 0 #e4e7ef;
  425. background-color: #ffffff;
  426. border: 1px solid #ffffff;
  427. }
  428. .toolItem:hover {
  429. border-color: #789cff;
  430. }
  431. .active {
  432. border-color: #d5dff2;
  433. background-color: #d5dff2;
  434. }
  435. #marker {
  436. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/marker_editor.png');
  437. }
  438. #polyline {
  439. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/polyline.png');
  440. }
  441. #polygon {
  442. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/polygon.png');
  443. }
  444. #circle {
  445. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/circle.png');
  446. }
  447. #rectangle {
  448. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/rectangle.png');
  449. }
  450. #ellipse {
  451. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/ellipse.png');
  452. }
  453. #markers {
  454. background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/marker_editor.png');
  455. }
  456. .control {
  457. position: absolute;
  458. left: 0px;
  459. top: 0px;
  460. z-index: 9999;
  461. padding: 10px;
  462. }
  463. .control button {
  464. padding: 10px 14px;
  465. box-sizing: border-box;
  466. border: none;
  467. background-color: #919aac;
  468. border-radius: 2px;
  469. color: #fff;
  470. font-size: 14px;
  471. line-height: 14px;
  472. cursor: pointer;
  473. margin-left: 6px;
  474. }
  475. .control .beginMove {
  476. background: #3876ff;
  477. }
  478. .control .stopMove {
  479. background: #ff0000;
  480. }
  481. </style>