1. 程式人生 > >在高德地圖上用svg.js繪製簡單圖形

在高德地圖上用svg.js繪製簡單圖形

> 這段時間做的一個專案,需要在地圖上繪製簡單的圖形。在學習高德地圖`JS API`的過程中,發現高德地圖提供的點、線等API並不能滿足我的需求,還好它開放了自定義圖層`CustomLayer`,官方說自定義圖層支援`canvas`、`svg`、甚至`dom`,這裡我用的是`svg`,多說無益,上程式碼。 ## 一、高德地圖 以下的步驟在[官方文件](https://lbs.amap.com/api/javascript-api/summary)中都有,而且官方文件比較齊全。 首先需要去高德API官網申請自己的key,此步略過。 拿到key後在頁面中引入地圖所用的js ```js ``` 準備一個放置地圖的容器,指定特定的高度,寬度。我是將容器高度寬度全部設定為100%。 ```html ``` ```css html, body, #container { margin: 0; padding: 0; width: 100%; height: 100%; } ``` 最後一步,在js中指定容器,載入地圖,然後就可以在頁面中看到你的地圖了。 ```js // 第一個引數是容器名稱,第二個引數可以按自己需求隨意配置。 var map = new AMap.Map('container', { zoom: 15, // 縮放等級 center: [115.49481017, 38.88656455], // 中心點 features: ['bg', 'road', 'building'] // 設定地圖中顯示的元素, 'bg'(地圖背景)、'point'(POI點)、'road'(道路)、'building'(建築物) }); ``` ## 二、自定義圖層 下面開始編寫自定義圖層,除過地圖所用的js檔案,我還用到了`jquery`。 首先地圖有一部分是非同步載入的,所以需要在地圖載入完成後,再去編寫自定義圖層,否則容易報錯,而地圖也給我們提供了`complete`事件。 ```js map.on('complete', function(){ // TODO 編寫自定義圖層 }) ``` 然後宣告`svg`,建立圖層 `svg`和地圖類似,也需要先宣告一個容器,此容器和地圖等寬等高 ```js var svg = $('')[0]; ``` ```css #drawing { margin: 0; padding: 0; width: 100%; height: 100%; } ``` 建立圖層 ```js // 第一個引數傳入我們建立的svg物件,第二個引數為圖層配置,可以根據自己需求進行配置 var customLayer = new AMap.CustomLayer(svg, { zIndex: 100, zooms: [3, 18], alwaysRender: true }); map.add(customLayer); // 要把圖層新增到地圖中 ``` ## 二、在圖層中畫自己喜歡的圖形。 為了簡化程式碼,專案中採用了[svg.js](https://svgjs.com/docs/3.0/getting-started/) ```js // 呼叫svg.js提供的SVG函式,傳入我們建立的svg物件,建立所需要的draw物件。 var draw = SVG(svg); ``` 現在我們開始在地圖上畫線。 我們規定在地圖上單擊即為線的起點,再進行單擊即為線的終點。 首先為地圖註冊單機事件 ```js var isDraw = false; // 用來判斷是開始畫線還是結束畫線。 var startPix; // 用來儲存起點 map.on('click', function(ev){ isDraw = !isDraw; if(isDraw) { // isDraw為true就標明起點 startPos = ev.pixel; }else{ // isDraw為false就畫線。 } }) ``` 然後編寫畫線函式 ```js function drawLine(start, end) { var lineWth = 3; var lineColor = 'blue'; var x = start.x; var y = start.y; var x1 = end.x; var y1 = end.y; line = draw.line(x, y, x1, y1).stroke({ color: lineColor, width: lineWth }); return line; } ``` 然後完善地圖單擊事件 ```js map.on('click', function(ev){ isDraw = !isDraw; if(isDraw){ // isDraw為true就標明起點 startPix = ev.pixel; }else{ // isDraw為false就畫線。 var endPix = ev.pixel; drawLine(startPix, endPix); } }) ``` 至此就可以在地圖上簡單的畫直線了。 但是當我們單擊地圖開始畫線時,此時地圖上沒有任何東西,再點選地圖時,線突然的出現,這樣顯得比較突兀。現在我們需要修改成,當開始畫線時,線跟隨滑鼠移動而移動,再點選地圖時,結束畫線。 我們需要先註冊地圖`mousemove`事件 ```js map.on('mousemove', function (ev) { if(isDraw) { drawLine(startPix, ev.pixel) } }); ``` 註冊完滑鼠移動時間後,線是可以跟隨滑鼠移動了,但是現在出現了一個小問題: ![](https://img2020.cnblogs.com/blog/740379/202003/740379-20200309094309085-568070184.jpg) 所有畫的線都留下了來了,這時我們需要將多餘的線去掉。 在滑鼠移動時 去掉多餘的線,這裡需要用到`draw`物件的`group`功能。 ```js var lineGroup; // 宣告一個物件 儲存line。 map.on('click', function(ev){ isDraw = !isDraw; if(isDraw){ // isDraw為true就標明起點 startPix = ev.pixel; lineGroup = draw.group(); // 開始畫線時建立一個group。 }else{ // isDraw為false就畫線。 var endPix = ev.pixel; drawLine(startPix, endPix); } }); map.on('mousemove', function(ev){ if(isDraw) { lineGroup.clear(); // 在滑鼠移動時先將group清空。 var line = drawLine(startPix, ev.pixel); lineGroup.add(line);// 將新線新增到group中。 } }) ``` 至此,我們完成了讓線跟隨滑鼠移動。 ## 三、地圖重繪時,讓畫的線隨實際經緯度座標重繪。 我們現在所畫的線,在拖動、放大、縮小地圖時,是不會跟隨地圖變化而變化的。 首先需要建立一個數組用來儲存座標點,一個物件用來儲存起點座標。 ```js var positions = []; var startPos; ``` 然後開始畫線記錄起始點經緯度座標,結束畫線時將兩點座標存入陣列。 ```js map.on('click', function(ev){ isDraw = !isDraw; if(isDraw){ // isDraw為true就標明起點 startPos = ev.lnglat; /*手動高亮*/ startPix = ev.pixel; lineGroup = draw.group(); }else{ // isDraw為false就畫線。 var endPix = ev.pixel; drawLine(startPix, endPix); positions.push({ /*手動高亮*/ start: startPos, end: ev.lnglat }) } }); ``` 最後註冊的是自定義層的重繪事件。 ```js customLayer.render = onRender; function onRender() { draw.clear(); // 先將畫板清空 for(var i = 0;i < positions.length;i++){ // 需要將經緯度座標轉換為容器內座標,lngLatToContainer是高德提供的轉換方法 var startPixCon = map.lngLatToContainer(positions[i].start); var endPixCon = map.lngLatToContainer(positions[i].end); drawLine(startPixCon, endPixCon); } } ``` 現在我們畫的線就可以隨地圖變化而變