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

掰掰啦~~~

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A4 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
honkun64 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19914 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
汉堡大王95274 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端