在地图中,显示多个地点的时候,想要更好的区分,往往会使用不同样式的地点图标,或改变图标的形状,或改变图标的颜色,或在图标上加上字符。论其成本,恐怕在原有地点图标上加上字符是最低的,添加字符相对来说也更利于区分。

百度地图 API 是采用 Icon 类来修改覆盖物,使用上 Marker 来完成标注的覆盖[1][2],可以用以下几种方式来实现加载带有数字或字母的 Marker。

单张图片

这是最没办法的办法,一个一个来,先放代码,后放示例。

<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>
<div id="map"></div>
<script type="text/javascript">
  var map = new BMap.Map('map');
  map.centerAndZoom(new BMap.Point(116.4, 23.4), 10);
  var size1 = new BMap.Size(23, 25);
  var size2 = new BMap.Size(11.5, 25);
  var points = [],
      icons = [],
      markers = [];
  var icons = [
    new BMap.Icon('http://7fv9cr.com1.z0.glb.clouddn.com/marker_a.png', size1, {anchor: size2 }),
    new BMap.Icon('http://7fv9cr.com1.z0.glb.clouddn.com/marker_b.png', size1, {anchor: size2 }),
    new BMap.Icon('http://7fv9cr.com1.z0.glb.clouddn.com/marker_c.png', size1, {anchor: size2 })
  ];
  for (var i = 0; i < 3; i++){
    points[i] = new BMap.Point(parseFloat('116.' + (i*3+1).toString()), 23.4);
    markers[i] = new BMap.Marker(points[i], {icon: icons[i]});
    map.addOverlay(markers[i]);
  }
</script>

通过 Image Sprites

既然是图片,那么可以使用类似于 CSS Image Sprites[3] 的方法来加载,通过 Icon 类 的 imageOffset 属性可以实现,具体如下:

<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>
<div id="map"></div>
<script type="text/javascript">
  var map = new BMap.Map('map');
  var size1 = new BMap.Size(23, 25);
  var size2 = new BMap.Size(11.5, 25);
  map.centerAndZoom(new BMap.Point(116.4, 23.4), 10);
  var points = [],
      icons = [],
      markers = [];
  for (var i = 0; i < 3; i++){
    points[i] = new BMap.Point(parseFloat('116.' + (i*3+1).toString()), 23.4);
    icons[i] = new BMap.Icon('http://7fv9cr.com1.z0.glb.clouddn.com/markers.png', size1, {anchor: size2, imageOffset: new BMap.Size(0, -(i+3)*25)});
    markers[i] = new BMap.Marker(points[i], {icon: icons[i]});
    map.addOverlay(markers[i]);
  }
</script>

通过 HTML5 Canvas

另外,也可通过 HTML5 的 Canvas 在图片里添加文字达到标注上加文字的效果,具体可参考台湾同胞的文章——利用 Canvas 製作 Google Maps API Marker Icon[4]

<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>
<div id="map"></div>
<script type="text/javascript">
  var map = new BMap.Map('map');
  var size1 = new BMap.Size(23, 25);
  var size2 = new BMap.Size(11.5, 25);
  var letter,
      points = [],
      icons = [],
      markers = [];
  map.centerAndZoom(new BMap.Point(116.4, 23.4), 10);
  var image = new Image();
  image.crossOrigin = '*';
  image.onload = function (){
    var width = this.width;
    var height = this.height;
    for(var i = 0; i < 3; i++) {
      letter = i + 71;
      var canvas = document.createElement('canvas');
          canvas.width = width;
          canvas.height = height;
      var ctx = canvas.getContext('2d');
          ctx.drawImage(this, 0, 0, width, height);
          ctx.textAlign = 'center';
          ctx.font = 'bold 10px sans-serif';
          ctx.fillStyle = '#ffffff';
          ctx.fillText(String.fromCharCode(letter), 9.5, height / 2);
      points[i] = new BMap.Point(parseFloat('116.' + (i*3+1).toString()), 23.4);
      icons[i] = new BMap.Icon(canvas.toDataURL(), size1, {anchor: size2});
      markers[i] = new BMap.Marker(points[i], {icon: icons[i]});
      map.addOverlay(markers[i]);
    }
  }
  image.src = 'http://7fv9cr.com1.z0.glb.clouddn.com/marker.png';
</script>

通过七牛 API

鄙人既然使用七牛做图床,那么可以采用七牛图片处理的相关 API[5] 处理图片文件。

图片水印

使用七牛 API 的文字水印[6],可以存储单个标注的图片即可轻松变换出无数的图片,例如:

<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>
<div id="map"></div>
<script type="text/javascript">
  var map = new BMap.Map('map');
  var size1 = new BMap.Size(23, 25);
  var size2 = new BMap.Size(11.5, 25);
  map.centerAndZoom(new BMap.Point(116.4, 23.4), 10);
  var letter;
      points = [],
      icons = [],
      markers = [];
  for (var i = 0; i < 3; i++){
    letter = i + 74;
    points[i] = new BMap.Point(parseFloat('116.' + (i*3+1).toString()), 23.4);
    icons[i] = new BMap.Icon('http://7fv9cr.com1.z0.glb.clouddn.com/marker.png?watermark/2/fill/d2hpdGU=/dx/8/dy/8/text/' + btoa(String.fromCharCode(letter)), size1, {anchor: size2});
    markers[i] = new BMap.Marker(points[i], {icon: icons[i]});
    map.addOverlay(markers[i]);
  }
</script>

裁剪图片

既然七牛也支持裁切图片[7],那么也可以跟 CSS Image Sprites 般的处理,只不过是在图片本身做处理,而不是在展示图片时处理,如下:

<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>
<div id="map"></div>
<script type="text/javascript">
  var map = new BMap.Map('map');
  var size1 = new BMap.Size(23, 25);
  var size2 = new BMap.Size(11.5, 25);
  map.centerAndZoom(new BMap.Point(116.4, 23.4), 10);
  var points = [],
      icons = [],
      markers = [];
  for (var i = 0; i < 3; i++){
    points[i] = new BMap.Point(parseFloat('116.' + (i*3+1).toString()), 23.4);
    icons[i] = new BMap.Icon('http://7fv9cr.com1.z0.glb.clouddn.com/markers.png?imageMogr2/crop/!23x25a0a' + i * 25, size1, {anchor: size2});
    markers[i] = new BMap.Marker(points[i], {icon: icons[i]});
    map.addOverlay(markers[i]);
  }
</script>

几种方式的对比

一个地图里面需要显示 N 个有不同文字修饰的地标,那么:

方式 图片数 IE8 支持
单张 N
imageOffset 1(大)
Canvas 1(小)
七牛水印 N
七牛裁剪 N
  • 最省资源的恐怕是 HTML5 Canvas 的方式加载,只是对 IE8 的支持不是很好。
  • 较省事的是七牛 API 的处理,不过水印文字需要用到 Base64 编码,鄙人采用 btoa()[8] 对文字进行编码,并不兼容 IE8。
  • 想要兼容 IE8 并省资源,那还是得尽量采用百度地图自身的方法来实现,不过或许哪天,IE 的兼容也可以抛一边了。

覆盖物素材

哦对了,若采用百度地图 API,我想采用他家的素材比较和谐,百度地图覆盖物的素材下面有一小部分。

http://api.map.baidu.com/img/markers.png

http://api.map.baidu.com/images/dest_markers.png

http://api.map.baidu.com/images/markers.png

http://api.map.baidu.com/images/markers_new.png

http://api.map.baidu.com/images/marker_red.png

http://api.map.baidu.com/images/marker_red_sprite.png

http://api.map.baidu.com/images/spotmkrs.png

http://api.map.baidu.com/images/stop_icon.png

http://api.map.baidu.com/images/trans_icons.png

以上域名换成 api0.map.bdimg.com 亦可

http://app.baidu.com/map/images/us_mk_icon.png

http://webmap0.map.bdstatic.com/wolfman/static/common/images/markers_new2_31a3944.png

参考资料

本文历史

  • 2015 年 10 月 08 日 完成初稿