Three.js - 绘制中国地图

获取GeoJSON数据

  • GeoJSON是一种对各种地理数据结构进行编码的格式。本质就是一个JSON对象
{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [125.6, 10.1]
  },
  "properties": {
    "name": "Dinagat Islands"
  }
}
  • 主要关心geometry对象的值,geometry.type几何数据类型(一共有7种),geometry.coordinates数据(不同类型格式不同)。

绘制地图

基础代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>学习</title>
  </head>
  <body>
    <canvas id="c2d" class="c2d" width="1000" height="500"></canvas>
    <script type="module">
      import * as THREE from './file/three.js-dev/build/three.module.js'
      import { OrbitControls } from './file/three.js-dev/examples/jsm/controls/OrbitControls.js'

      const canvas = document.querySelector('#c2d')
      // 渲染器
      const renderer = new THREE.WebGLRenderer({ canvas })

      const fov = 40 // 视野范围
      const aspect = 2 // 相机默认值 画布的宽高比
      const near = 0.1 // 近平面
      const far = 10000 // 远平面
      // 透视投影相机
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
      camera.position.set(0, 0, 300)
      camera.lookAt(0, 0, 0)
      // 控制相机
      const controls = new OrbitControls(camera, canvas)
      controls.update()

      // 场景
      const scene = new THREE.Scene()

      {
        const color = 0xffffff
        const intensity = 1
        // 环境光
        const light = new THREE.AmbientLight(color, intensity)
        // 加入场景
        scene.add(light)
      }

      // 渲染
      function render() {
        renderer.render(scene, camera)
        requestAnimationFrame(render)
      }
      requestAnimationFrame(render)
    </script>
  </body>
</html>

加载几何信息数据

  • THREE.FileLoader() 用于加载任何没有对应加载器的文件类型。
      const loader = new THREE.FileLoader()
      loader.load('./file/100000_full.json', (data) => {
        const jsondata = JSON.parse(data)
        console.log('jsondata', jsondata)
      })

image.png

  • 每个省的数据是分开的,会多次创建图形。创建图形公用方法。
  • .Shape()形状的使用,可以查看上一节
      /**
       * 立体几何图形
       * @param polygon 多边形 点数组
       * @param color 材质颜色
       * */
      function drawExtrudeMesh(polygon, color) {
        const shape = new THREE.Shape()
        polygon.forEach((row, i) => {
          const [x, y] = [row[0], row[1]]

          if (i === 0) {
            shape.moveTo(x, y)
          }
          shape.lineTo(x, y)
        })

        // 拉伸
        const geometry = new THREE.ExtrudeGeometry(shape, {
          depth: 10,
          bevelEnabled: false
        })
        const material = new THREE.MeshBasicMaterial({
          color: color,
          transparent: true,
          opacity: 0.5
        })
        return new THREE.Mesh(geometry, material)
      }
  • 添加坐标辅助,更好的绘制图形。
      // 坐标轴 辅助
      var axes = new THREE.AxisHelper(700)
      scene.add(axes)
  • 解析全球几何信息,对每一个多边形绘制图形。
      const map = new THREE.Object3D()
      // 解析数据
      function operationData(jsondata) {
        // 全国信息
        const features = jsondata.features

        features.forEach((feature) => {
          // 单个省份
          const province = new THREE.Object3D()
          // 地址
          province.properties = feature.properties.name
          const coordinates = feature.geometry.coordinates
          const color = 'yellow'

          if (feature.geometry.type === 'MultiPolygon') {
            // 多个,多边形
            coordinates.forEach((coordinate) => {
              // coordinate 多边形数据
              coordinate.forEach((rows) => {
                const mesh = drawExtrudeMesh(rows, color)
                province.add(mesh)
              })
            })
          }

          if (feature.geometry.type === 'Polygon') {
            // 多边形
            coordinates.forEach((coordinate) => {
              const mesh = drawExtrudeMesh(coordinate, color)
              province.add(mesh)
            })
          }
          map.add(province)
        })
        scene.add(map)
      }

1.gif

  • 一个简单的中国地图就绘制好了,可以看见绘制点不是原点且省份之间边界不明显。

优化地图

  • 引入d3.geoMercator()经纬度坐标转换。使用第三方控件帮助我们计算坐标转换。
...
<script src="https://d3js.org/d3.v5.min.js"></script>
...

// 修改北京的坐标为中心
const projection = d3.geoMercator().center([116.412318, 39.909843]).translate([0, 0])
...
  • 修改drawExtrudeMesh()函数,坐标转换部分。
    polygon.forEach((row, i) => {
      const [x, y] = projection(row)
      if (i === 0) {
        shape.moveTo(x, -y)
      }
      shape.lineTo(x, -y)
    })

image.png

  • 添加省份边界线。和图形绘制一样创建公用方法。
      /**
       * 边框 图形绘制
       * @param polygon 多边形 点数组
       * @param color 材质颜色
       * */
      function lineDraw(polygon, color) {
        const lineGeometry = new THREE.BufferGeometry()
        const pointsArray = new Array()
        polygon.forEach((row) => {
          const [x, y] = projection(row)
          // 创建三维点
          pointsArray.push(new THREE.Vector3(x, -y, 9))
        })
        // 放入多个点
        lineGeometry.setFromPoints(pointsArray)

        const lineMaterial = new THREE.LineBasicMaterial({
          color: color
        })
        return new THREE.Line(lineGeometry, lineMaterial)
      }
  • 修改.operationData()方法,在绘制立体图像(drawExtrudeMesh(rows, color))的后面绘制边框图形。
    // coordinate 多边形数据
    coordinate.forEach((rows) => {
        const mesh = drawExtrudeMesh(rows, color)
        const line = lineDraw(rows, color)
        province.add(line)
        province.add(mesh)
    })

1.gif

  • 现在就好看很多了。

其他操作

  • 在数据操作方法中,我们还可以根据省份名字做一些特殊操作。比如修改省份颜色等。
  // const color = 'yellow'
  const color = ['重庆市', '上海市'].includes(feature.properties.name) ? 'blue' : 'yellow'

image.png

  • 一个可视化地图还有很多功能,比如绘制飞线图、选中省市高亮等。后面在进行了解。
  • 代码地址
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值