基于threejs实现中国地图轮廓动画,简单聊聊2024年前端开发的现状和思考

  • @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-of

for (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 = projectionMatrixmodelViewMatrixvec4(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, // 设置透明

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

JavaScript

  • js的基本类型有哪些?引用类型有哪些?null和undefined的区别。

  • 如何判断一个变量是Array类型?如何判断一个变量是Number类型?(都不止一种)

  • Object是引用类型嘛?引用类型和基本类型有什么区别?哪个是存在堆哪一个是存在栈上面的?

  • JS常见的dom操作api

  • 解释一下事件冒泡和事件捕获

  • 事件委托(手写例子),事件冒泡和捕获,如何阻止冒泡?如何组织默认事件?

  • 对闭包的理解?什么时候构成闭包?闭包的实现方法?闭包的优缺点?

  • this有哪些使用场景?跟C,Java中的this有什么区别?如何改变this的值?

  • call,apply,bind

  • 显示原型和隐式原型,手绘原型链,原型链是什么?为什么要有原型链

  • 创建对象的多种方式

  • 实现继承的多种方式和优缺点

  • new 一个对象具体做了什么

  • 手写Ajax,XMLHttpRequest

  • 变量提升

  • 举例说明一个匿名函数的典型用例

  • 指出JS的宿主对象和原生对象的区别,为什么扩展JS内置对象不是好的做法?有哪些内置对象和内置函数?

  • attribute和property的区别

  • document load和document DOMContentLoaded两个事件的区别

  • JS代码调试

  • CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

d

  • 显示原型和隐式原型,手绘原型链,原型链是什么?为什么要有原型链

  • 创建对象的多种方式

  • 实现继承的多种方式和优缺点

  • new 一个对象具体做了什么

  • 手写Ajax,XMLHttpRequest

  • 变量提升

  • 举例说明一个匿名函数的典型用例

  • 指出JS的宿主对象和原生对象的区别,为什么扩展JS内置对象不是好的做法?有哪些内置对象和内置函数?

  • attribute和property的区别

  • document load和document DOMContentLoaded两个事件的区别

  • JS代码调试

  • CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  • 28
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值