地圖繪製初探——基於maptalks的2.5D地圖繪製

進行圖形可視化,不免會遇到地理數據的可視化需求。一般狀況下,直接使用echarts對配置項進行處理,就能夠知足大部分需求。固然,更加複雜的定製化需求,可能就須要藉助d三、Three.js等工具。若是對詳細的地圖背景有要求的話,又須要將圖形庫與leaflet、maptalks等地圖引擎相結合。
不過也許你的需求和我同樣,沒有那麼複雜的交互需求,但對顯示效果卻有一些想法。那麼就能夠嘗試閱讀本文,使用一種比較偷懶的方法,僅基於maptalks自己,來繪製可交互的僞3d地圖。
下面,以貴州省的僞3d地圖爲例,進行代碼的編寫和相應數據的簡單處理。
圖片描述
1.基本的地圖繪製
maptalks(maptalks的git)的官方範例寫得至關親切,咱們能夠從中找到全部繪製僞3d地圖須要的元素。
首先,從地圖底圖開始。(官方入門示例css

initMapTalk() {
  let map = new maptalks.Map('mapDom', {
    center: [121.345, 31.2088],
    zoom: 9,
    baseLayer: new maptalks.TileLayer('base', {
      urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
      subdomains: ['a','b','c','d'],
      attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
    })
  });
}

須要注意的是,除了maptalks.js之外,maptalks.css也是必須引入的。git

而後,咱們須要藉助maptalks.Polygon添加一些地圖區塊(Polygon示例)。雖然地圖看起來和長方體不太同樣,實際上這些區塊也不過是稍微複雜一些的點線集合而已。做爲一切繪製的基礎,咱們須要找一些GeoJson格式的數據(中國各省市級json世界主要國家json)。觀察GeoJson,其中,的coordinates屬性,就是地圖邊界的集合。須要注意的是,區域type包含Polygon和MultiPolygon兩類,和maptalks的多邊形函數相對應,在數組的層級上稍有區別。爲了減小數據選取的麻煩,這裏選擇使用MultiPolygon來進行繪製。github

drawPolygons(idx, coordinates, properties) {
    const polygon = new maptalks.MultiPolygon(coordinates, {
      symbol: {
        lineWidth: 1,
        lineColor: edgeColor,
        polygonFill: polygonColors[0],
        polygonOpacity: 0.5
      },
      properties: {
        id: properties.id,
        index: idx,
        properties: properties
      }
    })
    .on("mouseenter", function(e) {
      e.target.updateSymbol({
        polygonFill: polygonColors[1]
      });
    })
    .on("mouseout", function(e) {
      e.target.updateSymbol({
        polygonFill: polygonColors[0]
      });
    })
    this.polygons.push(polygon);
},
drawRegion() {
    const self = this
    $.getJSON("guizhou.json", "", function(mapData) {
      const features = mapData.features;
      features.forEach((g, i) => {
        const properties = g.properties;
        const coordinates = g.geometry.coordinates
        self.drawPolygons(i, coordinates, properties)
      });
      const polygonsLayer = new maptalks.VectorLayer(
        "vector-polygon",
        self.polygons,
      ).addTo(self.mapDom);
    })
},

到如今爲止,一切還只是2d的樣子。不過,maptalks容許咱們繪製3維的高度面(立體的線)。只須要引入一個altitude屬性,並在底圖上引入pitch屬性使視角稍稍偏移, 咱們的2.5d地圖就畫出來了。json

drawLimitLines(idx, coordinates, properties) {
  const outLine = new maptalks.MultiLineString(coordinates, {
    symbol: {
      lineColor: edgeColor,
      lineWidth: 1,
      textPlacement: "vertex"
    },
    properties: {
      altitude: altitude,
      index: idx,
      id: properties.id,
      properties: properties
    }
  });
  this.limitLines.push(outLine);
},
drawPolygons(idx, coordinates, properties) {
  const polygon = new maptalks.MultiPolygon(coordinates, {
    symbol: {
      lineWidth: 1,
      lineColor: edgeColor,
      polygonFill: polygonColors[0],
      polygonOpacity: 0.5
    },
    properties: {
      altitude: altitude,
      id: properties.id,
      index: idx,
      properties: properties
    }
  })
  .on("mouseenter", function(e) {
    e.target.updateSymbol({
      polygonFill: polygonColors[1]
    });
  })
  .on("mouseout", function(e) {
    e.target.updateSymbol({
      polygonFill: polygonColors[0]
    });
  })
  this.polygons.push(polygon);
},
drawRegion() {
  const self = this
  $.getJSON("guizhou.json", "", function(mapData) {
    const features = mapData.features;
    features.forEach((g, i) => {
      const properties = g.properties;
      const coordinates = g.geometry.coordinates
      self.drawPolygons(i, coordinates, properties)
      const pathCoordinates = g.geometry.type == "MultiPolygon" ? coordinates.map(d => { return d[0] }) : coordinates
      self.drawLimitLines(i, pathCoordinates, properties)
    });
    const polygonsLayer = new maptalks.VectorLayer(
      "vector-polygon",
      self.polygons,
      {
        enableAltitude: true
      }
    ).addTo(self.mapDom);
    const limitLinesLayer = new maptalks.VectorLayer(
      "vector-line",
      self.limitLines,
      {
        enableAltitude: true,
        drawAltitude: {
          polygonFill: edgeColor,
          polygonOpacity: 0.3,
          lineWidth: 0
        }
      }
    ).addTo(self.mapDom);
  })
},

2.數據和樣式處理
到這個時候,效果仍是不太使人滿意。縣市間的邊界太醜,有沒有什麼辦法把他去掉呢?很簡單,直接繪製地圖的外沿就好。不過,網上下載的貴州省邊界好像和如今帶有區縣劃分的精度不太同樣?那麼,就來本身處理一下吧。根據問答如何合併區域邊界,訪問在線的地圖數據處理網站http://mapshaper.org/,給每一個縣市取一個相同的別名,一番輸入輸出,咱們就獲得了貴州省的外邊界。segmentfault

drawBorderLines(coordinates, properties) {
    const outLine = new maptalks.MultiLineString(coordinates, {
      symbol: {
        lineColor: edgeColor,
        lineWidth: 1,
        textPlacement: "vertex"
      },
      properties: {
        altitude: altitude,
        id: properties.id,
        properties: properties
      }
    });
    this.limitLines.push(outLine);
},
drawWall() {
    const self = this
    $.getJSON("guizhou-border.json", "", function(borderMapData) {
      const borderFeatures = borderMapData.features[0]
      const properties = borderFeatures.properties;
      const pathCoordinates = borderFeatures.geometry.coordinates.map(d => { return d[0] })
      self.drawBorderLines(pathCoordinates, properties)
      const limitLinesLayer = new maptalks.VectorLayer(
        "vector-line",
        self.limitLines,
        {
          enableAltitude: true,
          drawAltitude: {
            polygonFill: edgeColor,
            polygonOpacity: 0.3,
            lineWidth: 0
          }
        }
      ).addTo(self.mapDom);
    })
}

固然,mapshaper的功效不止於此,簡直是區域數據處理的一大利器,很是值得探索。
另外一個使人不太滿意的是地圖的底圖。打開mapbox,找到Studio而後Start With Basic,一個全新的自配地圖的世界等待着你。這裏,就隨便先把英文的區縣名換成中文好了。
圖片描述
完成配置以後,點擊share,你會獲得一個連接。不過,在用他替換掉Map的urlTemplate以前,還要按照格式進行一下修整。
圖片描述
最後,就獲得了本文開頭所示的地圖。相關源碼數組

相關文章
相關標籤/搜索