test.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Vue2 高德地图地区查询与绘制</title>
  7. <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
  8. <script src="https://webapi.amap.com/maps?v=2.0&key=b96a1c32b0bb828f1d153b219fa59ecc&plugin=AMap.ElasticMarker,AMap.PolygonEditor,AMap.DistrictSearch,AMap.ToolBar, AMap.Scale, AMap.MouseTool, AMap.Geocoder,AMap.Zoom"></script>
  9. <style>
  10. * {
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
  15. }
  16. body {
  17. background-color: #f5f7fa;
  18. color: #333;
  19. line-height: 1.6;
  20. }
  21. .container {
  22. max-width: 1200px;
  23. margin: 0 auto;
  24. padding: 20px;
  25. }
  26. header {
  27. text-align: center;
  28. margin-bottom: 30px;
  29. padding: 20px;
  30. background: linear-gradient(135deg, #1e5799 0%, #207cca 100%);
  31. color: white;
  32. border-radius: 10px;
  33. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  34. }
  35. h1 {
  36. font-size: 2.2rem;
  37. margin-bottom: 10px;
  38. }
  39. .subtitle {
  40. font-size: 1.1rem;
  41. opacity: 0.9;
  42. }
  43. .app-container {
  44. display: flex;
  45. flex-direction: column;
  46. gap: 20px;
  47. }
  48. .search-panel {
  49. background: white;
  50. padding: 20px;
  51. border-radius: 10px;
  52. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
  53. }
  54. .search-box {
  55. display: flex;
  56. gap: 10px;
  57. margin-bottom: 15px;
  58. }
  59. .search-input {
  60. flex: 1;
  61. padding: 12px 15px;
  62. border: 1px solid #ddd;
  63. border-radius: 6px;
  64. font-size: 16px;
  65. transition: border-color 0.3s;
  66. }
  67. .search-input:focus {
  68. outline: none;
  69. border-color: #1e5799;
  70. box-shadow: 0 0 0 2px rgba(30, 87, 153, 0.2);
  71. }
  72. .search-btn, .draw-btn, .clear-btn, .edit-btn {
  73. padding: 12px 20px;
  74. background: #1e5799;
  75. color: white;
  76. border: none;
  77. border-radius: 6px;
  78. cursor: pointer;
  79. font-size: 16px;
  80. transition: background 0.3s;
  81. }
  82. .search-btn:hover, .draw-btn:hover, .edit-btn:hover {
  83. background: #16457a;
  84. }
  85. .clear-btn {
  86. background: #e74c3c;
  87. }
  88. .clear-btn:hover {
  89. background: #c0392b;
  90. }
  91. .edit-btn.active {
  92. background: #27ae60;
  93. }
  94. .map-container {
  95. height: 500px;
  96. border-radius: 10px;
  97. overflow: hidden;
  98. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  99. }
  100. .controls {
  101. display: flex;
  102. gap: 10px;
  103. margin-top: 15px;
  104. flex-wrap: wrap;
  105. }
  106. .results-panel {
  107. background: white;
  108. padding: 20px;
  109. border-radius: 10px;
  110. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
  111. max-height: 200px;
  112. overflow-y: auto;
  113. }
  114. .result-item {
  115. padding: 10px 15px;
  116. border-bottom: 1px solid #eee;
  117. cursor: pointer;
  118. transition: background 0.2s;
  119. }
  120. .result-item:hover {
  121. background: #f0f7ff;
  122. }
  123. .result-item:last-child {
  124. border-bottom: none;
  125. }
  126. .instructions {
  127. background: white;
  128. padding: 20px;
  129. border-radius: 10px;
  130. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
  131. margin-top: 20px;
  132. }
  133. .instructions h3 {
  134. color: #1e5799;
  135. margin-bottom: 10px;
  136. }
  137. .instructions ul {
  138. padding-left: 20px;
  139. }
  140. .instructions li {
  141. margin-bottom: 8px;
  142. }
  143. .status {
  144. margin-top: 10px;
  145. padding: 10px;
  146. border-radius: 6px;
  147. background: #e8f4fd;
  148. color: #1e5799;
  149. }
  150. .drawing-status {
  151. background: #fff8e1;
  152. color: #ff9800;
  153. }
  154. .editing-status {
  155. background: #e8f6f3;
  156. color: #27ae60;
  157. }
  158. @media (min-width: 768px) {
  159. .app-container {
  160. flex-direction: row;
  161. }
  162. .search-panel {
  163. width: 300px;
  164. flex-shrink: 0;
  165. }
  166. .map-container {
  167. flex: 1;
  168. }
  169. }
  170. </style>
  171. </head>
  172. <body>
  173. <div id="app" class="container">
  174. <header>
  175. <h1>Vue2 高德地图地区查询与绘制</h1>
  176. <p class="subtitle">搜索地区并在高德地图上绘制区域边界</p>
  177. </header>
  178. <div class="app-container">
  179. <div class="search-panel">
  180. <h3>地区搜索</h3>
  181. <div class="search-box">
  182. <input
  183. type="text"
  184. class="search-input"
  185. placeholder="输入地区名称,如:北京市朝阳区"
  186. v-model="searchKeyword"
  187. @keyup.enter="searchPlace"
  188. >
  189. <button class="search-btn" @click="searchPlace">搜索</button>
  190. </div>
  191. <div class="controls">
  192. <button class="draw-btn" @click="toggleDrawingMode">
  193. {{ drawingMode ? '退出绘制模式' : '进入绘制模式' }}
  194. </button>
  195. <button class="edit-btn" :class="{active: editingMode}" @click="toggleEditingMode">
  196. {{ editingMode ? '退出编辑模式' : '进入编辑模式' }}
  197. </button>
  198. <button class="clear-btn" @click="clearMap">清除地图</button>
  199. </div>
  200. <div class="status" :class="statusClass">
  201. {{ statusMessage }}
  202. </div>
  203. <div class="results-panel" v-if="searchResults.length > 0">
  204. <h4>搜索结果 ({{ searchResults.length }})</h4>
  205. <div
  206. class="result-item"
  207. v-for="(result, index) in searchResults"
  208. :key="index"
  209. @click="selectResult(result)"
  210. >
  211. <strong>{{ result.name }}</strong><br>
  212. <small>{{ result.district }}{{ result.address }}</small>
  213. </div>
  214. </div>
  215. </div>
  216. <div class="map-container" id="map-container"></div>
  217. </div>
  218. <div class="instructions">
  219. <h3>使用说明</h3>
  220. <ul>
  221. <li>在搜索框中输入地区名称(如"北京市朝阳区")并点击搜索或按Enter键</li>
  222. <li>点击搜索结果项可在地图上定位到该地区</li>
  223. <li>点击"进入绘制模式"可手动在地图上绘制多边形区域</li>
  224. <li>绘制完成后,点击第一个点或双击可完成绘制</li>
  225. <li>点击"进入编辑模式"可选择并编辑已绘制的区域</li>
  226. <li>点击"清除地图"可移除所有标记和绘制区域</li>
  227. </ul>
  228. </div>
  229. </div>
  230. <script type="text/javascript">
  231. window._AMapSecurityConfig = {
  232. serviceHost: 'http://47.110.79.22:9000/_AMapService',
  233. }
  234. </script>
  235. <script>
  236. // 请替换为您的高德地图API密钥
  237. const AMAP_KEY = 'b96a1c32b0bb828f1d153b219fa59ecc';
  238. new Vue({
  239. el: '#app',
  240. data: {
  241. map: null,
  242. searchKeyword: '',
  243. searchResults: [],
  244. drawingMode: false,
  245. editingMode: false,
  246. mouseTool: null,
  247. polygonEditor: null,
  248. polygons: [],
  249. markers: [],
  250. selectedPolygon: null,
  251. statusMessage: '请输入地区名称进行搜索',
  252. statusClass: ''
  253. },
  254. computed: {
  255. statusClass() {
  256. if (this.drawingMode) return 'drawing-status';
  257. if (this.editingMode) return 'editing-status';
  258. return '';
  259. }
  260. },
  261. mounted() {
  262. this.initMap();
  263. },
  264. methods: {
  265. initMap() {
  266. // 初始化地图
  267. this.map = new AMap.Map('map-container', {
  268. zoom: 10,
  269. center: [116.397428, 39.90923], // 默认中心点(北京)
  270. viewMode: '3D'
  271. });
  272. // 添加缩放控件
  273. // this.map.addControl(new AMap.Zoom());
  274. // 添加比例尺控件
  275. this.map.addControl(new AMap.Scale());
  276. // 初始化鼠标工具
  277. this.mouseTool = new AMap.MouseTool(this.map);
  278. // 监听绘制完成事件
  279. this.mouseTool.on('draw', (event) => {
  280. if (event.obj instanceof AMap.Polygon) {
  281. const polygon = event.obj;
  282. this.polygons.push(polygon);
  283. // 添加右键菜单删除功能
  284. this.addPolygonContextMenu(polygon);
  285. this.statusMessage = `已绘制区域,顶点数: ${polygon.getPath().length}`;
  286. // 自动退出绘制模式
  287. this.drawingMode = false;
  288. }
  289. });
  290. this.statusMessage = '地图加载完成,请输入地区名称进行搜索';
  291. },
  292. searchPlace() {
  293. if (!this.searchKeyword.trim()) {
  294. this.statusMessage = '请输入搜索关键词';
  295. return;
  296. }
  297. this.statusMessage = '搜索中...';
  298. // 使用高德地图PlaceSearch插件进行搜索
  299. AMap.plugin('AMap.PlaceSearch', () => {
  300. const placeSearch = new AMap.PlaceSearch({
  301. pageSize: 10,
  302. pageIndex: 1,
  303. citylimit: false
  304. });
  305. placeSearch.search(this.searchKeyword, (status, result) => {
  306. if (status === 'complete' && result.poiList && result.poiList.pois) {
  307. this.searchResults = result.poiList.pois;
  308. this.statusMessage = `找到 ${this.searchResults.length} 个结果`;
  309. } else {
  310. this.searchResults = [];
  311. this.statusMessage = '未找到相关结果,请尝试其他关键词';
  312. }
  313. });
  314. });
  315. },
  316. selectResult(result) {
  317. // 清除之前的标记
  318. this.clearMarkers();
  319. // 添加标记
  320. const marker = new AMap.Marker({
  321. position: [result.location.lng, result.location.lat],
  322. title: result.name,
  323. map: this.map
  324. });
  325. this.markers.push(marker);
  326. // 移动到标记位置
  327. this.map.setZoom(15);
  328. this.map.setCenter([result.location.lng, result.location.lat]);
  329. this.statusMessage = `已定位到: ${result.name}`;
  330. },
  331. toggleDrawingMode() {
  332. if (this.editingMode) {
  333. this.toggleEditingMode(); // 先退出编辑模式
  334. }
  335. this.drawingMode = !this.drawingMode;
  336. if (this.drawingMode) {
  337. // 进入绘制模式
  338. this.mouseTool.polygon({
  339. strokeColor: '#1e5799',
  340. strokeOpacity: 1,
  341. strokeWeight: 3,
  342. fillColor: '#1e5799',
  343. fillOpacity: 0.3,
  344. strokeStyle: 'solid'
  345. });
  346. this.statusMessage = '绘制模式:请在地图上点击绘制多边形区域,双击或点击第一个点完成绘制';
  347. } else {
  348. // 退出绘制模式
  349. this.mouseTool.close(true);
  350. this.statusMessage = '已退出绘制模式';
  351. }
  352. },
  353. toggleEditingMode() {
  354. if (this.drawingMode) {
  355. this.toggleDrawingMode(); // 先退出绘制模式
  356. }
  357. this.editingMode = !this.editingMode;
  358. if (this.editingMode) {
  359. this.statusMessage = '编辑模式:请点击要编辑的多边形区域';
  360. // 为所有多边形添加点击事件
  361. this.polygons.forEach(polygon => {
  362. polygon.on('click', () => {
  363. this.startEditPolygon(polygon);
  364. });
  365. });
  366. } else {
  367. this.stopEditPolygon();
  368. this.statusMessage = '已退出编辑模式';
  369. }
  370. },
  371. startEditPolygon(polygon) {
  372. // 停止之前的编辑
  373. this.stopEditPolygon();
  374. // 开始编辑选中的多边形
  375. this.selectedPolygon = polygon;
  376. // 加载PolyEditor插件
  377. AMap.plugin('AMap.PolyEditor', () => {
  378. this.polygonEditor = new AMap.PolyEditor(this.map, polygon);
  379. this.polygonEditor.open();
  380. this.statusMessage = '正在编辑多边形,拖动顶点或边进行调整';
  381. // 监听编辑事件
  382. this.polygonEditor.on('adjust', (event) => {
  383. this.statusMessage = '正在调整多边形顶点';
  384. });
  385. this.polygonEditor.on('end', (event) => {
  386. this.statusMessage = `编辑完成,当前顶点数: ${polygon.getPath().length}`;
  387. });
  388. });
  389. },
  390. stopEditPolygon() {
  391. if (this.polygonEditor) {
  392. this.polygonEditor.close();
  393. this.polygonEditor = null;
  394. }
  395. this.selectedPolygon = null;
  396. // 移除多边形的点击事件
  397. this.polygons.forEach(polygon => {
  398. polygon.off('click');
  399. });
  400. },
  401. addPolygonContextMenu(polygon) {
  402. // 添加右键菜单删除功能
  403. polygon.on('rightclick', (e) => {
  404. // 创建右键菜单
  405. const menu = new AMap.ContextMenu();
  406. menu.addItem("删除此区域", () => {
  407. // 从地图移除
  408. polygon.setMap(null);
  409. // 从数组中移除
  410. const index = this.polygons.indexOf(polygon);
  411. if (index > -1) {
  412. this.polygons.splice(index, 1);
  413. }
  414. this.statusMessage = '已删除选中区域';
  415. // 如果正在编辑此多边形,停止编辑
  416. if (this.selectedPolygon === polygon) {
  417. this.stopEditPolygon();
  418. this.editingMode = false;
  419. }
  420. }, 0);
  421. // 在点击位置打开菜单
  422. menu.open(this.map, e.lnglat);
  423. });
  424. },
  425. clearMap() {
  426. // 清除所有标记
  427. this.clearMarkers();
  428. // 清除所有多边形
  429. this.clearPolygons();
  430. // 退出绘制和编辑模式
  431. if (this.drawingMode) {
  432. this.drawingMode = false;
  433. this.mouseTool.close(true);
  434. }
  435. if (this.editingMode) {
  436. this.editingMode = false;
  437. this.stopEditPolygon();
  438. }
  439. this.statusMessage = '地图已清除';
  440. },
  441. clearMarkers() {
  442. this.markers.forEach(marker => {
  443. marker.setMap(null);
  444. });
  445. this.markers = [];
  446. },
  447. clearPolygons() {
  448. this.polygons.forEach(polygon => {
  449. polygon.setMap(null);
  450. });
  451. this.polygons = [];
  452. }
  453. }
  454. });
  455. </script>
  456. </body>
  457. </html>