目录
百度地图 javascript api gl 地图聚合点、地图框选功能开发
参考地址: 百度地图的开发者频道
注意:使用前要先登录百度账号申请一个浏览器端的 ak,详见 ak 申请
创建地图以及初始化交通流量图层
引用 gl 版本的 js api:
<script src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=你的密钥"></script>
初始化地图的 javascript 代码:
const map = new bmapgl.map('map', {
// minzoom: 11,
// maxzoom: 20,
});
map.centerandzoom('武汉', 12, {
callback: () => {
// 一定要在回调中开启交通流量图层
map.settrafficon();
},
});
map.enablescrollwheelzoom(true);
bmapgl.map
bmapgl.map 类是地图api的核心类,用来实例化一个地图。请注意 webgl 版本的地图 api 的命名空间是bmapgl。
构造函数 | 描述 |
---|---|
map(container: string | htmlelement, opts: mapoptions ) | 在指定的容器内创建地图实例,之后需要调用map.centerandzoom()方法对地图进行初始化,未进行初始化的地图将不能进行任何操作。 |
mapoptions
属性 | 类型 | 描述 |
---|---|---|
minzoom | number | 地图允许展示的最小级别 |
maxzoom | number | 地图允许展示的最大级别 |
maptype | maptypeid | 地图类型,默认为bmap_normal_map |
enableautoresize | boolean | 开启自动适应地图容器变化,默认启用 |
enabletilt | boolean | 是否允许地图倾斜 |
enablerotate | boolean | 是否允许地图旋转 |
enablerotategestures | boolean | 是否允许通过手势旋转地图。 |
enabletiltgestures | boolean | 是否允许通过手势倾斜地图。 |
overlaytop | boolean | 覆盖物是否显示在文字上面,默认false |
fixcenterwhenpinch | boolean | 手势缩放是否固定中心点,默认不固定,由手指中心点决定 |
displayoptions | object | 配置地图显示元素。该参数详细信息请参见 setdisplayoptions方法 |
map.centerandzoom() 对地图进行初始化
调用 new bmapgl.map
之后需要使用 map.centerandzoom()
对地图进行初始化,否则不能对地图进行任何操作。
入参:
centerandzoom(center: point , zoom: number)
描述:
初始化地图,如果 center 的类型为 point 时,zoom 必须赋值,范围 3-19 级,若调用高清底图(针对移动端开发)时,zoom 可赋值范围为 3-18 级。如果 center 类型为字符串时,比如“北京”,zoom可以忽略,地图将自动根据 center 适配最佳 zoom 级别。
设置地图元素
通过 map.setdisplayoptions({option: displayoptions }) 可以设置地图元素显隐。
displayoptions
属性 | 类型 | 描述 |
---|---|---|
poi | boolean | 是否显示 poi 信息。注意:poi 、poitext 与 poiicon 均用来配置 poi 显示。当 poi 为 true 时,可配置另外两个选项;如果为 false ,则另外两个选项不再生效。 |
poitext | boolean | 是否显示poi文字信息 |
poiicon | boolean | 是否显示poi的icon |
overlay | boolean | 是否显示覆盖物 |
building | boolean | 是否显示3d建筑物(仅支持 webgl 方式渲染的地图) |
indoor | boolean | 是否显示室内图(仅支持 webgl 方式渲染的地图) |
street | boolean | 是否显示路网(只对卫星图和地球模式有效) |
skycolor | array | 配置天空的颜色,数组中首个元素表示地面颜色,第二个元素表示天空颜色。从而形成渐变,支持只传入一个元素。 |
点覆盖物 (marker)
通过 marker
构造函数可以根据经纬度在地图上生成各类的点覆盖物。
构造函数:marker(point: point , opts: markeroptions )
使用自定义图片生成指定大小的 marker,并且设置名称(label)
示例:生成一个 32 * 47 像素的图片 marker,并且将地图的中心点定位到点位的经纬度上。
map.centerandzoom('武汉', 12, {
callback: () => {
// 构造一个包含经纬度和点位名称的数据
const data = {
lng: 114.32947483740818,
lat: 30.62295757673447,
name: '汉口江滩三期',
};
// 提前定义 marker 的宽高
const width = 32;
const height = 47;
// 构造一个 point 点位
const point = new bmapgl.point(data.lng, data.lat);
// 构造一个 marker
const marker = new bmapgl.marker(point, {
icon: new bmapgl.icon( // icon 接收一个 icon 对象,通过 bmapgl.icon 构造函数生成
'/marker-red.png', // 图标的绝对路径
new bmapgl.size(width, height), // 图标的尺寸,通过 bmapgl.size 构造函数生成
// marker 的配置项,参考:
// https://mapopen-pub-jsapi.bj.bcebos.com/jsapi/reference/jsapi_webgl_1_0.html#a3b2
{
// anchor 可以理解为要将图片的哪个坐标点位设置到对应的经纬度上,左上角为 (0,0) ,右下为正
// new bmapgl.size(width / 2, height) 的意思就是将图片底边的中心点定到对应的经纬度上去
anchor: new bmapgl.size(width / 2, height),
imageoffset: new bmapgl.size(0, 0),
imagesize: new bmapgl.size(width, height),
}
),
});
// 设置 marker 的 z-index 层级
marker.setzindex(2);
// 构造 label,参考:
// https://mapopen-pub-jsapi.bj.bcebos.com/jsapi/reference/jsapi_webgl_1_0.html#a3b8
const label = new bmapgl.label(
// label 的 html
`<span title="${data.name}">${data.name}</span>`,
{
position: point,
// label 的偏移, (0,10) 代表向下偏移 10 像素
offset: new bmapgl.size(0, 10),
}
);
// 使用 object 对象描述 label 的样式
label.setstyle({
border: 0,
backgroundcolor: 'rgba(0, 14, 17, 0.6)',
maxwidth: '120px',
// 使用 css 实现横向灵活居中而不是 offset
transform: 'translatex(-50%)',
whitespace: 'nowrap',
overflow: 'hidden',
textoverflow: 'ellipsis',
borderradius: '4px',
padding: '2px 6px',
color: '#fff',
fontsize: '18px',
});
// 设置层级
label.setzindex(2);
// 绑定 marker
marker.setlabel(label);
// 覆盖物上图
map.addoverlay(marker);
// 将地图定位到点位,并且设置层级为18
// noanimation 设置为 true 可以取消 setviewport 的动画过程
map.setviewport(
{
center: point,
zoom: 18,
},
{
noanimation: true,
}
);
},
});
map.enablescrollwheelzoom(true);
信息窗体 (infowindow)
通过构造函数生成infowindow对象并设置 html 内容:
// 构造 infowindow
const infowindowcontent = `
<div class="info-content">
<div class="label">名称:${data.name}</div>
<div class="label">位置:${data.lng},${data.lat}</div>
</div>
`;
const infowindow = new bmapgl.infowindow(infowindowcontent, {
title: '点位信息',
width: 360
});
// 点标记添加点击事件
marker.addeventlistener('click', () => {
map.setviewport(
{
center: point,
zoom: 18,
},
{
noanimation: true,
callback: () => {
map.openinfowindow(infowindow, point);
infowindow.disablecloseonclick();
},
}
);
});
关于 infowindow 自带的丑箭头以及立体阴影效果
百度地图渲染出的 infowindow 自带一个白色的箭头以及一个向右上方倾斜的阴影,如下图:
如果你不想要它,可以使用 css 隐藏自带箭头的图片元素以及自带的阴影,并自己用 css 写一个箭头,下面给一个简单的例子:
/* 隐藏箭头 */
img[src="http://webmap0.bdimg.com/image/api/iw_tail.png"] {
display: none;
}
/* 写一个普通箭头 */
.bmap_bubble_pop::after {
position: absolute;
top: 100%;
left: 50%;
content: '';
margin-left: -8px;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid #e4e4e4;
border-bottom: 8px solid transparent;
}
/* 隐藏阴影 */
.shadow[type='infowindow_shadow'] {
display: none;
}
聚合点 (cluster)
bmapgl 中没有关于聚合点的渲染相关的类,那是因为百度将其放在了 mapvgl 中。
聚合点分为点聚合和图标聚合,如果想自定义不同聚合程度下的图标样式,推荐使用图标聚合 iconclusterlayer,代码参考官方示例即可。
热力图(heatmap)
热力图也是热力图分为 热力点 和 热力图,代码参考官方示例即可。
鼠标绘制工具
基于百度地图 jsapi gl 版本,百度推出了 bmap-draw ,它提供了一系列 api 用于完成鼠标绘制的诸多功能,比如绘制矩形,圆形,多边形等。
绘制(draw)
绘制类 用于鼠标绘制点线面,支持吸附绘制,是鼠标绘制的基础能力。开启之后鼠标会变成十字准星样式,按照提示操作鼠标即可完成图形的绘制。
选择工具(select)
bmap-draw 提供了 select 类用于地图中的 marker 的框选,以 矩形框选 为例,配置项 type
设置为 drawingtype.drawing_rectangle
,基于绑定监听 operateeventtype.complete
事件,实现框选功能。
聚合点的框选
在 bmap-draw 的选择工具代码示例中可以看出选择工具默认支持的是 geojsonlayer 图层,也即点(marker)、线(polyline)、面(polygon),看起来似乎无法支持聚合图层的框选,但有时我们就是需要框选出地图上的聚合点,这时就需要使用百度推出的另一个工具 bmapgllib。
bmapgllib 是基于百度地图 jsapi gl 版的 javascript 开源工具库。拥有一下能力:
-
鼠标绘制工具条库 示例
提供鼠标绘制点、线、面、多边形(矩形、圆)的编辑工具条的开源代码库。且用户可使用javascript api对应覆盖物(点、线、面等)类接口对其进行属性(如颜色、线宽等)设置、编辑(如开启线顶点编辑等)等功能。
-
测距工具 示例
百度地图的测距工具类,对外开放。 允许用户在地图上点击完成距离的测量。 使用者可以自定义测距线段的相关样式,例如线宽、颜色、测距结果所用的单位制等等。
-
几何运算 示例
geoutils类提供若干几何算法,用来帮助用户判断点与矩形、 圆形、多边形线、多边形面的关系,并提供计算折线长度和多边形的面积的公式。
-
视角轨迹动画 示例
trackanimation类提供视角轨迹动画展示效果。
-
区域限制 示例
百度地图浏览区域限制类,对外开放。 允许开发者输入限定浏览的地图区域的bounds值, 则地图浏览者只能在限定区域内浏览地图。
-
百度地图的infobox。类似于infowindow,比infowindow更有灵活性,比如可以定制border,关闭按钮样式等。
-
百度地图的富marker类,对外开放。 允许用户在自定义丰富的marker展现样式,并添加点击、双击、拖拽等事件。
-
路书 示例
百度地图路书类,实现marker沿路线运动,对外开放。 用户可以在地图上自定义轨迹运动,支持暂停/停止功能,并可以自定义路过某个点的图片,文字介绍等。
下面是一个框选聚合点的完整示例:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>百度地图 js api 使用教程</title>
<script src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=j3n7g7jzrldhyxqix7jwjytuwwodxtty"></script>
<script src="https://unpkg.com/mapvgl/dist/mapvgl.min.js"></script>
<script src="/bmap-draw.min.js"></script>
<script src="/geoutils.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh;
}
.btn-con {
position: absolute;
top: 24px;
left: 40px;
z-index: 6;
}
.btn {
width: 90px;
height: 32px;
border-radius: 3px;
background-color: #2985f7;
color: #fff;
border-width: 0;
cursor: pointer;
}
</style>
</head>
<body>
<div class="btn-con">
<button class="btn" id="opencircle">圆形框选</button>
<button class="btn" id="openrect">矩形框选</button>
<button class="btn" id="openpolygon">多边形框选</button>
<button class="btn" id="close">关闭</button>
<button class="btn" id="clear">清除</button>
</div>
<div id="map"></div>
<script>
const map = new bmapgl.map('map');
map.centerandzoom('武汉', 14, {
callback: () => {
renderclusterlayer();
initdrawutil();
initevents();
},
});
map.enablescrollwheelzoom(true);
// 鼠标绘制工具
let scene, rectdraw, polygondraw, circledraw, activedraw;
// 图标聚合图层
let iconclusterlayer = null;
// 绑定事件
function initevents() {
document.queryselector('#opencircle').addeventlistener('click', opencircle);
document.queryselector('#openrect').addeventlistener('click', openrect);
document.queryselector('#openpolygon').addeventlistener('click', openpolygon);
document.queryselector('#close').addeventlistener('click', close);
document.queryselector('#clear').addeventlistener('click', clear);
function opencircle() {
activedraw = circledraw;
circledraw.open();
}
function openrect() {
activedraw = rectdraw;
rectdraw.open();
}
function openpolygon() {
activedraw = polygondraw;
polygondraw.open();
}
function close() {
activedraw.close();
}
function clear() {
scene && scene.cleardata();
}
}
// 渲染聚合点
function renderclusterlayer() {
const data = [
{
name: '位置1',
lng: 114.32074427093403,
lat: 30.614411917020718,
},
{
name: '位置2',
lng: 114.31715104889412,
lat: 30.614038958043224,
},
{
name: '位置3',
lng: 114.31513884455177,
lat: 30.60950117426803,
},
{
name: '位置4',
lng: 114.31844460882849,
lat: 30.611490366197277,
},
{
name: '位置5',
lng: 114.32268461083558,
lat: 30.611490366197277,
},
];
const geojsondata = [];
data.foreach((item) => {
geojsondata.push({
geometry: {
type: 'point',
coordinates: [item.lng, item.lat],
},
properties: {
extradata: item, // 将数据本身保存到这里后面要用
icon: 'https://maponline0.bdimg.com/sty/map_icons2x/mapres/zhongyangjigou.png',
width: 40,
height: 40,
},
});
});
const view = new mapvgl.view({
map: map,
});
iconclusterlayer = new mapvgl.iconclusterlayer({
textoptions: {
fontsize: 20,
format: function (count) {
return count;
},
},
iconoptions: {
width: 40,
height: 40,
},
iconextent: {
0: 'https://a.amap.com/jsapi_demos/static/images/blue.png',
5: 'https://a.amap.com/jsapi_demos/static/images/green.png',
10: 'https://a.amap.com/jsapi_demos/static/images/orange.png',
15: 'https://a.amap.com/jsapi_demos/static/images/red.png',
34: 'https://a.amap.com/jsapi_demos/static/images/darkred.png',
},
// enablepicked: true,
onclick: (e) => {
if (!e.dataitem) {
return;
}
const { id, children, geometry, properties } = e.dataitem;
if (children) {
console.log(children);
alert('点击了聚合点');
} else {
console.log(properties);
alert('点击了marker');
}
},
});
view.addlayer(iconclusterlayer);
iconclusterlayer.setdata(geojsondata);
}
// 初始化鼠标绘制工具
function initdrawutil() {
scene = new bmapgldraw.drawscene(map, {
nolimit: true, // 不对框选范围做限制
});
const labeloptions = {
borderradius: '2px',
background: '#b5d3fb',
border: '1px solid #b5d3fb',
color: '#333',
fontsize: '12px',
letterspacing: '0',
padding: '5px',
};
const baseopts = {
fillcolor: '#fff',
strokecolor: '#00ffee',
strokeweight: 5,
strokeopacity: 1,
fillopacity: 0.2,
};
rectdraw = new bmapgldraw.rectdraw(scene, {
isopen: false,
isseries: false,
labeloptions,
baseopts,
});
polygondraw = new bmapgldraw.polygondraw(scene, {
isseries: false,
isopen: false,
labeloptions,
baseopts,
});
circledraw = new bmapgldraw.circledraw(scene, {
isopen: false,
isseries: false,
labeloptions,
baseopts,
});
const rectcallback = (e) => {
if (!e.target.overlay.togeojson) {
alert('当前jsapi版本不支持圆选');
return;
}
// 获取当前层级下地图中的聚合数据
const clusterdata = iconclusterlayer.getclusterdata(map.getbounds(), map.getzoom());
console.log('clusterdata', clusterdata);
const clusterpoints = [];
clusterdata.foreach((v) => {
const pt = new bmapgl.point(...v.geometry.coordinates);
const bds = e.target.overlay.getbounds();
if (bmapgllib.geoutils.ispointinrect(pt, bds)) {
clusterpoints.push(v);
}
});
// clusterpoints 是框选到的聚合点和普通 marker 点
console.log(getclusterinnermarkers(clusterpoints));
};
const polygoncallback = (e) => {
if (!e.target.overlay.togeojson) {
alert('当前jsapi版本不支持圆选');
return;
}
// 获取当前层级下地图中的聚合数据
const clusterdata = iconclusterlayer.getclusterdata(map.getbounds(), map.getzoom());
const clusterpoints = [];
clusterdata.foreach((v) => {
const pt = new bmapgl.point(...v.geometry.coordinates);
if (bmapgllib.geoutils.ispointinpolygon(pt, e.target.overlay)) {
clusterpoints.push(v);
}
});
console.log(getclusterinnermarkers(clusterpoints));
};
const circlecallback = (e) => {
if (!e.target.overlay.togeojson) {
alert('当前jsapi版本不支持圆选');
return;
}
const center = e.target.overlay.getcenter();
const circle = new bmapgl.circle(center, e.target.overlay.radius); // 圆
// 获取当前层级下地图中的聚合数据
const clusterdata = iconclusterlayer.getclusterdata(map.getbounds(), map.getzoom());
const clusterpoints = [];
clusterdata.foreach((v) => {
const pt = new bmapgl.point(...v.geometry.coordinates);
if (bmapgllib.geoutils.ispointincircle(pt, circle)) {
clusterpoints.push(v);
}
});
console.log(getclusterinnermarkers(clusterpoints));
};
rectdraw.addeventlistener(bmapgldraw.operateeventtype.complete, rectcallback);
polygondraw.addeventlistener(bmapgldraw.operateeventtype.complete, polygoncallback);
circledraw.addeventlistener(bmapgldraw.operateeventtype.complete, circlecallback);
}
// 聚合点的数据提取出来
function getclusterinnermarkers(clusterpoints) {
let clustermarkers = [];
clusterpoints.foreach((pt) => {
if (pt.type === 'feature') {
// 聚合点
clustermarkers = clustermarkers.concat(iconclusterlayer.getclusterpoints(pt.id));
} else {
clustermarkers.push(pt);
}
});
return clustermarkers;
}
</script>
</body>
</html>
其中有几个 api 比较关键,但是没找到具体的文档,只能从源码中获取相关信息:
-
iconclusterlayer.getclusterdata
该方法的入参为 bound 和 zoom,顾名思义是获取地图的聚合图层上对应的 bound 和 zoom 上所有的点,包括聚合点和普通点,一般情况下需要对返回值遍历判断类型
-
iconclusterlayer.getclusterpoints(id)
通过聚合点的 id 获取聚合点下的所有的普通 marker 点的 geojson 数组。
该方法的入参为聚合点的 geojson 数据的 id,在上面的getclusterdata
方法返回的聚合点数组中会返回。 -
bmapgllib.geoutils.ispointinrect
该方法判断一个点是否在一个矩形内
-
bmapgllib.geoutils.ispointinpolygon
该方法判断一个点是否在一个多边形内
-
bmapgllib.geoutils.ispointincircle
该方法判断一个点是否在一个圆形内
over~
发表评论