当前位置: 代码网 > it编程>编程语言>Javascript > 百度地图 JavaScript API GL + mapV GL + bmap-draw 实现地图聚合点以及聚合点框选功能开发

百度地图 JavaScript API GL + mapV GL + bmap-draw 实现地图聚合点以及聚合点框选功能开发

2024年07月28日 Javascript 我要评论
使用百度地图 JavaScript API GL + bmap-draw + mapV GL 工具包开发地图的一系列功能,包括聚合点、地图框选功能

百度地图 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

属性类型描述
minzoomnumber地图允许展示的最小级别
maxzoomnumber地图允许展示的最大级别
maptypemaptypeid地图类型,默认为bmap_normal_map
enableautoresizeboolean开启自动适应地图容器变化,默认启用
enabletiltboolean是否允许地图倾斜
enablerotateboolean是否允许地图旋转
enablerotategesturesboolean是否允许通过手势旋转地图。
enabletiltgesturesboolean是否允许通过手势倾斜地图。
overlaytopboolean覆盖物是否显示在文字上面,默认false
fixcenterwhenpinchboolean手势缩放是否固定中心点,默认不固定,由手指中心点决定
displayoptionsobject配置地图显示元素。该参数详细信息请参见 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

属性类型描述
poiboolean是否显示 poi 信息。注意:poipoitextpoiicon 均用来配置 poi 显示。当 poitrue 时,可配置另外两个选项;如果为 false,则另外两个选项不再生效。
poitextboolean是否显示poi文字信息
poiiconboolean是否显示poi的icon
overlayboolean是否显示覆盖物
buildingboolean是否显示3d建筑物(仅支持 webgl 方式渲染的地图)
indoorboolean是否显示室内图(仅支持 webgl 方式渲染的地图)
streetboolean是否显示路网(只对卫星图和地球模式有效)
skycolorarray配置天空的颜色,数组中首个元素表示地面颜色,第二个元素表示天空颜色。从而形成渐变,支持只传入一个元素。

点覆盖物 (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 自带一个白色的箭头以及一个向右上方倾斜的阴影,如下图:

自带的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 开源工具库。拥有一下能力:

  1. 鼠标绘制工具条库 示例

    提供鼠标绘制点、线、面、多边形(矩形、圆)的编辑工具条的开源代码库。且用户可使用javascript api对应覆盖物(点、线、面等)类接口对其进行属性(如颜色、线宽等)设置、编辑(如开启线顶点编辑等)等功能。

  2. 测距工具 示例

    百度地图的测距工具类,对外开放。 允许用户在地图上点击完成距离的测量。 使用者可以自定义测距线段的相关样式,例如线宽、颜色、测距结果所用的单位制等等。

  3. 几何运算 示例

    geoutils类提供若干几何算法,用来帮助用户判断点与矩形、 圆形、多边形线、多边形面的关系,并提供计算折线长度和多边形的面积的公式。

  4. 视角轨迹动画 示例

    trackanimation类提供视角轨迹动画展示效果。

  5. 区域限制 示例

    百度地图浏览区域限制类,对外开放。 允许开发者输入限定浏览的地图区域的bounds值, 则地图浏览者只能在限定区域内浏览地图。

  6. 自定义信息窗口 顶部示例 底部示例

    百度地图的infobox。类似于infowindow,比infowindow更有灵活性,比如可以定制border,关闭按钮样式等。

  7. 富标注 示例1 示例2

    百度地图的富marker类,对外开放。 允许用户在自定义丰富的marker展现样式,并添加点击、双击、拖拽等事件。

  8. 路书 示例

    百度地图路书类,实现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 比较关键,但是没找到具体的文档,只能从源码中获取相关信息:

  1. iconclusterlayer.getclusterdata

    该方法的入参为 bound 和 zoom,顾名思义是获取地图的聚合图层上对应的 bound 和 zoom 上所有的点,包括聚合点和普通点,一般情况下需要对返回值遍历判断类型

  2. iconclusterlayer.getclusterpoints(id)

    通过聚合点的 id 获取聚合点下的所有的普通 marker 点的 geojson 数组。
    该方法的入参为聚合点的 geojson 数据的 id,在上面的 getclusterdata 方法返回的聚合点数组中会返回。

  3. bmapgllib.geoutils.ispointinrect

    该方法判断一个点是否在一个矩形内

  4. bmapgllib.geoutils.ispointinpolygon

    该方法判断一个点是否在一个多边形内

  5. bmapgllib.geoutils.ispointincircle

    该方法判断一个点是否在一个圆形内

over~

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com