用Ycc库,绘制一个中国地图来玩

上篇文章我们知道了怎么去绘制一个多边形,既然有了多边形,那么这篇文章就教大家使用来绘制一个中国地图。

基础知识-GeoJSON

在绘制之前,我们必须了解标准的地图地理位置json文件。

下面是一个示例:

{ "type": "FeatureCollection",
   "features": [
   { "type": "Feature",
      "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
      "properties": {"prop0": "value0"}
   },
   { "type": "Feature",
      "geometry": {
         "type": "LineString",
         "coordinates": [
            [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
         ]
      },
      "properties": {
         "prop0": "value0",
         "prop1": 0.0
      }
   },
   { "type": "Feature",
      "geometry": {
         "type": "Polygon",
         "coordinates": [
            [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
               [100.0, 1.0], [100.0, 0.0] ]
         ]
      },
      "properties": {
         "prop0": "value0",
         "prop1": {"this": "that"}
      }
   }
]
}

简单的说,GeoJSON文件通过type字段定义了几种地图相关的图形:"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon",    "MultiPolygon",   "GeometryCollection", "Feature", "FeatureCollection"。

对于常见的地图来说,最常用的类型就是Polygon(多边形)和MultiPolygon(镂空多边形),这篇文章也只会用到这两类图形来绘制。

关于GeoJSON文件中各个字段更详细的含义,可以参考网上的其他文章,比如这篇译文:https://www.oschina.net/translate/geojson-spec

只要对文件有个大致的了解,我们就可以进行下一步的绘制了。

使用Ycc绘制地图

在Ycc框架中,封装了一个多边形类Ycc.UI.Polygon,它的绘制函数很简单:

Ycc.UI.Polygon.prototype.render = function (ctx) {
   var self = this;
   ctx = ctx || self.ctx;
   if(!self.ctx){
      console.error("[Ycc error]:","ctx is null !");
      return;
   }
   // 多边形的顶点坐标数组
   var coordinates = this.coordinates;
   // 绘制的起点
   var start = coordinates[0];
      
   ctx.save();
   
   ctx.fillStyle = this.fillStyle;
   ctx.strokeStyle = this.strokeStyle;
   
   ctx.beginPath();
   ctx.moveTo(start.x,start.y);
   for(var i=0;i<this.coordinates.length-1;i++){
      var dot = this.coordinates[i];
      ctx.lineTo(dot.x,dot.y);
   }
   ctx.closePath();
   this.fill?ctx.fill():ctx.stroke();
   ctx.restore();
   
};

上面代码没什么特别的地方,就是上一篇文章介绍的绘制多边形的方法,只不过加入了颜色、是否填充、多边形坐标点数组等参数。

注意:在我们的GeoJSON文件中也有一个coordinates参数,它们是否一样呢?

事实上它们就是一样的,只不过在GeoJSON文件中使用数组的方式[x,y,z]这种方式表示x,y,z,而在Ycc框架中采用对象的方式{x,y,z}表示,差别仅此而已。

有了这个认识,我们只需要转换一下坐标就可以直接使用Polygon类进行绘制了。

代码量也不是很大,这里直接贴出来

var canvas = document.createElement("canvas");
canvas.width = 350;
canvas.height = 250;
document.getElementById("canvas").appendChild(canvas);

// 地图的偏移量
var offsetX = 70; // 临界值为 73.4766
var offsetY = 60; // 临界值为 53.5693
// 缩放倍数
var scale=5;

var ycc = new Ycc();
ycc.bindCanvas(canvas);
// 新建图层
var layer = ycc.layerManager.newLayer({enableEventManager:true});

ycc.ajax.get('./china.json',function (data) {
   data = JSON.parse(data);
   data.features.forEach(function (item) {
      // 河北等省为MultiPolygon,取第一个多边形直接绘制
      var provinceDots = item.geometry.type==="MultiPolygon"?item.geometry.coordinates[0][0]:item.geometry.coordinates[0];
      var dots = provinceDots.map(function (dot) {
         //x坐标去除偏移量,y坐标加上偏移量,并做镜像处理
         return new Ycc.Math.Dot((dot[0]-offsetX)*scale,(offsetY-dot[1])*scale);
      });
      var polygon = new Ycc.UI.Polygon({
         coordinates:dots,
         fill:false,
         fillStyle:"rgb(0,88,160)",
         noneZeroMode:2,
         userData:{area:item},
         strokeStyle:"rgb(0,88,160)",
         ontap:onEvent,
         onmousemove:onEvent,
      });
      layer.addUI(polygon);
      ycc.layerManager.reRenderAllLayerToStage();

      // 事件处理:填充选中的省份
      function onEvent(e) {
         this.belongTo.uiList.forEach(function (t) {
            t.fill=false;
         });
         this.fill=true;
         ycc.layerManager.reRenderAllLayerToStage();
         document.getElementById('area').innerHTML=this.userData.area.properties.name;

      }
   });
});

上面代码中的两个参数需要说明一下。

1、偏移量:

由于地图的坐标都是用经纬度来表示的,如果没有偏移量直接绘制,是不会出现在我们画面左上角的。这个临界值,实质就是地图经纬度的临界值。

2、缩放比例:

原因也一样,由于地图的坐标都是用经纬度来表示的,与我们实际像素坐标是有差别的,如果直接绘制,地图会非常小。

示例与总结

地图的绘制其实不算很难,难的是地图各个坐标数据的采集、更新、维护。

本例的区域地图相对来说是很简单的地图,更新维护只需要更新区域的坐标点。像百度高德这种成熟的地图,数据维护起来相当麻烦,区域信息、标记信息、道路信息、森林覆盖信息、河流信息等等,所以地图相关的一切都需要维护更新。

好在有开源的力量,帮我们维护更新区域信息和位置信息,https://github.com/modood/Administrative-divisions-of-China

文末惯例,贴上示例链接:https://www.lizhiqianduan.com/products/ycc/examples/map-of-china/

效果如下:

image.png

(本文完)



打赏作者

用Ycc库,绘制一个中国地图来玩》有1个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注