引言
前端er必备技能之一:地图开发。也不能说是开发,只是拿百度地图大牛们开发好的插件,做一个简单使用。建议阅读本文前,先尝试一下在线地图的开发,如:申请AK码,了解百度地图相关api,Echarts中地图模块。
效果预览
去年在JS中做的离线版,为了兼容IE,使用的老版本Echarts: 需要兼容ie的可以使用这个版本的Echarts
这是最近做的vue版:
实现方式
1.引入文件
我的实现方式是需要4样东西:echarts,apiv1.3.min.js,modules_ditu.js,瓦片图。
地图开发最关键的一步就是:如何引入百度地图的api文件。
在线地图中的引用很简单,只需要script引入一个url即可,即可引入相关API的文件。<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的AK码"></script>
那么离线地图也是一样的思路,我们只需要引入api相关的JS文件即可。引入文件步骤(以需要的apiv1.3.min为例)。我之前是学习的这位博主的博客
在离线地图中,我们需要引入的JS文件只有2个JS,文中说的那个CSS可以不引,无影响。
最后就是我们的核心=>瓦片图的获取。离线地图就是靠JS中动态拼接路径,来调取瓦片图,以此来实现的可视化地图。我们用的瓦片图只有5个层级,但是图片数量也已经有2W多张了,
2.文件中路径改动
文件引入之后呢,我们还需要根据我们的文件存放位置,来调整一下两个JS中的路径。以我的这一版api--.js为例:
3.引入文件出现的bug
文本无法选中
在引入地图相关文件的该页面中,会出现文本无法选中,使得用户无法复制。这个是因为modules_ditu.js引起的,因为有的modules--.js版本中,会加onselectstart = fasle 禁止选中文字
。然后呢,我试着在源码中,改变其值,反正是木得效果,没起作用。
最后的解决方法,百度的是,重新找几个老版本的modules--.js文件替上去即可。
vue中的代码实现
1.相关代码
index.html中引入
注:脚手架创建的项目中,因为webpack中打包静态文件路径默认是在static中,所以我们的静态文件也要放在static下。
<script type="text/javascript" src="./static/map/js/apiv1.3.min.js"></script>
modules_ditu不用在这引入,因为该JS是在api---.js中有引入,无需重复引入。
<template>
<div class="ip_query query clearfix">
<div id="map"></div>
</div>
</template>
<script>
export default {
data() {
return {
geo_data: {
city: null,
coord: null,
radius: null
}
};
},
created() {
let this_ = this;
let ipLocation = {
city: null,
coord: null,
radius: 600
};
// 赋值
this.geo_data = {
city: ipLocation.city ? ipLocation.city : "北京",
coord: [
ipLocation.lngwgs ? ipLocation.lngwgs : 116.397469,
ipLocation.latwgs ? ipLocation.latwgs : 39.908821
],
radius: ipLocation.radius
};
// 绘制地图
this.$nextTick(() => {
let IpMap_ec = this.echarts.init(document.getElementById("map"));
let map_render = function(params, api) {
let x_y = api.coord(this_.geo_data.coord);
let r = api.size([0, 1])[1] * (this_.geo_data.radius / 80);
let color = "#A7C2DF";
return {
type: "circle",
shape: {
cx: x_y[0],
cy: x_y[1],
r: r
},
style: api.style({
fill: color,
stroke: this_.echarts.color.lift(color)
})
};
};
IpMap_ec.setOption(
{
bmap: {
center: this.geo_data.coord,
zoom: 5,
roam: "scale"
},
series: [
{
type: "scatter",
coordinateSystem: "bmap",
symbol: "circle",
symbolSize: 30,
data: [
{
name: this.geo_data.city,
value: this.geo_data.coord
}
]
},
{
type: "custom",
coordinateSystem: "bmap",
renderItem: map_render,
itemStyle: {
opacity: 0.5
},
animation: false,
silent: true,
data: [0],
z: -10
}
]
},
true
);
// map API事件相关
let bmap = IpMap_ec.getModel()
.getComponent("bmap")
.getBMap();
bmap.setMinZoom(3);
bmap.setMaxZoom(7);
// 解决滚动触发2次zoomstart时的情形
let zoom_arr = [];
bmap.addEventListener("zoomstart", function() {
let zoom_level = bmap.getZoom();
zoom_arr.push(zoom_level);
});
let zoom_map = function() {
let point = new BMap.Point(
this_.geo_data.coord[0],
this_.geo_data.coord[1]
);
if (zoom_arr.length > 1) {
let end_level = bmap.getZoom();
let differ = end_level - zoom_arr[0];
let res_level = differ > 0 ? zoom_arr[0] + differ - 1 : zoom_arr[0] + differ + 1;
zoom_arr = [];
bmap.centerAndZoom(point, res_level);
} else {
bmap.centerAndZoom(point, bmap.getZoom());
zoom_arr = [];
}
};
// 缩扩固定中心点
bmap.addEventListener("zoomend", zoom_map);
});
}
};
</script>
<style lang="stylus" scoped>
.ip_query {
#map {
width: 900px;
height: 600px;
position: relative;
margin: 30px auto;
}
}
</style>
实现效果:
2.相关bug或优化点
1.如果2次或多次实例化echarts,滑轮滚动一次,缩扩2个级别
因为我做的这一版地图主要是运用到IP查询中,可能会出现查询失败,查询时的input框及查询内容的动态过渡效果的实现,然后我这里是简单粗暴的多次实例化echarts来达到效果。这样会出现一个问题,就是多次搜索IP,地图中缩扩时会出现滑轮滚动一次,缩扩2个级别,然后做了个判断,来手动让他恢复缩放正常情况下。
// 解决滚动触发2次zoomstart时的情形
let zoom_arr = [];
bmap.addEventListener("zoomstart", function() {
let zoom_level = bmap.getZoom();
zoom_arr.push(zoom_level);
});
let zoom_map = function() {
let point = new BMap.Point(
this_.geo_data.coord[0],
this_.geo_data.coord[1]
);
if (zoom_arr.length > 1) {
let end_level = bmap.getZoom();
let differ = end_level - zoom_arr[0];
let res_level;
if (differ > 0) {
res_level = zoom_arr[0] + differ - 1;
} else {
res_level = zoom_arr[0] + differ + 1;
}
zoom_arr = [];
bmap.centerAndZoom(point, res_level);
} else {
bmap.centerAndZoom(point, bmap.getZoom());
zoom_arr = [];
}
};
// 缩扩固定中心点
bmap.addEventListener("zoomend", zoom_map);
2.拖拽出边界时的优化
地图实质上就是瓦片图的拼接,但是离线地图受制于瓦片图的完善度,拖拽出边界后,我们实质上是没有图片可以引了。所以,会出现灰边(咋们的背景色),体验不好。
最好的效果就是:用户拖拽至边界时,禁用拖拽。往回拖时,再启用拖拽。或者 是做成球形的效果,拖拽至左侧边界时,出现右侧边界,但难度较大。我这里完成的是类似第一种效果,也并不完美。
去年在做的时候,本意是想在每次拖拽开始时(dragstart)先判断当前是否在边界处,在边界处就继续禁用拖拽,dragging中判断滑动至边界时,直接禁用拖拽map.disableDragging();
,然后dragend中再启用拖拽。但是,实际中禁用拖拽后,比如dragging中禁用拖拽,他就不走dragend了,直接在dragging这一状态便停止了,然后其他的回调情况也是类似这种,我没有找到完善的触发这套流程的回调,所以就没能实现。
因为离线地图的资料比较少,百度地图的API中也并不完善,没有相关的回调,我又没能力自己封装,所以就采用的是下边这种。 这里的思路就是:
因为我们只有4个缩放层级,然后通过百度地图的相关API手动测出临界值时所对应的中心点经纬度,在拖拽出边界时,给他拖回当前临界值对应的中心点。然后呢,这里的问题就是:当你拖拽出边界时,再拖回边界所对应的中心点时,实际上是有一个过程的,会有一定的时间来完成这个流程。然后这种情况呢,就会触发多次拖拽回当前中心点,用户的体验就是下图中:拖拽出左边界时,会下滑一定距离。只会回到当前左边界中心点对应的x处,y是会下滑一些的。关于这个问题的解决,我在后来学习了防抖节流之后,可以用节流的思路去完善一下。
let x = 0;
let y = 0;
map.addEventListener('dragging', function () {
console.log(map.getBounds().getCenter());
//移动后的可视区域
var movew = map.getBounds().getSouthWest(); //可视区域左下角
var movee = map.getBounds().getNorthEast(); //可视区域右上角
var moveL = movew.lng;//可视区域左边界的经度
var moveR = movee.lng;//可视区域右边界的经度
var moveB = movew.lat;//可视区域下边界的纬度
var moveT = movee.lat;//可视区域上边界的纬度
var boundaryleftlng;//左边界临界值经度
var boundaryrightlng;//右边界临界值经度
var boundarytoplat;//上边界临界值纬度
var boundarydownlat;//下边界临界值纬度
if (zoom == 4) {
boundaryleftlng = -179.204242;
boundarydownlat = -82.202266;
boundaryrightlng = 180.910992
boundarytoplat = 84.602547;
if (moveR > boundaryrightlng) {
x = 60;
} else if (moveL < boundaryleftlng) {
x = -58;
} else {
x = map.getBounds().getCenter().lng;
}
if (moveT > boundarytoplat) {
y = 65;
} else if (moveB < boundarydownlat) {
y = -55;
} else {
y = map.getBounds().getCenter().lat;
}
} else if (zoom == 5) {
boundaryleftlng = -179.940134;
boundarydownlat = -81.533889;
boundaryrightlng = 179.690224;
boundarytoplat = 84.602547;
if (moveR > boundaryrightlng) {
x = 120;
} else if (moveL < boundaryleftlng) {
x = -120;
} else {
x = map.getBounds().getCenter().lng;
}
if (moveT > boundarytoplat) {
y = 79;
} else if (moveB < boundarydownlat) {
y = -55;
} else {
y = map.getBounds().getCenter().lat;
}
} else if (zoom == 6) {
boundaryleftlng = -179.976929;
boundarydownlat = -81.133421;
boundaryrightlng = 179.984581;
boundarytoplat = 84.581712;
if (moveR > boundaryrightlng) {
x = 150;
} else if (moveL < boundaryleftlng) {
x = -150;
} else {
x = map.getBounds().getCenter().lng;
}
if (moveT > boundarytoplat) {
y = 82;
} else if (moveB < boundarydownlat) {
y = -73;
} else {
y = map.getBounds().getCenter().lat;
}
} else if (zoom == 7) {
boundaryleftlng = -179.811353;
boundarydownlat = -80.952417;
boundaryrightlng = 179.910992;
boundarytoplat = 84.607743;
if (moveR > boundaryrightlng) {
x = 164;
} else if (moveL < boundaryleftlng) {
x = -164;
} else {
x = map.getBounds().getCenter().lng;
}
if (moveT > boundarytoplat) {
y = 83;
} else if (moveB < boundarydownlat) {
y = -78;
} else {
y = map.getBounds().getCenter().lat;
}
}
if(moveR > boundaryrightlng || moveL < boundaryleftlng || moveT > boundarytoplat || moveB < boundarydownlat){
// map.disableDragging();
var point = new BMap.Point(x,y);
map.centerAndZoom(point, map.getZoom());
}
});
3.mousemove事件耗时久使得拖拽体验不好(未解决)
vue版的代码中我禁止了拖拽,因为我用的两个JS文件和上面的JS版的是一样的,但是用最新版的echarts加vue引入后,拖拽时会报这个警告,会很卡顿,正好我们的需求也不用拖拽,我就禁了给。如果你需要拖拽的话可以试试多找几个版本的api--.js和module--.js替上去试试看能否解决。
尾言
感谢您能看到这里,如果觉得有些许收获的话,请动动你发财的小手,给小编点个赞吧~ !
因为目前是五一假期,瓦片图那个文件太大了,我就没拷,之后我会把我这一版地图的相关文件,上传到百度云,后续会放个链接,大家感兴趣的可以下载一下,试试看。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!