背景


目前项目的中国地图是echarts画的,现在这想再次基础上增加一个中国地图描边动画。

分析


因为echart 使用geo 坐标画上去的,我们可以根绝中国地图坐标画点,然后定时去移动这些点。

这里使用threejs 的点材质去帧动画移动。

geojson版本


threejs 基础场景不过多介绍,具体看代码,只写下核心部分。

步骤:

  1. 中国地图轮廓geojson 获取点坐标。(百度和阿里都有提供,可以自己搜很多。)
  2. 使用卡墨托投影方法,将经纬坐标转成平面
  3. 根绝点轮廓图采样出亮点
  4. 控制亮点亮度和移动

核心代码:

import {BufferGeometry,Object3D,FileLoader,BufferAttribute,ShaderMaterial,Color,Points,LineBasicMaterial,Line,Vector3,ColorRepresentation
} from "three";
import * as d3 from "d3-geo";
import coordinates from "./data/china";const projection = d3.geoMercator().center([116.412318, 39.909843]).translate([0, 0]);const linePinots:any[] = [];const countryLine = (tintColor:ColorRepresentation,outLineColor?:ColorRepresentation)=>{let positions:Float32Array;let opacitys:Float32Array;const opacityGeometry = new BufferGeometry();// 中国边界const chinaLines = new Object3D();// 点数据coordinates.forEach((coordinate:any) => {// coordinate 多边形数据coordinate.forEach((rows:any) => {const line = lineDraw(rows, outLineColor ?? '0xffffff');chinaLines.add(line);});});positions = new Float32Array(linePinots.flat(1));// 设置顶点opacityGeometry.setAttribute("position", new BufferAttribute(positions, 3));// 设置 粒子透明度为 0opacitys = new Float32Array(positions.length).map(() => 0);opacityGeometry.setAttribute("aOpacity", new BufferAttribute(opacitys, 1));// 控制 颜色和粒子大小const params = {pointSize: 2.0,pointColor: tintColor}const vertexShader = `attribute float aOpacity;uniform float uSize;varying float vOpacity;void main(){gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);gl_PointSize = uSize;vOpacity=aOpacity;}`const fragmentShader = `varying float vOpacity;uniform vec3 uColor;float invert(float n){return 1.-n;}void main(){if(vOpacity <=0.2){discard;}vec2 uv=vec2(gl_PointCoord.x,invert(gl_PointCoord.y));vec2 cUv=2.*uv-1.;vec4 color=vec4(1./length(cUv));color*=vOpacity;color.rgb*=uColor;gl_FragColor=color;}`const material = new ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,transparent: true, // 设置透明uniforms: {uSize: {value: params.pointSize},uColor: {value: new Color(params.pointColor)}}})const opacityPoints = new Points(opacityGeometry, material)return {chinaLines,opacityPoints,opacitys,linePinots,opacityGeometry}
}// let indexBol = true
/*** 边框 图形绘制* @param polygon 多边形 点数组* @param color 材质颜色* */
function lineDraw(polygon:any, color:ColorRepresentation) {const lineGeometry = new BufferGeometry();const pointsArray = new Array();polygon.forEach((row:any) => {const projectionRow = projection(row);if (!projectionRow) {return}let x = projectionRow[0]let y = projectionRow[1]// 创建三维点pointsArray.push(new Vector3(x, -y, 0));linePinots.push([x, -y, 0]);});// 放入多个点lineGeometry.setFromPoints(pointsArray);const lineMaterial = new LineBasicMaterial({color: color,});return new Line(lineGeometry, lineMaterial);
}export { countryLine };

全部代码: demo

遇到问题


geojson 版本我们需要将提供的经纬度坐标点转场成平面,各平台算法不同,投影失真情况不同,所以一些情况地图会失真无法重合。

我们刚才使用卡墨托投影转换,也会失真并且和echarts 地图轮廓对不上,所以想起其他方案。

我们利用svg路径来取点,UI提供的svg地图轮廓肯定是一致的。

SVG版本


设计思路:

  1. 加载svg 取所有的点
  2. 根绝点来创建threejs 亮光点
  3. 移动动画

核心代码:

import * as THREE from 'three';
import { initRender } from './render';
import { initScene } from './scene';
import { initCamera } from './camera';
// import { countryLine } from "./countryPolygon";
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js';export interface OutLineConfig {outline: boolean;outlineColor?: THREE.ColorRepresentation;tintColor: THREE.ColorRepresentation;speed: number;tintLength?: number;tintPointSize?: number;
}class MapOutline {private parentDom: HTMLElement;private width: number;private height: number;private renderer: THREE.WebGLRenderer;private scene: THREE.Scene;private camera: THREE.PerspectiveCamera;private opacitys: Float32Array | null = null;private linePinots: any[] = [];private opacityGeometry: THREE.BufferGeometry | null = null;private currentPos = 0;public constructor(containerId: string,public config: OutLineConfig = { outline: false, speed: 3, tintColor: '#008792' },) {this.parentDom = document.getElementById(containerId)!;this.width = this.parentDom.offsetWidth;this.height = this.parentDom.offsetHeight;this.renderer = initRender(this.width, this.height);this.parentDom?.appendChild(this.renderer.domElement);this.scene = initScene();this.camera = initCamera(this.width, this.height);}public render = () => {const loader = new SVGLoader();loader.load('./chinaLine.svg', (data) => {const paths = data.paths;const group = new THREE.Group();group.scale.multiplyScalar(0.34);group.position.x = -117;group.position.y = 90;group.scale.y *= -1;let allPoints: any[] = [];let pointsMesh: THREE.Points | null = null;// eslint-disable-next-line @typescript-eslint/prefer-for-offor (let i = 0; i < paths.length; i++) {const path = paths[i];const strokeColor = path.userData?.style.stroke;const material = new THREE.MeshBasicMaterial({color: 'red',opacity: path.userData?.style.strokeOpacity,transparent: path.userData?.style.strokeOpacity < 1,side: THREE.DoubleSide,depthWrite: false,});for (let j = 0, jl = path.subPaths.length; j < jl; j++) {const subPath = path.subPaths[j];let subPoints = subPath.getPoints();allPoints = allPoints.concat(subPoints);const geometry = SVGLoader.pointsToStroke(subPath.getPoints(), path.userData?.style);if (geometry) {const mesh = new THREE.Mesh(geometry, material);group.add(mesh);}}allPoints = allPoints.map((item) => {item.z = 0;return item;});for (const point of allPoints) {this.linePinots.push(point.x * 0.34 - 117, -point.y * 0.34 + 90, point.z);}this.opacityGeometry = new THREE.BufferGeometry();this.opacitys = new Float32Array(this.linePinots.length).map(() => 0);this.opacityGeometry.setAttribute('position', new THREE.Float32BufferAttribute(this.linePinots, 3));this.opacityGeometry.setAttribute('aOpacity', new THREE.BufferAttribute(this.opacitys, 1));// 控制 颜色和粒子大小const params = {pointSize: 5.0,pointColor: 'DarkOrange',};const vertexShader = `attribute float aOpacity;uniform float uSize;varying float vOpacity;void main(){gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);gl_PointSize = uSize;vOpacity=aOpacity;}`;const fragmentShader = `varying float vOpacity;uniform vec3 uColor;float invert(float n){return 1.-n;}void main(){if(vOpacity <=0.2){discard;}vec2 uv=vec2(gl_PointCoord.x,invert(gl_PointCoord.y));vec2 cUv=2.*uv-1.;vec4 color=vec4(1./length(cUv));color*=vOpacity;color.rgb*=uColor;gl_FragColor=color;}`;const material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,transparent: true, // 设置透明uniforms: {uSize: {value: params.pointSize,},uColor: {value: new THREE.Color(params.pointColor),},},});let opacityPoints = new THREE.Points(this.opacityGeometry, material);this.scene.add(opacityPoints);// this.scene.add(group);});this.animate();};private animate = () => {if (this.linePinots && this.opacitys) {// console.log(this.currentPos);if (this.currentPos > 1600) {this.currentPos = 0;}this.currentPos += this.config.speed;for (let i = 0; i < this.config.speed; i++) {this.opacitys[(this.currentPos - i) % this.linePinots.length] = 0;}for (let i = 0; i < 100; i++) {// console.log((this.currentPos + i) % this.linePinots.length);this.opacitys[(this.currentPos + i) % this.linePinots.length] = i / 50 > 2 ? 2 : i / 50;}if (this.opacityGeometry) {this.opacityGeometry.attributes.aOpacity.needsUpdate = true;}}this.renderer.render(this.scene, this.camera);requestAnimationFrame(this.animate);};
}export default MapOutline;

基于threejs实现中国地图轮廓动画相关推荐

  1. 【echarts 中国地图射线版本】vue实现中国地图航线动画效果,地图上添加散点效果【详细注释,通俗易懂】

    先上效果图 前置条件,必看 首先你需要安装echarts并引入 然后你需要下载china.json文件并注册引入,不然不生效 当然很多新手可能不知道china.json在哪里下载,因为官方已经没有了, ...

  2. echarts geo地图示例_基于Echarts的中国地图数据展示

    一.概述 实际项目中大概率会遇到很多需要进行数据展示的地方,如折现图,柱状图等,今天给大家介绍一个更加炫酷的中国地图大数据展示,结合echarts免费开源第三方插件,可以实现自己的定制样式,定制提示. ...

  3. echarts中国地图线性动画特效

    显示效果如图所示. 下载地址:https://download.csdn.net/download/weixin_38959210/11065196

  4. 一个让echarts中国地图包含省市轮廓的技巧

    背景知识及应用简介 本文主要介绍一个使用ECharts地图组件的取巧方法,该技巧源于实际需求中遇到的问题,一般没有该需求的话这个技巧也是用不到的.有前端基础和以及对ECharts有了解的人基本可以读懂 ...

  5. 中国地图FLASH和JS版本

    本文转载自: https://www.cnblogs.com/yetiea/archive/2012/02/15/2352632.html 作者:yetiea 转载请注明该声明. 最近要实现在web中 ...

  6. 请问怎么用python画一个轮廓图,,例如中国地图这种,注意是轮廓图,求大佬指点

    请问怎么用python画一个轮廓图,,例如中国地图这种,注意是轮廓图 例如这个:

  7. echarts中国地图线性流动动画js特效

    下载地址 使用百度的图表插件echarts.js制作的中国地图线性流动动画特效,可以在网页制作中实现总公司到分公司业务展示.物流.路线等网页设计内容. dd:

  8. 基于Threejs火焰烟雾动画功能代码

    利用Threejs进行三维可视化的应用项目开发,我们经常回遇到需要加入一些动画效果,粒子效果等.所以本片利用此详细的例子进行介绍在Threejs中如何使用. 1,首先需要对三维场景进行初始化 func ...

  9. BigData:基于python编程—根据中国各个城市地理坐标+人口、GDP大数据进行标记中国地图、热点图、动态图

    BigData:基于python编程-根据中国各个城市地理坐标+人口.GDP大数据进行标记中国地图.热点图.动态图 目录 输出结果 1.地理坐标图 2.GDP热点图 3.人口热力图 输出结果 1.地理 ...

  10. 基于VUE+TS中引用ECharts的中国地图和世界地图密度表

    (第一次写掘金,嗯也不知道写啥好.想了想,先来一份简单可口的老菜谱.虽然以前在其他平台也上过,换个地方说不准口味刚好呢哈哈哈哈-) 首先先附上官网 http://echarts.baidu.com/o ...

最新文章

  1. python与excel的应用-Python 3 读取和存储Excel数据(应用到接口测试)
  2. iphone静音键失灵_知否 | 为何大部分安卓机 都不学iPhone加入静音键?
  3. js - (初中级)常见笔试面试题
  4. c++ string 数组_PHP数组与字符串之间相互转换的方法
  5. 基于灰度世界、完美反射、动态阈值等图像自动白平衡算法的原理、实现及效果...
  6. 拓端tecdat|R语言分位数回归、GAM样条曲线、指数平滑和SARIMA对电力负荷时间序列预测
  7. TCP协议与IP协议
  8. 202206-2 寻宝!大冒险! CCF认证真题
  9. 关于后盾网yii框架的学习小结(1)--yii模块的安装
  10. UE5中创建VR项目并在瞬移的基础上增加圆盘位移操作
  11. STM32F103调试笔记(1)——microusb接入电脑后显示未知USB设备(代码43)
  12. Dockerfile构建Nginx镜像、镜像优化(多阶段构建,最小化镜像构建)
  13. Spring Cloud的基本认识和使用Spring Cloud的基本教程(山东数漫江湖)
  14. 有趣的海盗问题(完整版)
  15. Windows 2003 工作手册
  16. 使用CSS画一个萌萌的大白
  17. 2020 ACM杰出科学家名单出炉:叶杰平、崔鹏等26位华人学者上榜
  18. 6、python-mongodb获取数据存储到sql server
  19. 建造者模式——案例分析与代码演示
  20. 创建网易云歌单外链 Hexo

热门文章

  1. 数字逻辑电路—全减器的实现
  2. 计算机版本过低怎么办,浏览器版本过低嗡嗡叫怎么办_电脑显示浏览器版本过低嗡嗡叫如何处理-win7之家...
  3. Java实现图书馆管理系统(重构版,数据库存储数据)
  4. python调节电脑音量_python如何调节音量大小
  5. Handler机制原理----全解
  6. 大牛直播sdk简单播放端demo使用
  7. mac appium环境搭建
  8. 南昌大学计算机考试题,南昌大学计算机基础考试题库
  9. LINUX下汉化CodeBlocks
  10. QImage转yuv420