這段時間做的一個項目,需要在地圖上繪制簡單的圖形。在學習高德地圖
JS API
的過程中,發現高德地圖提供的點、線等API並不能滿足我的需求,還好它開放了自定義圖層CustomLayer
,官方說自定義圖層支持canvas
、svg
、甚至dom
,這里我用的是svg
,多說無益,上代碼。
一、高德地圖
以下的步驟在官方文檔中都有,而且官方文檔比較齊全。
首先需要去高德API官網申請自己的key,此步略過。
拿到key后在頁面中引入地圖所用的js
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=申請的key"></script>
准備一個放置地圖的容器,指定特定的高度,寬度。我是將容器高度寬度全部設置為100%。
<div id="container"></div>
html, body, #container {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
最后一步,在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
事件。
map.on('complete', function(){
// TODO 編寫自定義圖層
})
然后聲明svg
,創建圖層
svg
和地圖類似,也需要先聲明一個容器,此容器和地圖等寬等高
var svg = $('<svg id="drawing" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" ></svg>')[0];
#drawing {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
創建圖層
// 第一個參數傳入我們創建的svg對象,第二個參數為圖層配置,可以根據自己需求進行配置
var customLayer = new AMap.CustomLayer(svg, {
zIndex: 100,
zooms: [3, 18],
alwaysRender: true
});
map.add(customLayer); // 要把圖層添加到地圖中
二、在圖層中畫自己喜歡的圖形。
為了簡化代碼,項目中采用了svg.js
// 調用svg.js提供的SVG函數,傳入我們創建的svg對象,創建所需要的draw對象。
var draw = SVG(svg);
現在我們開始在地圖上畫線。
我們規定在地圖上單擊即為線的起點,再進行單擊即為線的終點。
首先為地圖注冊單機事件
var isDraw = false; // 用來判斷是開始畫線還是結束畫線。
var startPix; // 用來存儲起點
map.on('click', function(ev){
isDraw = !isDraw;
if(isDraw) {
// isDraw為true就標明起點
startPos = ev.pixel;
}else{
// isDraw為false就畫線。
}
})
然后編寫畫線函數
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;
}
然后完善地圖單擊事件
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
事件
map.on('mousemove', function (ev) {
if(isDraw) {
drawLine(startPix, ev.pixel)
}
});
注冊完鼠標移動時間后,線是可以跟隨鼠標移動了,但是現在出現了一個小問題:
所有畫的線都留下了來了,這時我們需要將多余的線去掉。
在鼠標移動時 去掉多余的線,這里需要用到draw
對象的group
功能。
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中。
}
})
至此,我們完成了讓線跟隨鼠標移動。
三、地圖重繪時,讓畫的線隨實際經緯度坐標重繪。
我們現在所畫的線,在拖動、放大、縮小地圖時,是不會跟隨地圖變化而變化的。
首先需要創建一個數組用來存儲坐標點,一個對象用來存儲起點坐標。
var positions = [];
var startPos;
然后開始畫線記錄起始點經緯度坐標,結束畫線時將兩點坐標存入數組。
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
})
}
});
最后注冊的是自定義層的重繪事件。
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);
}
}
現在我們畫的線就可以隨地圖變化而變化了。