在高德地图上绘制飞机标记,相信不少人都使用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