UNPKG

czmap

Version:

- 提供统一的API 实现不同的地图(百度、高德、腾讯)应用 丝滑切换 - 主要实现功能 - 基础地图展示 - 路径 - 围栏 #### 相关API使用

887 lines (866 loc) 29.8 kB
class CMap { constructor(options) { this.$options = options this.mapAk = ''; this.map = '' const { type } = options if (window.$catch && window.$catch === type) { if (type && type === 'TMAP') { this.initTMap() } else if (type && type === 'AMAP') { this.initAMap() } else if (type && type === 'BMAP') { this.initBMap() } } else { this.initMap() } } // 初始化地图 initMap() { const { type } = this.$options window.$catch = type this.getMapAK(type) if (type && type === 'TMAP') { this.createTMap() } else if (type && type === 'AMAP') { this.createAMap() } else if (type && type === 'BMAP') { this.createBMap() } } // 获取地图的ak getMapAK(type) { const { mapAk } = this.$options if (mapAk) { this.mapAk = mapAk } else { switch (type) { case 'TMAP': { this.mapAk = 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77' break } case 'AMAP': { this.mapAk = 'c081218aae02057742b9f1a100d6cf66' break } default: { this.mapAk = 'f7HnzEYGLgOyMyDVTh99ZEQqjlEzuhyC' } } } } // 初始化百度地图 createBMap() { const self = this const { drivingPath, enclosure, coordType } = this.$options window.BMapGL_loadScriptTime = (new Date).getTime(); window.BMapGL = window.BMapGL || {}; window.BMapGL.apiLoad = function () { delete window.BMapGL.apiLoad; if ((typeof self.initBMap == "function" && !enclosure) || (enclosure && enclosure.type != 'district' )){ self.initBMap() } }; // 百度地图 需要坐标系转换的一个插件 默认进入的时是GBJ02 的坐标系 需要转换为BD09的坐标 if (!coordType){ const coord = document.createElement('script'); coord.src = `https://unpkg.com/gcoord/dist/gcoord.js`; document.body.appendChild(coord); } const s = document.createElement('script'); s.src = `http://api.map.baidu.com/getscript?type=webgl&v=1.0&ak=${self.mapAk}`; document.body.appendChild(s); const link = document.createElement('link'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type', 'text/css'); link.setAttribute('href', 'http://api.map.baidu.com/res/webgl/10/bmap.css'); document.getElementsByTagName('head')[0].appendChild(link); if (drivingPath && drivingPath.length >= 2) { const trackAnim = document.createElement('script'); trackAnim.src = `//mapopen.bj.bcebos.com/github/BMapGLLib/TrackAnimation/src/TrackAnimation.min.js`; document.body.appendChild(trackAnim); } if (enclosure && enclosure.type === 'district'){ s.onload = function(){ self.initBMap() } } } // 初始化高德地图 createAMap() { const self = this const { enclosure } = this.$options const url = `https://webapi.amap.com/maps?v=2.0&key=${self.mapAk}&&plugin=AMap.Scale,AMap.HawkEye,AMap.ToolBar,AMap.MapType`; const jsapi = document.createElement('script'); jsapi.src = url; document.body.appendChild(jsapi); jsapi.onload = function () { if (enclosure && enclosure.type === 'district'){ const prov = document.createElement('script'); prov.src = '//webapi.amap.com/ui/1.1/main.js?v=1.1.1' document.body.appendChild(prov); prov.onload = function () { self.initAMap() } } else { self.initAMap() } } } // 初始化腾讯地图 createTMap() { const self = this const url = `https://map.qq.com/api/gljs?v=1.exp&key=${self.mapAk}&libraries=geometry`; const jsapi = document.createElement('script'); jsapi.src = url; document.body.appendChild(jsapi); jsapi.onload = function () { self.initTMap() } } } //腾讯地图处理 CMap.prototype.initTMap = function () { const wd = window || {} const { id = 'map', points = [39.984104, 116.307503], zoom = 10, isScaleCtrl = false, isZoomCtrl = false, navi3DCtrl = false, drivingPath = [], enclosure = {} } = this.$options const center = new wd.TMap.LatLng(points[1], points[0]) const map = new wd.TMap.Map(document.getElementById(id), { center, //设置地图中心点坐标 zoom, //设置地图缩放级别 // pitch: 43.5, //设置俯仰角 // rotation: 45 //设置地图旋转角度 }); this.map = map // 默认是开启的-可以选择关闭 if (!isZoomCtrl) { map.removeControl(TMap.constants.DEFAULT_CONTROL_ID.ZOOM); } /** 控件 * CONTROL_POSITION * DEFAULT_CONTROL_ID: SCALE 、FLOOR、LOGO、ROTATION、SCALE、ZOOM * **/ if (!isScaleCtrl) { map.removeControl(TMap.constants.DEFAULT_CONTROL_ID.SCALE) } if (!navi3DCtrl) { map.removeControl(TMap.constants.DEFAULT_CONTROL_ID.ROTATION) } if (drivingPath && drivingPath.length >= 2) { let path = []; drivingPath.forEach(it => { path.push(new TMap.LatLng(it.lat, it.lng)) }) const lastPoint = drivingPath.at(-1) const startPosition = new TMap.LatLng(drivingPath[0].lat, drivingPath[0].lng); const endPosition = new TMap.LatLng(lastPoint.lat, lastPoint.lng); new TMap.MultiMarker({ // 创造MultiMarker显示起终点标记 id: 'marker-layer', map: map, styles: { start: new TMap.MarkerStyle({ width: 25, height: 35, anchor: { x: 16, y: 32 }, src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/start.png', }), end: new TMap.MarkerStyle({ width: 25, height: 35, anchor: { x: 16, y: 32 }, src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/end.png', }), }, geometries: [{ id: 'start', styleId: 'start', position: startPosition, }, { id: 'end', styleId: 'end', position: endPosition, }, ], }); // 创建 MultiPolyline显示路径折线 new TMap.MultiPolyline({ id: 'polyline-layer', map: map, styles: { style_blue: new TMap.PolylineStyle({ color: '#3777FF', width: 6, lineCap: 'round', }), }, geometries: [{ id: 'pl_1', styleId: 'style_blue', paths: path, }, ], }); setCenterAndZoom(getAreaAndCent(path)) } //多边形区域 if (enclosure && enclosure.points) { const { points, radius, strokeColor, strokeWeight } = enclosure let path = []; points.forEach(it => { path.push(new TMap.LatLng(it.lat, it.lng)) }) new TMap.MultiPolygon({ id: 'polygon-layer', //图层id map: map, //显示多边形图层的底图 styles: { //多边形的相关样式 'polygon': new TMap.PolygonStyle({ 'color': 'rgba(0,125,255,0.3)', //面填充色 'showBorder': true, //是否显示拔起面的边线 'borderColor': strokeColor || '#6699FF' //边线颜色 }) }, geometries: [{ 'id': 'polygon', //多边形图形数据的标志信息 'styleId': 'polygon', //样式id 'paths': path, //多边形的位置信息 'properties': { //多边形的属性数据 'title': 'polygon' } }] }); setCenterAndZoom(getAreaAndCent(path)) map.setCenter(path[0]) } // 圆形围栏 if (enclosure && enclosure.point) { const { point, radius, strokeColor, strokeWeight } = enclosure const TMapCent = new TMap.LatLng(point[1], point[0]) new TMap.MultiCircle({ map, styles: { // 设置圆形样式 'circle': new TMap.CircleStyle({ 'color': 'rgba(41,91,255,0.3)', 'showBorder': true, 'borderColor': strokeColor || 'rgba(41,91,255,1)', 'borderWidth': strokeWeight, }), }, geometries: [{ styleId: 'circle', center: TMapCent, radius, }], }) setCenterAndZoom({ distance: radius * 2, cent: TMapCent }) } // 计算最大区域以及 区域中心点 function getAreaAndCent(path) { let startPoint = [], endPoint = [], rt = [], lb = []; path.forEach(it => { if (startPoint[0] === undefined || startPoint[0] < it.lat) { startPoint[0] = it.lat } if (startPoint[1] === undefined || startPoint[1] > it.lng) { startPoint[1] = it.lng } if (endPoint[0] === undefined || endPoint[0] > it.lat) { endPoint[0] = it.lat } if (endPoint[1] === undefined || endPoint[1] < it.lng) { endPoint[1] = it.lng } if (rt[0] === undefined || rt[0] < it.lat) { rt[0] = it.lat } if (rt[1] === undefined || rt[1] < it.lng) { rt[1] = it.lng } if (lb[0] === undefined || lb[0] > it.lat) { lb[0] = it.lat } if (lb[1] === undefined || lb[1] > it.lng) { lb[1] = it.lng } }) const pointSE = [ new TMap.LatLng(startPoint[0], startPoint[1]), new TMap.LatLng(endPoint[0], endPoint[1]) ] const distance = TMap.geometry.computeDistance(pointSE); var ctpath = [...pointSE, new TMap.LatLng(rt[0], rt[1]), new TMap.LatLng(lb[0], lb[1]), ]; // 使用百度地图的点位 出现报错 let cent = '' try { cent = TMap.geometry.computeCentroid(ctpath); } catch { cent = undefined } return { distance: distance.toFixed(2), cent } } // 调整中心点和展示区域 function setCenterAndZoom(tags) { const { distance, cent } = tags console.log(distance, cent) if (cent) { console.log(2, distance, cent) map.setCenter(cent) } if (distance) { let comZoom = 10; if (distance < 80) { comZoom = 16; } else if (80 < distance && distance < 1000) { comZoom = 15; } else if (1000 < distance && distance < 3000) { comZoom = 14; } else if (3000 < distance && distance < 7000) { comZoom = 13; } else if (7000 < distance && distance < 15000) { comZoom = 12; } else { comZoom = 10; } map.setZoom(comZoom) } } } //高德地图处理 CMap.prototype.initAMap = function () { const AMap = window.AMap || {} const { id, points = [116.404, 39.915], areaName, zoom = 10, isScaleCtrl = false, isZoomCtrl = false, navi3DCtrl = false, // 添加3D控件 enclosure = {}, drivingType, drivingPath = [], } = this.$options const map = new AMap.Map(id, { center: points, resizeEnable: true, //是否监控地图容器尺寸变化 zoom }) this.map = map if (isScaleCtrl) { map.addControl(new AMap.Scale({ visible: isScaleCtrl })) } if (isZoomCtrl) { map.addControl(new AMap.ToolBar({ visible: isZoomCtrl, position: { bottom: '60px', right: '40px' } })) } if (navi3DCtrl) { map.addControl(new AMap.MapType()); } // 使用路径搜索展示 if (drivingType === 'path' && drivingPath.length > 2) { AMap.plugin(['AMap.DragRoute'], function () { let path = [] for (let i = 0; i < drivingPath.length; i++) { path.push([drivingPath[i].lng, drivingPath[i].lat]) } const route = new AMap.DragRoute(map, path, AMap.DrivingPolicy.LEAST_FEE) route.search() }); } if (drivingPath && drivingPath.length > 2) { // 折线的节点坐标数组,每个元素为 AMap.LngLat 对象 let path = [ ]; for (let i = 0; i < drivingPath.length; i++) { path.push(new AMap.LngLat(drivingPath[i].lng, drivingPath[i].lat)) } // console.log() // 创建折线实例 const polyline = new AMap.Polyline({ path: path, strokeColor: "#6699FF", strokeWeight: 6, strokeOpacity: 0.9, zIndex: 50, bubble: true, }); const startIcon = new AMap.Icon({ // 图标尺寸 size: new AMap.Size(25, 34), // 图标的取图地址 image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png', // 图标所用图片大小 imageSize: new AMap.Size(135, 40), // 图标取图偏移量 imageOffset: new AMap.Pixel(-9, -3) }); // 将 开始 icon 传入 marker const startMarker = new AMap.Marker({ position: new AMap.LngLat(drivingPath[0].lng, drivingPath[0].lat), icon: startIcon, offset: new AMap.Pixel(-13, -30) }); // 创建一个 icon const endIcon = new AMap.Icon({ size: new AMap.Size(25, 34), image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png', imageSize: new AMap.Size(135, 40), imageOffset: new AMap.Pixel(-95, -3) }); const endPint = drivingPath.at(-1) // 将 icon 传入 marker const endMarker = new AMap.Marker({ position: new AMap.LngLat(endPint.lng, endPint.lat), icon: endIcon, offset: new AMap.Pixel(-13, -30) }); map.add(startMarker); map.add(polyline); map.add(endMarker); map.setFitView() // 缩放地图到合适的视野级别 } // 多边形轮廓线的节点坐标数组 if (enclosure && enclosure.points && enclosure.type === 'polygon') { const { points, fillColor = '#6699FF', fillOpacity = 0.3, strokeColor = '#6699FF', borderWeight = 2, } = enclosure let path = []; for (let i = 0; i < points.length; i++) { path.push(new AMap.LngLat(points[i].lng, points[i].lat)) } const polygon = new AMap.Polygon({ path: path, fillColor, // 多边形填充颜色 borderWeight, // 线条宽度,默认为 1 strokeColor, // 线条颜色 fillOpacity, // 多边形填充颜色透明度 }); map.add(polygon); map.setFitView(); } // 圆形 if (enclosure && enclosure.point && enclosure.type === 'circle') { const { point, radius, fillColor = '#6699FF', fillOpacity = 0.3, strokeColor = '#6699FF', strokeWeight = 2, } = enclosure const circle = new AMap.Circle({ center: new AMap.LngLat(point[0], point[1]), // 圆心位置 radius, // 圆半径 fillColor, // 圆形填充颜色 fillOpacity, strokeColor, // 描边颜色 strokeWeight, // 描边宽度 }); map.add(circle); map.setFitView() } // 行政区域 if ((enclosure && enclosure.type === 'district')){ const { fillColor = "#6699FF", fillOpacity = 0.3, strokeColor = "#6699FF", strokeWeight = 1, strokeOpacity = 1, adcodes } = enclosure AMapUI.loadUI(['geo/DistrictExplorer'], function(DistrictExplorer) { //创建一个实例 var districtExplorer = new DistrictExplorer({ map: map }); function renderAreaNode(areaNode) { //绘制子区域 districtExplorer.renderSubFeatures(areaNode, function(feature, i) { return { cursor: 'default', bubble: true, strokeColor: strokeColor, //线颜色 strokeOpacity, //线透明度 strokeWeight, //线宽 fillColor: fillColor, //填充色 fillOpacity, //填充透明度 }; }); } districtExplorer.loadMultiAreaNodes(adcodes, function(error, areaNodes) { //清除已有的绘制内容 districtExplorer.clearFeaturePolygons(); for (let i = 0, len = areaNodes.length; i < len; i++) { renderAreaNode(areaNodes[i]); } //更新地图视野 map.setFitView(districtExplorer.getAllFeaturePolygons()); }); }); } // 绘制线型区域 if ((enclosure && enclosure.points && enclosure.type === 'polyline')){ const { strokeColor = "#6699FF", strokeWeight = 4, strokeOpacity = 1, points, offset } = enclosure let point = []; for (let i = 0; i < points.length; i++) { point.push(new AMap.LngLat(points[i].lng, points[i].lat)); } const label = new AMap.Text({ map: map, text: `线性覆盖辐射范围: ${offset} 米`, position: new AMap.LngLat(points[0].lng, points[0].lat), style: { borderRadius: '5px', borderColor: '#ccc', padding: '0px 15px', fontSize: '14px', height: '28px', lineHeight: '30px', fontFamily: '微软雅黑' } }) const polyline = new AMap.Polyline({ path: point, borderWeight:strokeWeight, // 线条宽度,默认为 1 strokeColor, // 线条颜色 color: '#6699FF', }); map.add(label); map.add(polyline); map.setFitView(); } } //百度地图处理 CMap.prototype.initBMap = function () { let { id, points = [116.404, 39.915], areaName, poiText = true, //是否显示POI信息 poiIcon = true, //是否显示POI图标信息 zoom = 10, drivingPath = [], enableScrollWheel = false, coordType, isScaleCtrl = false, isZoomCtrl = false, navi3DCtrl = false, // 添加3D控件 enclosure = {}, drivingType } = this.$options const map = new BMapGL.Map(id); // 坐标中心点转换 let centerpoint = points // 坐标转换 function pointsChange(data){ let dishPint = [] data.forEach(item => { const result = gcoordChange([item.lng,item.lat]) dishPint.push({lng:result[0], lat:result[1]}) }) data = dishPint } // 坐标走二次转换 function gcoordChange(points){ const result = gcoord.transform( points, // 经纬度坐标 gcoord.GCJ02, // 当前坐标系 gcoord.BD09 // 目标坐标系 ); return result } // 如果使用非百度的BD09坐标系 转换为gcj02 if (!coordType){ // 中心点的转换 centerpoint = gcoordChange(points) // 路径转换 if (drivingPath){ pointsChange(drivingPath) } // 圆心围栏转换 if(enclosure && enclosure.point){ enclosure.point = gcoordChange(enclosure.point) } // 其他围栏转换 if(enclosure && enclosure.points){ pointsChange(enclosure.points) } } this.map = map const point = this.$options.points && points.length === 2 ? new BMapGL.Point(centerpoint[0], centerpoint[1]) : null; map.centerAndZoom(point ?? areaName, zoom); map.enableScrollWheelZoom(enableScrollWheel); map.setDisplayOptions({ poiText, poiIcon }) // 添加3D控件 if (navi3DCtrl) { const ctrl3D = new BMapGL.NavigationControl3D(); map.addControl(ctrl3D); } // 添加比例尺控件 if (isScaleCtrl) { const scaleCtrl = new BMapGL.ScaleControl(); map.addControl(scaleCtrl); } // 添加缩放控件 if (isZoomCtrl) { const zoomCtrl = new BMapGL.ZoomControl(); map.addControl(zoomCtrl); } // 轨迹配置 if (drivingPath && drivingPath.length >= 2) { startPints = [drivingPath[0].lng, drivingPath[0].lat] endPints = [drivingPath.at(-1).lng, drivingPath.at(-1).lat] // 起始结束点位计算路径 if (drivingType && drivingType === 'path') { const start = new BMapGL.Point(...startPints); const end = new BMapGL.Point(...endPints); const driving = new BMapGL.DrivingRoute(map, { renderOptions: { map: map, autoViewport: true } }); driving.search(start, end); } else { map.centerAndZoom(new BMapGL.Point(...startPints)); let point = []; for (let i = 0; i < drivingPath.length; i++) { point.push(new BMapGL.Point(drivingPath[i].lng, drivingPath[i].lat)); } const pl = new BMapGL.Polyline(point, { strokeColor: "#6699FF", strokeWeight: 6, }); const startIcon = new BMapGL.Icon('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/start.png', new BMapGL.Size(23, 35)); const endIcon = new BMapGL.Icon('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/end.png', new BMapGL.Size(23, 35)); const markerST = new BMapGL.Marker(new BMapGL.Point(...startPints), { icon:startIcon, name: '起点', }); const markerEND = new BMapGL.Marker(new BMapGL.Point(...endPints), { icon:endIcon, title: '终点' }); setTimeout(function () { trackAni = new BMapGLLib.TrackAnimation(map, pl, { overallView: true, // 动画完成后自动调整视野到总览 tilt: 30, // 轨迹播放的角度,默认为55 duration: 4000, // 动画持续时长,默认为10000,单位ms delay: 300 // 动画开始的延迟,默认0,单位ms }); trackAni.start(); map.addOverlay(markerST); map.addOverlay(markerEND); }, 1000); } } // 围栏配置 if ((enclosure && enclosure.type === 'circle') || enclosure && enclosure.point) { const { fillColor = "#6699FF", fillOpacity = 0.3, strokeColor = "#6699FF", strokeWeight = 2, strokeOpacity = 1, point, radius } = enclosure const circle = new BMapGL.Circle(new BMapGL.Point(...point), radius, { fillColor, fillOpacity, strokeColor, strokeWeight, strokeOpacity, }); setCircleBestViewport(new BMapGL.Point(point[0], point[1]), radius) map.addOverlay(circle); // 添加到地图中 } else if (enclosure && enclosure.points && enclosure.type === 'polygon') { const { fillColor = "#6699FF", fillOpacity = 0.3, strokeColor = "#6699FF", strokeWeight = 2, strokeOpacity = 1, points = [] } = enclosure let pl = [] for (let i = 0; i < points.length; i++) { pl.push(new BMapGL.Point(points[i].lng, points[i].lat)) } const polygon = new BMapGL.Polygon(pl, { fillColor, fillOpacity, strokeColor, strokeWeight, strokeOpacity }); setZoom(pl) map.addOverlay(polygon); } else if ((enclosure && enclosure.type === 'district')){ // 行政区域 const { fillColor = "#6699FF", fillOpacity = 0.3, strokeColor = "#6699FF", strokeWeight = 2, strokeOpacity = 1, proname = '北京市', prokind = 1 } = enclosure /************/ //获取行政区域 并调整视野 const bdary = new BMapGL.Boundary(); bdary.get(proname, function(rs) { const points = rs.boundaries[0].split(';') const nPoints = points.map(it => { const item = it.split(',') return {lng: item[0], lat: item[1]} }) setZoom(nPoints) }) // 必须调整完视野才能 添加行政区域覆盖 setTimeout(function(){ const dist = new BMapGL.DistrictLayer({ name: `(${proname})`, fillColor, strokeWeight, strokeColor, fillOpacity }); map.addDistrictLayer(dist); }, 1200) /************/ } else if ((enclosure && enclosure.points && enclosure.type === 'polyline')){ // 绘制线 const { strokeColor = "#6699FF", strokeWeight = 4, strokeOpacity = 1, points, offset } = enclosure let point = []; for (let i = 0; i < points.length; i++) { point.push(new BMapGL.Point(points[i].lng, points[i].lat)); } var opts = { position: new BMapGL.Point(points[0].lng, points[0].lat), // 指定文本标注所在的地理位置 offset: new BMapGL.Size(30, -30) // 设置文本偏移量 }; // 创建文本标注对象 var label = new BMapGL.Label(`线性覆盖辐射范围: ${offset} 米`, opts); // 自定义文本标注样式 label.setStyle({ color: '#6699FF', borderRadius: '5px', borderColor: '#ccc', padding: '5px 15px', fontSize: '14px', height: '28px', lineHeight: '30px', fontFamily: '微软雅黑' }); var polyline = new BMapGL.Polyline( point, { strokeColor, strokeWeight, strokeOpacity }); setZoom(points) map.addOverlay(label); map.addOverlay(polyline); } // 坐标系转换 // interface points = [122.99395597, 44.99804071] | { // "type": "Point", // "coordinates": [123, 45] // } // 多边形视野调整 function setZoom(bPoints) { var view = map.getViewport(bPoints); var mapZoom = view.zoom; var centerPoint = view.center; map.centerAndZoom(centerPoint, mapZoom); } // 圆形的最佳视野范围 function setCircleBestViewport(point, radius) { let zoom = 20; //地图层级数(百度地图默认为19层,这里多加1层使下面通过直径的运算刚好可以得出地图对应的层级) let num = 20; //基数 while (num < radius) { num = num * 2; zoom--; } map.centerAndZoom(point, zoom + 1); //设置中心点和缩放层级,为了优化显示效果此处zoom多加2级 } }