在高德地圖上繪製飛機標記,相信不少人都使用marker來實現的,但若是這個數據較多的話, 地圖就會有些卡,嚴重影響用戶使用,那麼怎樣才能在大數據的狀況下不卡呢?javascript
這裏咱們主要講的是CustomLayer來實現,相對之前的多個marker實現,那麼使用CustomLayer就好多了。。css
下面先看下效果吧
html
使用customLayer主要的工做仍是在於繪製canvashtml5
行看一個簡單的示例(繪製飛機和添加事件)java
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="jquery.min.js"></script> </head> <body> <canvas id="canvas"></canvas> <script> var canvas = document.getElementById('canvas'); canvas.width = 500; canvas.height = 500; var ctx = canvas.getContext('2d'); // 背景 ctx.fillStyle = '#999'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 飛機 var coord = [200, 200], planeSize = 26, planeHalf = planeSize/2; var x = coord[0], y = coord[1], angle = 2*Math.PI*(-60/360); // 藍色線 ctx.save(); ctx.moveTo(x, y); ctx.lineTo(x-200, y); ctx.lineWidth = 1; ctx.strokeStyle = 'blue'; ctx.stroke(); ctx.restore(); // 黑色飛機 ctx.save(); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x+2, y+3); ctx.lineTo(x+2, y+12); ctx.lineTo(x+13, y+20); ctx.lineTo(x+2, y+16); ctx.lineTo(x+2, y+23); ctx.lineTo(x+5, y+26); ctx.lineTo(x, y+25); ctx.lineTo(x-5, y+26); ctx.lineTo(x-2, y+23); ctx.lineTo(x-2, y+16); ctx.lineTo(x-13, y+20); ctx.lineTo(x-2, y+12); ctx.lineTo(x-2, y+3); ctx.fillStyle = '#000'; ctx.fill(); ctx.closePath(); ctx.restore(); // 綠色飛機 ctx.save(); ctx.translate(0, -planeHalf); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x+2, y+3); ctx.lineTo(x+2, y+12); ctx.lineTo(x+13, y+20); ctx.lineTo(x+2, y+16); ctx.lineTo(x+2, y+23); ctx.lineTo(x+5, y+26); ctx.lineTo(x, y+25); ctx.lineTo(x-5, y+26); ctx.lineTo(x-2, y+23); ctx.lineTo(x-2, y+16); ctx.lineTo(x-13, y+20); ctx.lineTo(x-2, y+12); ctx.lineTo(x-2, y+3); ctx.fillStyle = '#690'; ctx.fill(); ctx.closePath(); ctx.restore(); // 白色飛機 ctx.save(); ctx.translate(x, y); ctx.rotate(angle); ctx.translate(-x, -y); ctx.beginPath(); ctx.translate(0, -planeHalf); ctx.moveTo(x, y); ctx.lineTo(x+2, y+3); ctx.lineTo(x+2, y+12); ctx.lineTo(x+13, y+20); ctx.lineTo(x+2, y+16); ctx.lineTo(x+2, y+23); ctx.lineTo(x+5, y+26); ctx.lineTo(x, y+25); ctx.lineTo(x-5, y+26); ctx.lineTo(x-2, y+23); ctx.lineTo(x-2, y+16); ctx.lineTo(x-13, y+20); ctx.lineTo(x-2, y+12); ctx.lineTo(x-2, y+3); ctx.fillStyle = '#fff'; ctx.fill(); ctx.closePath(); ctx.restore(); // 紅色飛機 ctx.save(); ctx.translate(x, y); ctx.rotate(angle); ctx.translate(-x, -y); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x+2, y+3); ctx.lineTo(x+2, y+12); ctx.lineTo(x+13, y+20); ctx.lineTo(x+2, y+16); ctx.lineTo(x+2, y+23); ctx.lineTo(x+5, y+26); ctx.lineTo(x, y+25); ctx.lineTo(x-5, y+26); ctx.lineTo(x-2, y+23); ctx.lineTo(x-2, y+16); ctx.lineTo(x-13, y+20); ctx.lineTo(x-2, y+12); ctx.lineTo(x-2, y+3); ctx.fillStyle = '#f00'; ctx.fill(); ctx.closePath(); ctx.restore(); // 點擊點在飛機矩形範圍內[ Math.round(Math.sqrt(planeHalf*planeHalf*2))==18 ] ( 推薦 ) var modulesPoints = {}; modulesPoints['plane'] = { xMin: x-18, xMax: x+18, yMin: y-18, yMax: y+18 }; canvas.addEventListener('click', function(e) { var clientX = e.clientX, clientY = e.clientY, planeRect = modulesPoints['plane']; if(planeRect.xMin<clientX && clientX<planeRect.xMax && planeRect.yMin<clientY && clientY<planeRect.yMax) { console.log(+new Date); } }); // 點擊點只在飛機內 // var modulesPoints = {}; // for(var i=0; i<canvas.width; i++) { // for(var j=0; j<canvas.height; j++) { // if(ctx.isPointInPath(i, j)) { // if(!modulesPoints['plane']) { // modulesPoints['plane'] = {}; // } // modulesPoints['plane']['x_'+i] = i; // modulesPoints['plane']['y_'+j] = j; // } // } // } // canvas.addEventListener('click', function(e) { // if(modulesPoints['plane']['x_'+e.clientX] && modulesPoints['plane']['y_'+e.clientY]) { // console.log(+new Date); // } // }); </script> </body> </html>
效果:
jquery
基本原理就是上面那樣的,用過canvas的同窗應該都能看懂,固然也能夠先了解下canvas基礎 和 canvas APIweb
接下來就請嚴讀完整代碼嘍~~~
註釋也都很清淅。。ajax
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> *{margin: 0;} </style> <script src="js/jquery.min.js"></script> </head> <body> <div id="zh_map"></div> <script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=b705b0ffe322148bbf5c1febdf47fe95&plugin=AMap.Geocoder"></script> <script type="text/javascript" src="js/socketio.js"></script> <script type="text/javascript" src="js/wgs2mars.min.js"></script> <script type="text/javascript" src="js/protobuf/protobuf.js"></script> <script> // 初始化 var initSet = (function set() { document.getElementById('zh_map').style.cssText = 'height: '+window.innerHeight+'px;'; return set; })(); window.onresize = function() { initSet(); } // 變量 var planeMarkers = {}, planeLayer = null, planeSize = 26, planePoints = {}, selectedPlaneAnum = null; // 打印log function log() { var args = Array.prototype.slice.call(arguments); if(args.length == 1) { console.log(args[0]); } else { console.log('%c'+args[0], 'color: '+(args[1]?args[1]:'#333')); } } // 地圖 var map = new AMap.Map('zh_map', { zoom: 10, center: [102.926672, 25.09155], doubleClickZoom: false, mapStyle: 'blue_night', features: ['bg', 'point'] }); // 數據結構 var locProto, pathProto; protobuf.load('js/protobuf/flightloc.json', function(err, root) { locProto = root.lookupType("Loc.FlightLoc"); pathProto = root.lookupType("Loc.FlightPath"); }); // 請求appid、token function reqToken() { $.ajax({ type: 'get', url: 'http://***/***/get_client_token', success: function(res) { res = JSON.parse(res); if(res.status) { planeFn(res.appid, res.token); } } }); } reqToken(); function planeFn(appid, token) { socket = null; // 可視範圍 var curBounds = map.getBounds(); var clientBounds = [curBounds.northeast.lat,curBounds.southwest.lng,curBounds.southwest.lat,curBounds.northeast.lng]; // 左上右下 // 鏈接socket socket = io('https://***.***.com/***', {path: "/**/socket.io", transports: ['websocket'], reconnection: true}); // 鏈接 socket.on('connect', function() { log('connect success.', 'green'); }); // 驗證 socket.on('validate', function(ack) { log('validate...', 'blue'); ack(appid, token, '{}'); socket.emit('sub', clientBounds, -1, ''); }); // 驗證成功 socket.on('validateSuccess', function() { log('socket validate success.', 'green'); }); // 驗證失敗 socket.on('validateFailed', function() { log('socket validate failed.', 'red'); reqToken(); }); socket.on('disconnect', function() { log('socket disconnect.', 'red'); reqToken(); }); // 心跳 socket.on('heartbeat', function(ack) { ack(); }); // 監聽adsb數據 socket.on('~', function(buffer) { if(locProto) { var item = locProto.decode(new Uint8Array(buffer)), // 數據解碼 Anum = item.Anum, // 飛機編號 Lon = item.Lon, // 經度 Lat = item.Lat, // 緯度 Alt = item.Alt, // 高度 Ang = item.Ang, // 角度 Spd = item.Spd; // 速度 var coord = transformFromWGSToGCJ(Lon, Lat); // WGS(World Geodetic System) 世界大地座標系 轉 高德地圖GCJ(國測局座標)使用的火星座標系 Lon = coord.lng; Lat = coord.lat; planeMarkers[Anum] = item; } else { log('監控飛機位置失敗~'); } }); } // 從新訂閱 function resub(socket) { // 可視範圍 var curBounds = map.getBounds(); var clientBounds = [curBounds.northeast.lat,curBounds.southwest.lng,curBounds.southwest.lat,curBounds.northeast.lng]; // 左上右下 // 訂閱 socket.emit("sub", clientBounds, -1, ''); } // 拖動結束 map.on('dragend', function() { if(socket) resub(socket); }); // 縮放結束 map.on('zoomend', function() { if(socket) resub(socket); }); // 繪製 function drawPlane(anum) { if(planeLayer) { map.remove(planeLayer); planeLayer = null planePoints = {}; } map.plugin(['AMap.CustomLayer'], function() { var canvas = document.createElement('canvas'); canvas.id = 'plane_layer'; canvasWth = map.getSize().width; canvasHgt = map.getSize().height; canvas.width = canvasWth; canvas.height = canvasHgt; planeLayer = new AMap.CustomLayer(canvas, { zIndex: 110 }); planeLayer.render = function() { var ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvasWth, canvasHgt); $.each(planeMarkers, function(k, v) { var Anum = v.Anum, // 飛機編號 Fnum = v.Fnum, // 航班號 Org = v.Org, // 出發地 Dst = v.Dst, // 目的地 Squawk = v.Squawk, // 應答碼 Lon = v.Lon, // 經度 Lat = v.Lat, // 緯度 Spd = v.Spd, // 速度 Ang = v.Ang, // 角度 Alt = v.Alt; // 高度 var coord = transformFromWGSToGCJ(Lon, Lat); Lon = coord.lng; Lat = coord.lat; var containerCoord = map.lngLatToContainer([coord.lng, coord.lat]), x = containerCoord.x-planeSize/2, y = containerCoord.y, angle = 2*Math.PI*(Ang/360); // 繪製飛機 ctx.save(); ctx.translate(x, y); ctx.rotate(angle); ctx.translate(-x, -y); ctx.beginPath(); ctx.translate(0, -planeHalf); ctx.moveTo(x, y); ctx.lineTo(x+2, y+3); ctx.lineTo(x+2, y+12); ctx.lineTo(x+13, y+20); ctx.lineTo(x+2, y+16); ctx.lineTo(x+2, y+23); ctx.lineTo(x+5, y+26); ctx.lineTo(x, y+25); ctx.lineTo(x-5, y+26); ctx.lineTo(x-2, y+23); ctx.lineTo(x-2, y+16); ctx.lineTo(x-13, y+20); ctx.lineTo(x-2, y+12); ctx.lineTo(x-2, y+3); ctx.fillStyle = (selectedPlaneAnum===Anum?'#FF5F3A':'#1282F7'); ctx.fill(); ctx.closePath(); ctx.restore(); // 保存座標點 planePoints[Anum] = { xMin: x-18, xMax: x+18, yMin: y-18, yMax: y+18 }; // 繪製矩形 x += planeHalf; y -= planeHalf; ctx.fillStyle = 'rgba(0,0,0,0.5)'; ctx.fillRect(x, y, 100, 150); ctx.restore(); // 繪製文字 x += 10; ctx.fillStyle = '#fff'; ctx.fillText(Anum, x, y+20); ctx.fillText(Fnum, x, y+40); ctx.fillText(Org+'-'+Dst, x, y+60); ctx.fillText(Squawk||'--', x, y+80); ctx.fillText(Ang, x, y+100); ctx.fillText(Spd.toFixed(2), x, y+120); ctx.fillText(Alt.toFixed(2), x, y+140); }); } planeLayer.setMap(map); }); } // 1秒鐘繪製一次 setInterval(function() { drawPlane(selectedPlaneAnum); }, 1000); // 事件 $('#zh_map').on('click', 'canvas',function(e) { var clientX = e.clientX, clientY = e.clientY; $.each(planePoints, function(k, v) { if(v.xMin<clientX && clientX<v.xMax && v.yMin<clientY && clientY<v.yMax) { selectedPlaneAnum = k; } }); drawPlane(selectedPlaneAnum); }); </script> </body> </html>
其實整個過程也不難,就是考驗你們想不想作了。。json