本文主要记录基于百度地图API的投资地图前端开发过程和方法指导。
开发目标
- 设置中心点
- 仅采用测试数据
- 数据可根据类型显示不同图标
- 数据可能需要绘制出一片区域
- 根据提供的经纬度坐标将镜头转换到地图上对应标注点
- 隐藏公共定位点
- 缩放聚合
- 拾取坐标
申请百度地图API密钥
- 首先进入百度地图开放平台,右上角登陆账号后点击导航栏控制台。
- 进入控制台后依次点击左侧应用管理,我的应用,创建应用。
- 由于要开发的是一个网页端DEMO,因此应用类型选服务器端,下面的白名单就先填写半角星号即可。
- 这样一来,应用就创建成功了;在我的应用里就可以看见创建好的应用了!如图红方框内就得到了我们想要的密钥API KEY,简称AK。
快速开始
- 点击导航栏的快速开始,在下拉菜单中选择Javascript API。
- 跳转后点击DEMO详情,就可以看到百度地图提供的所有基础功能的源代码了。
- 除此以外,百度地图还提供了官方的坐标拾取器方便参考。
基本定义与设置
- 头部文件。
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=刚才的密钥"></script>
<title></title>
</head>
- Map实例的创建与地图的初始化设置,包含中心点坐标和默认缩放级别两个参数。其中中心点也可以不用地图点的方式,而选择直接以城市作为中心点,例如“上海”。
<body>
<div id="allmap"></div>
</body>
<script type="text/javascript">
// 百度地图API功能
var map = new BMap.Map("allmap"); // 创建Map实例
map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
</script>
地图控件和覆盖物的添加
- 工具条和比例尺控件,在百度地图里分别称作NavigationControl和ScaleControl;通过定义变量的方式添加这些控件,其中anchor参数设定你想放置的位置,有四个角可选;type参数设定你想控制的该控件的样式,例如默认缩放平移工具条是否包含平移和缩放按钮等。最后,用map.addControl()和map.removeControl()实现控件的添加和删除。
var top_left_control = new BMap.ScaleControl({anchor: BMAP_ANCHOR_TOP_LEFT});// 左上角,添加比例尺
var top_left_navigation = new BMap.NavigationControl(); //左上角,添加默认缩放平移控件
var top_right_navigation = new BMap.NavigationControl({anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL}); //右上角,仅包含平移和缩放按钮
/*缩放控件type有四种类型:
BMAP_NAVIGATION_CONTROL_SMALL:仅包含平移和缩放按钮;BMAP_NAVIGATION_CONTROL_PAN:仅包含平移按钮;BMAP_NAVIGATION_CONTROL_ZOOM:仅包含缩放按钮*/
//添加控件和比例尺
function add_control(){
map.addControl(top_left_control);
map.addControl(top_left_navigation);
map.addControl(top_right_navigation);
}
//移除控件和比例尺
function delete_control(){
map.removeControl(top_left_control);
map.removeControl(top_left_navigation);
map.removeControl(top_right_navigation);
}
- 地图类型和缩略图控件,和上面相似,都是百度地图默认提供的控件。同样地,地图类型空间可以通过修改type参数的方式设置可以切换哪些类型。
var mapType1 = new BMap.MapTypeControl(
{
mapTypes: [BMAP_NORMAL_MAP,BMAP_HYBRID_MAP],
anchor: BMAP_ANCHOR_TOP_LEFT
}
);
var overView = new BMap.OverviewMapControl();
var overViewOpen = new BMap.OverviewMapControl({isOpen:true, anchor: BMAP_ANCHOR_BOTTOM_RIGHT});
//添加地图类型和缩略图
function add_control(){
map.addControl(mapType1); //2D图,混合图
map.addControl(overView); //添加默认缩略地图控件
map.addControl(overViewOpen); //右下角,打开
}
//移除地图类型和缩略图
function delete_control(){
map.removeControl(mapType1); //移除2D图,混合图
map.removeControl(overView);
map.removeControl(overViewOpen);
}
- 本地图中对上述控件的综合应用示例如下,根据需求,在左上方添加移动定位和比例尺控件,右上方添加地图类型转换控件。
function addControl() {
//添加工具类
var top_left_navigation = new BMap.NavigationControl({
anchor: BMAP_ANCHOR_TOP_LEFT,
});
var top_right_type = new BMap.MapTypeControl({
anchor: BMAP_ANCHOR_TOP_RIGHT,
mapTypes: [BMAP_NORMAL_MAP, BMAP_HYBRID_MAP],
});
map.addControl(top_left_navigation);
map.addControl(top_right_type);
}
- 多边形覆盖物,可以在百度地图中充当区域的划定等功能。本地图中以两个例子进行举例。首先是最简单的绘制给定多边形的功能实现。首先定义一个多边形变量BMap.Polygon,其本质是由多个坐标点构成的边界坐标组;并可以对多边形的参数进行各种设置以改变外观样式。
var polygon = new BMap.Polygon(
[
//声明多边形区域的边界坐标
new BMap.Point(110.855163, 34.480104),
new BMap.Point(110.838491, 34.471058),
new BMap.Point(110.825842, 34.461296),
new BMap.Point(110.812907, 34.465105),
new BMap.Point(110.812907, 34.447008),
new BMap.Point(110.835616, 34.437005),
new BMap.Point(110.850564, 34.44677),
new BMap.Point(110.863499, 34.464153),
],
{
//声明多边形区域的参数
strokeColor: "#FFA500", //设置多边形的线条颜色
fillColor: "#FFA500", //设置多边形的填充颜色,空为白色
strokeWeight: 2, //设置边线的宽度
strokeOpacity: 0, //设置边线的透明度,0为完全不透明,1为完全透明
fillOpacity: 0.1, //填充的透明度,值越小越透明
strokeStyle: "dashed", //边线的样式,solid或dashed
}
);
map.addOverlay(polygon);
- 多边形覆盖物之进阶行政区划的表示。以本地图为例,需要将区域限定在需求方要求的区域即三门峡市,那么除了在第一部分默认中心点坐标进行设置以外,显然还需要进行一些限制与提醒。为此,根据@小虾米zheng提供的思路,利用行政区划点的集合与外围自定义东南西北形成一个环形遮罩层进而画出一个所需行政区域的高亮多边形。
function addBoundary() {
//为特定行政区域画片
var bdary = new BMap.Boundary();
bdary.get("三门峡", function (rs) {
// 获取行政区域
// 东西经南北纬的范围
var EN_JW = "180, 90;"; // 东北角
var NW_JW = "-180, 90;"; // 西北角
var WS_JW = "-180, -90;"; // 西南角
var SE_JW = "180, -90;"; // 东南角
// 添加环形遮罩层
var ply1 = new BMap.Polygon(
rs.boundaries[0] + SE_JW + SE_JW + WS_JW + NW_JW + EN_JW + SE_JW,
{
strokeColor: "none",
fillColor: "rgb(246,246,246)",
fillOpacity: 0.4,
strokeOpacity: 0.5,
}
); // 建立多边形覆盖物
map.addOverlay(ply1);
ply1.disableMassClear();
// 给目标行政区划添加一个没有填充物的遮罩层(即边框)
var ply = new BMap.Polygon(rs.boundaries[0], {
strokeWeight: 2,
strokeColor: "#008000",
fillColor: "",
});
map.addOverlay(ply);
ply.disableMassClear();
// map.setViewport(ply.getPath()); //调整视野
});
}
戳点详解
- 根据前面几个部分,对地图整体的面板渲染和一些区域划定的基本功能暂时完成,接下来进入核心:marker添加的详细编写步骤分析。首先看百度地图API提供的标注点示例,为了添加marker首先需要一个point作为参数;和之前的属性修改类似,还可以通过扩充icon属性来个性化地对marker的图标进行自定义。
// 百度地图API功能
var map = new BMap.Map("allmap");
var point = new BMap.Point(116.404, 39.915);
map.centerAndZoom(point, 15);
//创建小狐狸
var pt = new BMap.Point(116.417, 39.909);
var myIcon = new BMap.Icon("/jsdemo/img/fox.gif", new BMap.Size(300,157));
var marker2 = new BMap.Marker(pt,{icon:myIcon}); // 创建标注
map.addOverlay(marker2); // 将标注添加到地图中
- 除了戳点以外,我们还需要在对标注点进行点击的同时弹出信息框,在百度地图API中被称作信息窗口。同样地,先来看百度地图提供的文字型信息窗口示例。由下面的结合上一点可知,信息窗口依托于marker,marker依托于point,通过监听marker的点击动作让map执行openInfoWindow的动作,进而呈现出点击标注点弹出标注点详情的效果。而infoWindow本身可以同样看成一个BMap.InfoWindow数据类型,包含基本信息和属性参数设置信息,如下面示例中引号内内容和opts。
// 百度地图API功能
var map = new BMap.Map("allmap");
var point = new BMap.Point(116.417854,39.921988);
var marker = new BMap.Marker(point); // 创建标注
map.addOverlay(marker); // 将标注添加到地图中
map.centerAndZoom(point, 15);
var opts = {
width : 200, // 信息窗口宽度
height: 100, // 信息窗口高度
title : "海底捞王府井店" , // 信息窗口标题
enableMessage:true,//设置允许信息窗发送短息
message:"亲耐滴,晚上一起吃个饭吧?戳下面的链接看下地址喔~"
}
var infoWindow = new BMap.InfoWindow("地址:北京市东城区王府井大街88号乐天银泰百货八层", opts); // 创建信息窗口对象
marker.addEventListener("click", function(){
map.openInfoWindow(infoWindow,point); //开启信息窗口
});
- 综合上面两点梳理一下思路,我们添加点需要坐标,添加marker需要点或图标等属性信息(可选),添加infoWindow需要要展示的内容(可以包含html排版语法)和样式等属性信息(可选)。为此,把创建带信息窗口的标注点这个功能进行分解,首先根据前面的分析进行数据的准备。为了直观和规整起见,把每个点连同经纬度属性一起定义一个类似json的数据格式如下。
var data_info = [
//定义传入InfoWindow的展示信息
{
id: 1,
lng: "111.202664",
lat: "34.7769",
name: "方塔商圈",
type: "现代服务业",
addr: "三门峡市三门峡街",
dist: "三门峡市",
contact: "张三",
tel: "12345678",
email: "1@qq.com",
gca: "100000平方米",
gia: "100000平方米",
url: "http://viggoz.com/simpleMap/",
color: "红",
},
{
id: 2,
lng: "110.899525",
lat: "33.877797",
name: "三门商圈",
type: "传统工商业",
addr: "三门峡市解放路",
dist: "三门峡市",
contact: "李四",
tel: "23456789",
email: "2@qq.com",
gca: "200000平方米",
gia: "200000平方米",
url: "http://viggoz.com/simpleMap/",
color: "蓝",
},
{
id: 3,
lng: "110.845483",
lat: "34.46368",
name: "解放商圈",
type: "信息产业",
addr: "三门峡市红旗桥",
dist: "三门峡市",
contact: "王五",
tel: "34567890",
email: "3@qq.com",
gca: "300000平方米",
gia: "300000平方米",
url: "http://viggoz.com/simpleMap/",
color: "橙",
},
];
- 准备好数据之后进行为已有测试数据进行戳点并绘制信息窗口的函数的编写。首先遍历data_info数组先取出经纬度坐标和类型属性值,经纬度坐标用来创建点、类型属性值用来判断并赋予不同的图标。之后进行信息窗口参数的配置,由于我们不仅仅是将信息平铺在InfoWindow之上,而是想要一定的排版,因此抽取出一个content变量进行处理,如代码所示:通过html语法结合data_info数组中属性值的取出完成内容的拼接,之后opts设置宽高比和标题。前期准备都完成后,通过嵌套函数传入经纬度坐标、内容和信息窗属性四个参数,一口气完成戳点和吸窗口的操作;并将markers的数据push进defaultMarkersArray数组作为备用。函数在设计时一定要注意作用域的问题,以防遇到只能添加最后一个marker的尴尬局面。
var defaultMarkersArray = [];
function addMarkerWithInfo(data_info) {
//所有marker生成的核心功能函数
for (var i = 0, m = data_info.length; i < m; i++) {
type = data_info[i].type;
lng = data_info[i].lng;
lat = data_info[i].lat;
if (data_info[i].color == "红") {
//根据获取到的类型不同显示不同图标
var myIcon = new BMap.Icon(
"image/maker-with-ring.png",
new BMap.Size(40, 40)
);
} else if (data_info[i].color == "蓝") {
var myIcon = new BMap.Icon(
"image/maker-with-ring.png",
new BMap.Size(40, 40)
);
} else if (data_info[i].color == "橙") {
var myIcon = new BMap.Icon(
"image/maker-with-ring.png",
new BMap.Size(40, 40)
);
}
// 拼接内容展示
var content =
'<div class="BMap_bubble_content" >' +
'<div class="mapDiv">' +
'<p class="Tabletd"><b>名称:</b>' +
data_info[i].name +
"</p>" +
'<p class="Tabletd"><b>招商类型:</b>' +
data_info[i].type +
"</p>" +
'<p class="Tabletd"><b>地址:</b>' +
data_info[i].addr +
"</p>" +
'<p class="Tabletd"><b>所属区划:</b>' +
data_info[i].dist +
"</p>" +
'<p class="Tabletd"><b>联系人:</b>' +
data_info[i].contact +
"</p>" +
'<p class="Tabletd"><b>电话:</b>' +
data_info[i].tel +
"</p>" +
'<p class="Tabletd"><b>邮箱:</b>' +
data_info[i].email +
"</p>" +
'<p class="Tabletd"><b>总建筑面积:</b>' +
data_info[i].gca +
"</p>" +
'<p class="Tabletd"><b>总招商面积:</b>' +
data_info[i].gia +
"</p>" +
'<p class="Tabletd"><b>站点链接:</b><a href=' +
data_info[i].url +
">点此进入</a></p>" +
"</div>" +
"</div>";
var opts = {
//定义InfoWindow的一些其他参数options
width: 250,
height: 300,
title: '<p class="tableP" title="气泡信息">平台载体信息</p>', //信息窗口标题
};
var createMark = function (lng, lat, content, opts) {
//定义函数根据位置信息添加marker,再根据内容和参数创建marker的InfoWindow
var _marker = new BMap.Marker(new BMap.Point(lng, lat), {
icon: myIcon,
});
var label = new BMap.Label(data_info[i][12]);
label.setStyle({ display: "none" });
_marker.setLabel(label, { offset: new BMap.Size(20, -10) });
_marker.addEventListener("click", function (e) {
this.openInfoWindow(new BMap.InfoWindow(content, opts));
});
return _marker;
};
var marker = createMark(lng, lat, content, opts);
defaultMarkersArray.push(marker);
map.addOverlay(marker);
}
}
addMarkerWithInfo(data_info);
- 还记得上面存放进的defaultMarkersArray吗?接下来我们为标记点添加聚合功能就要用到它了。通过百度地图API,我们只需要生成一个marker数组,然后调用markerClusterer类即可。
// 为默认的地点添加聚合点
defaultMarkerClusterer = new BMapLib.MarkerClusterer(map, {
markers: defaultMarkersArray,
});
功能事件响应的实现
- 此处针对的主要是最开始的第5和第8个功能需求,下面先从拾取坐标说起。为了简单起见,下面口述一下html部分的元件就不展示代码了:首先三个text类型的input框,id分别是lat、lng和address用以展示拾取位置的经纬度和地址。之后是id为switchon、switchoff和open的三个button。之后功能的实现由javascript实现,首先document.getElementById的点击事件监听来add或remove函数功能的开启。
document.getElementById("open").onclick = function () {
//点击id为open的按钮时清除地图上的标记
clearOverlays();
};
document.getElementById("switchon").onclick = function () {
//点击id为switchon的按钮时开启戳点功能
map.addEventListener("click", showInfo);
};
document.getElementById("switchoff").onclick = function () {
//点击id为switchoff的按钮时关闭戳点功能
map.removeEventListener("click", showInfo);
};
- 坐标的拾取需要用到地址解析对象,同样根据获取元素修改文本框的值。最后点击清除标记按钮时,需要将已戳的点进行一下清空,此处由于需要防止默认标注点被清空,将点击戳点产生的新marker放入一个新的数组,这样之后removeOverlay时只请空这个数组的即可。
var geoc = new BMap.Geocoder(); //声明地址解析对象
function showInfo(e) {
//拾取戳点坐标与地点的函数
document.getElementById("lng").value = e.point.lng;
document.getElementById("lat").value = e.point.lat;
geoc.getLocation(e.point, function (rs) {
var addComp = rs.addressComponents;
var address =
addComp.province +
addComp.city +
addComp.district +
addComp.street +
addComp.streetNumber;
document.getElementById("address").value = address;
});
addMarker(e.point);
}
function addMarker(point) {
//戳点增加标注功能
var marker = new BMap.Marker(point);
markersArray.push(marker);
map.addOverlay(marker);
}
function clearOverlays() {
//对于戳点标注增加的标注点进行清除的函数
//清除标识
if (markersArray) {
for (i in markersArray) {
map.removeOverlay(markersArray[i]);
}
}
}
- 接下来是聚焦功能的实现,首先我们计划在页面的左侧安排一个有层次感的浮动列表。为此我们同样通过一个js函数填充左侧列表的元素。
// 左侧结果列表样式
$(function () {
infoFun();
});
function infoFun() {
for (j = 0; j < data_info.length; j++) {
$("div.ts-results-wrapper").append(
'<div class="ts-result-link" data-ts-id="' +
data_info[j].id +
'" data-ts-lng="' +
data_info[j].lng +
'" data-ts-lat="' +
data_info[j].lat +
'">' +
'<span class="ts-center-marker"><img src="assets/img/result-center.svg"></span>' +
'<a class="card ts-item ts-card ts-result">' +
'<div class="card-img ts-item__image" style="background-image: url(image/pic01.jpg)"></div>' +
'<div class="card-body">' +
'<div class="ts-item__info-badge">' +
data_info[j].gia +
"</div>" +
'<figure class="ts-item__info">' +
"<h4>" +
data_info[j].name +
"</h4>" +
"<aside>" +
'<i class="fa fa-map-marker mr-2"></i>' +
data_info[j].addr +
"</aside>" +
"</figure>" +
'<div class="ts-description-lists">' +
"<dl>" +
"<dt>产业类型</dt>" +
"<dd>" +
data_info[j].type +
"</dd>" +
"</dl>" +
"<dl>" +
"<dt>联系人</dt>" +
"<dd>" +
data_info[j].contact +
"</dd>" +
"</dl>" +
"<dl>" +
"<dt>联系电话</dt>" +
"<dd>" +
data_info[j].tel +
"</dd>" +
"</dl>" +
"<dl>" +
"<dt>电子邮件</dt>" +
"<dd>" +
data_info[j].email +
"</dd>" +
"</dl>" +
"</div>" +
"</div>" +
'<div class="card-footer">' +
'<span class="ts-btn-arrow">Detail</span>' +
"</div>" +
"</a>" +
"</div>"
);
}
}
- 之后实现点击聚焦到列表所在位置并放大的效果。通过获取到上面函数安排的每个div元素的id存放经纬度坐标,之后通过新建点,再panTo实现。
//点击定位到列表所在位置并放大效果
$(document).on("click", ".ts-result-link", function () {
var lng = $(this).attr("data-ts-lng");
var lat = $(this).attr("data-ts-lat");
var id = $(this).attr("data-ts-id");
// var addr = $(this).attr("data-addr");
if (lng == "undefined" || lat == "undefined")
alert($(this).find("span").eq(0).text());
else {
var point = new BMap.Point(lng, lat);
map.panTo(new BMap.Point(lng, lat)); //定位到所点击的位置
}
});
其他优化
- 隐藏公共定位点。只需在创建Map实例时关闭默认地图POI事件即可。
var map = new BMap.Map("ts-map-hero", { enableMapClick: false }); //创建Map实例,并关闭默认地图POI事件
- 极简地图风格设置。通过调整透明度、曝光度和地铁等公共设施元素的可视化做出的一种极简地图风格,仅供选用。
map.setMapStyle({
styleJson: [
{
featureType: "all",
elementType: "all",
stylers: {
weight: "0.4",
lightness: 47,
saturation: -100,
},
},
{
featureType: "subway",
elementType: "labels.icon",
stylers: {
saturation: -100,
visibility: "off",
},
},
],
});
以上,就是目前在开发产业投资地图过程中各阶段的功能需求和实现方法。未来可能会根据开发进度和实际情况继续更新,欢迎大家多多关注!