在高德地圖上用svg.js繪製簡單圖形
阿新 • • 發佈:2020-03-09
> 這段時間做的一個專案,需要在地圖上繪製簡單的圖形。在學習高德地圖`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);
}
}
```
現在我們畫的線就可以隨地圖變化而變