geojson-3d-renderer:从原理到实践,打造高性能3D地理可视化库

geojson-3d-renderer: 3D GeoJSON 可视化

geojson-3d-renderer 是我制作的一个功能强大的 3D GeoJSON 可视化库,兼容 Three.js、Vue.js + Three.js 和 TresJS 环境。提供 Vue 组件、钩子和工具函数,用于在 3D 空间中渲染 GeoJSON 数据,并支持自定义材质。

演示示例

中文文档

Github

  • 🗺️ 基于墨卡托投影的 3D GeoJSON 可视化
  • 🎨 可自定义材质的几何体生成(形状和线条)
  • ⚡ Vue 3 Composition API 支持
  • 📦 支持 Tree-shaking,轻量级
  • 🔧 TypeScript 支持

用法

安装

bash 复制代码
npm install geojson-3d-renderer
# 或
yarn add geojson-3d-renderer
# 或
pnpm add geojson-3d-renderer

Vue 组件

需要在 Vue.js、Three.js 和 TresJS 环境中使用

vue 复制代码
<template>
  <TresCanvas>
    <TresPerspectiveCamera :position="[0, 0, 50]" />
    <OrbitControls />
    <GeoJson
      url="https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json"
      :mercator-center="[104.0, 37.5]"
      :options="{
        mercatorScale: 30,
        extrudeDepth: 1,
        lineOffset: 0.01,
      }"
    />
  </TresCanvas>
</template>

<script setup>
import { TresCanvas, TresPerspectiveCamera } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { GeoJson } from 'geojson-3d-renderer'
</script>

Composition API

需要在 Vue.js、Three.js 环境中使用

vue 复制代码
<template>
  <TresCanvas>
    <TresPerspectiveCamera :position="[0, 0, 50]" />
    <OrbitControls />
    <TresGroup>
      <TresMesh v-if="shapeGeometry" :geometry="shapeGeometry">
        <TresMeshBasicMaterial color="#409EFF" />
      </TresMesh>
      <TresLineSegments v-if="lineGeometry" :geometry="lineGeometry">
        <TresLineBasicMaterial color="#000000" />
      </TresLineSegments>
    </TresGroup>
  </TresCanvas>
</template>

<script setup>
import {
  TresCanvas,
  TresPerspectiveCamera,
  TresGroup,
  TresMesh,
  TresLineSegments,
} from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { useGeojson } from 'geojson-3d-renderer'

const { mergedShapeGeometry: shapeGeometry, mergedLineGeometry: lineGeometry } = useGeojson(
  'https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json',
  [104.0, 37.5],
  {
    mercatorScale: 30,
    extrudeDepth: 1,
    lineOffset: 0.01,
  }
)
</script>

工具函数 (Utility Function)

需要在 Three.js 环境中使用

ts 复制代码
import { genGeojsonGeometry } from 'geojson-3d-renderer/utils'

const { mergedShapeGeometry, mergedLineGeometry } = await genGeojsonGeometry(
  'https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json',
  [104.0, 37.5],
  {
    mercatorScale: 30,
    extrudeDepth: 1,
    lineOffset: 0.01,
  }
)

原理解析

整体架构设计

genGeojsonGeometry.ts 是整个库的核心模块,负责将 GeoJSON 数据转换为 Three.js 可渲染的几何体。其整体架构设计遵循了职责分离原则:

text 复制代码
// 模块职责划分
genGeojsonGeometry()
├── 数据加载 (d3.json)
├── 投影转换 (d3.geoMercator)
├── 几何体生成
│   ├── 填充几何体 (ExtrudeGeometry)
│   └── 线段几何体 (BufferGeometry)
└── 几何体合并 (BufferGeometryUtils)

下面主要介绍几何体的生成与合并

Three.js 几何体构建

填充几何体生成

填充几何体使用 Three.js 的 ExtrudeGeometry 实现:

ts 复制代码
const createGeometryFromPolygon = (polygon: number[][], projection: GeoProjection) => {
  const shape = new Shape()
  let firstPoint = true

  polygon.forEach((coord) => {
    const [x, y] = projection(coord as [number, number]) || [0, 0]
    if (firstPoint) {
      shape.moveTo(x, -y)  // 注意:Y 坐标取反,适应 Three.js 坐标系
      firstPoint = false
    } else {
      shape.lineTo(x, -y)
    }
  })

  const extrudeSettings = {
    depth: mergedOptions.extrudeDepth,  // 挤出深度
    bevelEnabled: false,               // 禁用斜面
  }

  return new ExtrudeGeometry(shape, extrudeSettings)
}

线段几何体生成

线段几何体使用 Three.js 的 BufferGeometry 实现:

ts 复制代码
const createLineSegmentsFromPolygon = (polygon: number[][], projection: GeoProjection) => {
  const n = polygon.length
  if (n < 2) return new BufferGeometry()
  
  // 使用 TypedArray 优化性能
  const vertexCount = n * 2
  const positions = new Float32Array(vertexCount * 3)
  let ptr = 0
  
  for (let i = 0; i < n; i++) {
    const a = polygon[i] as [number, number]
    const b = polygon[(i + 1) % n] as [number, number]
    const [ax, ay] = projection(a) || [0, 0]
    const [bx, by] = projection(b) || [0, 0]
    
    // 线段起点
    positions[ptr++] = ax
    positions[ptr++] = -ay
    positions[ptr++] = lineZPosition  // Z 轴偏移

    // 线段终点  
    positions[ptr++] = bx
    positions[ptr++] = -by
    positions[ptr++] = lineZPosition
  }
  
  const lineGeometry = new BufferGeometry()
  lineGeometry.setAttribute('position', new Float32BufferAttribute(positions, 3))
  return lineGeometry
}

几何体合并优化

为了提高渲染性能,库使用 BufferGeometryUtils.mergeGeometries 进行几何体合并:

ts 复制代码
if (mergedOptions.needShapeGeometry) {
  mergedShapeGeometry = BufferGeometryUtils.mergeGeometries(shapeGeometryList)
  mergedShapeGeometry.computeBoundingSphere()
}

if (mergedOptions.needLineGeometry) {
  mergedLineGeometry = BufferGeometryUtils.mergeGeometries(lineGeometryList)
  mergedLineGeometry.computeBoundingSphere()
}

结束啦

这就是我做的一个将geojson渲染为3d的包啦

如果你有更好的方法或者建议,欢迎在下面留言,或者在 GitHub 提 issues

掰掰啦~~~

相关推荐
web小白成长日记5 小时前
企业级 Vue3 + Element Plus 主题定制架构:从“能用”到“好用”的进阶之路
前端·架构
APIshop6 小时前
Python 爬虫获取 item_get_web —— 淘宝商品 SKU、详情图、券后价全流程解析
前端·爬虫·python
风送雨6 小时前
FastMCP 2.0 服务端开发教学文档(下)
服务器·前端·网络·人工智能·python·ai
XTTX1106 小时前
Vue3+Cesium教程(36)--动态设置降雨效果
前端·javascript·vue.js
LYFlied7 小时前
WebGPU与浏览器边缘智能:开启去中心化AI新纪元
前端·人工智能·大模型·去中心化·区块链
Setsuna_F_Seiei7 小时前
2025 年度总结:人生重要阶段的一年
前端·程序员·年终总结
model20057 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
han_8 小时前
从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序
前端·javascript·面试
aPurpleBerry8 小时前
React 01 目录结构、tsx 语法
前端·react.js
jayaccc8 小时前
微前端架构实战全解析
前端·架构