1595 字
8 分钟
贷款平台可视化数据大屏
3D 可视化数据大屏
一、项目概述与预览
在线预览(已部署)
技术栈:Vue 3(Vue CLI)、three.js、ECharts(局部图表)、axios(后端请求)、CSS2DRenderer(DOM 标签)、TWEEN.js(动画)。
二、实现流程(按时间/功能顺序)
-
准备资产
- 把省份边界 GeoJSON(
public/map.json或public/newMap.json)、ChinaLine.json、以及必要的图片资源放入public/。
- 把省份边界 GeoJSON(
-
基础框架
- 使用 Vue CLI 建立项目骨架,按功能拆分视图与模块:
src/views/map_china.vue作为地图主视图,src/initChinaMap负责 GeoJSON 加载与 three.js 模型构建,src/views/prism负责棱柱效果,src/components放图表组件。
- 使用 Vue CLI 建立项目骨架,按功能拆分视图与模块:
-
three.js 场景搭建
- 创建
THREE.Scene、PerspectiveCamera(或 Orthographic 根据需要)、WebGLRenderer、CSS2DRenderer(用于 DOM 标签),并集成到 Vue 生命周期(mounted/destroyed)。 - 使用一个
mapModel(THREE.Group)作为地图根节点,所有省份网格、光效、粒子、棱柱、标签都挂在其下,方便统一管理与重加载。
- 创建
-
地图构建(GeoJSON -> Three.js)
- 解析 GeoJSON 的
features,对每个 feature 通过投影(或直接坐标转换)构造THREE.Shape->ShapeGeometry->Mesh,使用MeshStandardMaterial或MeshPhongMaterial。 - 将每个省份的
properties.name绑定到对应的mesh.userData.name或object.parent.name,并存储userData.center(省的质心)用于放置标签/棱柱。 - 将所有省份 mesh 加入
mapModel,然后把mapModel加到主场景。
- 解析 GeoJSON 的
-
后端数据接入与省级聚合
- 可用两种方式:
a) 后端直接提供按省聚合的接口(推荐):例如
GET /stats/province-overview返回每个省的指标(用户数、申请数、贷款均值、信用均值、通过率等)。 b) 后端只提供原始用户/申请数据,前端并行拉取并合并(次优):调用/get-allUser、/allApplication、/get-creditScore等,然后通过city -> province的映射函数(src/utils/geoMatch.js与src/utils/cityToProvince.js)把 city 字段解析为省名并聚合。 - 实现要点:前端方法要做并发控制(例如 mapLimit)避免大量阻塞请求;但长期看应由后端做聚合以节省前端延迟与流量。
- 可用两种方式:
a) 后端直接提供按省聚合的接口(推荐):例如
-
可视化映射
- 颜色映射(Heatmap):根据某个指标(如人均贷款金额)计算每个省的归一化值,使用线性插值在蓝色/红色之间取色,并把颜色应用到省份材质或棱柱颜色。
- 棱柱(Prism):在省会/省中心位置放置
THREE.CylinderGeometry/BoxGeometry(或自定义棱柱),高度按值映射到一个区间(例如 3 到 40),顶部放 CSS2D 标签显示数值并带单位。 - 粒子与波纹效果:利用
THREE.Points(带 BufferGeometry)或在材质上做渐变纹理;波纹可用 Shader 或在顶层添加Ringmesh 并逐帧缩放透明度来模拟。
-
交互与弹窗
- 鼠标拾取(raycaster):在 click 事件里做
raycaster.intersectObjects(mapModel.children, true)找到省份 mesh,读取mesh.userData.name或feature.properties.name,然后从provinceStats中取指标并填充 DOM 弹窗(使用 CSS2DRenderer 或普通 Vue 弹窗)。 - 保护 HMR:在热重载或重复初始化场景时,使用
mapModel.userData.__loaded、ensureAdd()等 guard 避免重复添加模型或重复绑定事件,防止内存泄露与视觉异常。
- 鼠标拾取(raycaster):在 click 事件里做
-
性能与容错
- GeoJSON 较大时(如包含很多 detail 的 map.json),构建成本高,考虑:
- 压缩 GeoJSON(去除不必要的属性/精度)。
- 懒加载细节图层(在缩放进入时再加载城市级别)。
- 把大的静态资源放 CDN 或启用压缩/缓存(gzip、http cache headers)。
- 数据层面:若后端不提供按省聚合,请移交后端增加接口,避免前端发出成千上万次请求。
- GeoJSON 较大时(如包含很多 detail 的 map.json),构建成本高,考虑:
三、实现要点总结
- 以
mapModel作为地图根对象,便于 add/remove、热重载、安全判断(__loaded)。 - 省级匹配(city -> province)是数据正确性的关键:优先匹配省级词条,回退到 city->province 映射表,最后归为 unknown 并人工核查。
- Prism 的高度与颜色应基于归一化值(对数或线性),防止极端值压缩其他数据的可视差异。
- 事件绑定要具名并防止重复(绑定前检查标志),尤其在使用 HMR 的开发环境中。
- 把后端聚合放在服务器(REST 接口)是最佳实践,能显著降低前端请求量与延迟。
四、three.js 关键技术细节与实现说明
-
场景与渲染器
- 使用
THREE.WebGLRenderer渲染 3D 内容。为 DOM 标签使用THREE.CSS2DRenderer,并在每帧同步其位置(labelRenderer.render(scene, camera))。 - 在移动设备或低性能设备上考虑降低像素比:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))。
- 使用
-
投影与坐标转换
- GeoJSON 通常为经纬度,需要将(lon, lat)转换为二维屏幕坐标或三维地表坐标。常用做法:把经纬度转换为墨卡托或平面投影后缩放映射到场景坐标系。也可在
public里准备每个省的userData.center作为已转换的三维坐标(减少重复计算)。
- GeoJSON 通常为经纬度,需要将(lon, lat)转换为二维屏幕坐标或三维地表坐标。常用做法:把经纬度转换为墨卡托或平面投影后缩放映射到场景坐标系。也可在
-
Geometry 构建
- 解析
feature.geometry.coordinates,构造THREE.Shape,然后new THREE.ShapeGeometry(shape)得到网格。对带孔(holes)的多边形需先处理 holes。 - 使用 BufferGeometry 可以显著提高性能(使用
THREE.BufferGeometry并尽量减少 draw calls)。
- 解析
-
材质与灯光
- 选择
MeshStandardMaterial或MeshPhongMaterial来获得更好的高光/漫反射效果。对大型地图,尽量重用材质实例或基于InstancedMesh来减少开销。 - 添加环境光
AmbientLight+ 方向光DirectionalLight。如果需要阴影,注意阴影会额外影响性能。
- 选择
-
Label(文字)与 DOM 结合
- CSS2DRenderer 用于在 3D 场景上固定 DOM 标签(例如省名/数值),文本样式由 CSS 控制,方便响应式与交互。
- 当标签很多时,考虑只显示 top N 或在缩放级别控制显示。
-
动画与过渡
- 使用
TWEEN.js或gsap做平滑过渡(例如 prism 高度变化、弹窗淡入、右侧面板淡入)。 - 在渲染循环里以
requestAnimationFrame更新动画并渲染两个 renderer(WebGL 与 CSS2D)。
- 使用
-
效果(Prism/Particles/Ripple)实现技巧
- Prism:可以用
THREE.CylinderGeometry或BoxGeometry,并通过mesh.scale.y或调整几何体的高度来表示数值。 - Particles:用
THREE.BufferGeometry+THREE.PointsMaterial,使用顶点属性(position、size、color)并在 shader 里做额外效果。 - Ripple:用多层
RingGeometry,在每帧按比例缩放并降低透明度;或写一个简单的 shader 根据时间生成扩散波纹。
- Prism:可以用
-
性能优化(要点)
- 合并静态 geometry(例如把多个小标注合并成一个
BufferGeometry)。 - 对重复使用的对象使用
InstancedMesh。 - 使用 LOD(Level of Detail)分层渲染,缩放时切换到更少 detail 的模型。
- 对大的静态 JSON(如 ChinaLine.json、map.json)使用 gzip、CDN 或按需加载。
- 合并静态 geometry(例如把多个小标注合并成一个
参考链接与文档
- three.js 文档: https://threejs.org/docs/
- Vue CLI 部署文档: https://cli.vuejs.org/guide/deployment.html
- 浏览器兼容性数据更新: https://github.com/browserslist/update-db
贷款平台可视化数据大屏
https://blog.tonks.top/posts/dashboard/dash/ 部分信息可能已经过时