zoukankan      html  css  js  c++  java
  • ThreeJS 地球添加迁徙图

    环境

    • ThreeJS 107版本
    • three.min.js
    • OrbitControls.js
    • THREE.MeshLine.js

    说明

    迁徙图参考了网上大大们的方法做的,但是效果不太理想,迁徙飞行效果原理是生成50个小球循环飞,数据量一大有点卡,需要优化。

    解决方案

    1. 创建球的过程参见"ThreeJS制作地球"

    2. 创建点位group,考虑后面会做删除功能,所以把所有的实体都以group组为单位添加,后续方便做删除

    // 标记点组合
    var marking = new THREE.Group();
    
    1. 根据数据,在地球上添加飞出、飞入的点位,并且绘制贝塞尔曲线
    var groupLines = new THREE.Group();
    for (var i = 0; i < _flyData.length; i++) {
    index = i;
    for (var j = 0; j < _flyData[i].length; j++) {
    var ballPosFrom, ballPosTo;
    
    // 创建标记点球体
    var ballFrom = new THREE.Mesh(new THREE.SphereGeometry(0.5, 30, 30), new THREE.MeshBasicMaterial({
    color: ballColors[index % 3]//'#1bb4b0'
    }));
    // 获取标记点坐标
    ballPosFrom = this.getPosition(getPositionByName(_flyData[i][j][0].name)[1][0] + 90, getPositionByName(_flyData[i][j][0].name)[1][1], 30);
    ballFrom.position.set(ballPosFrom.x, ballPosFrom.y, ballPosFrom.z);
    marking.add(ballFrom);
    
    // 创建标记点球体
    var ballTo = new THREE.Mesh(new THREE.SphereGeometry(0.5, 30, 30), new THREE.MeshBasicMaterial({
    color: ballColors[index % 3]//'#1bb4b0'
    }));
    // 获取标记点坐标
    ballPosTo = this.getPosition(getPositionByName(_flyData[i][j][1].name)[1][0] + 90, getPositionByName(_flyData[i][j][1].name)[1][1], 30);
    ballTo.position.set(ballPosTo.x, ballPosTo.y, ballPosTo.z);
    marking.add(ballTo);
    
    // 添加飞线
    var line = addLine(ballFrom.position, ballTo.position);//迁徙方向,第一个参数是起始方向
    groupLines.add(line.lineMesh);
    animateDots.push(line.curve.getPoints(150));
    }
    }
    scene.add(marking);
    scene.add(groupLines);
    
    1. 将经纬度转换成球上坐标
    //经纬度转球坐标
    this.getPosition = function (_longitude, _latitude, _radius) {
    var lg = THREE.Math.degToRad(_longitude);
    var lt = THREE.Math.degToRad(_latitude);
    var temp = _radius * Math.cos(lt);
    var x = temp * Math.sin(lg);
    var y = _radius * Math.sin(lt);
    var z = temp * Math.cos(lg);
    return {
    x: x,
    y: y,
    z: z
    }
    }
    
    1. 绘制贝塞尔曲线
    function animationLine() {
    aGroup.children.forEach(function (elem, index) {
    var _index = parseInt(index / 50);
    var index2 = index - 50 * _index;
    var _vIndex = 0;
    if (firstBool) {
    _vIndex = vIndex - index2 % 50 >= 0 ? vIndex - index2 % 50 : 0;
    } else {
    _vIndex = vIndex - index2 % 50 >= 0 ? vIndex - index2 % 50 : 150 + vIndex - index2;
    }
    var v = animateDots[_index][_vIndex];
    elem.position.set(v.x, v.y, v.z);
    })
    vIndex++;
    if (vIndex > 150) {
    vIndex = 0;
    }
    if (vIndex == 150 && firstBool) {
    firstBool = false;
    }
    requestAnimationFrame(animationLine);
    }
    // 计算球体上两个点的中点
    function getVCenter(v1, v2) {
    var v = v1.add(v2);
    return v.divideScalar(2);
    }
    // 计算球体两点向量固定长度的点
    function getLenVcetor(v1, v2, len) {
    var v1v2Len = v1.distanceTo(v2);
    return v1.lerp(v2, len / v1v2Len);
    }
    // 添加轨迹函数
    function addLine(v0, v3) {
    var angleRate = _style.angleRate ? _style.angleRate : 0.5;
    var angle = (v0.angleTo(v3) * 180) / Math.PI;
    var aLen = angle * angleRate * (1 - angle / (Math.PI * 90));
    var hLen = angle * angle * 1.2 * (1 - angle / (Math.PI * 90));
    var p0 = new THREE.Vector3(0, 0, 0);
    // 法线向量
    var rayLine = new THREE.Ray(p0, getVCenter(v0.clone(), v3.clone()));
    // 顶点坐标
    var vtop = rayLine.at(hLen / rayLine.at(1).distanceTo(p0));
    // 控制点坐标
    var v1 = getLenVcetor(v0.clone(), vtop, aLen);
    var v2 = getLenVcetor(v3.clone(), vtop, aLen);
    // 绘制贝塞尔曲线
    var curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
    var geometry = new THREE.Geometry();
    geometry.vertices = curve.getPoints(100);
    var line = new MeshLine();
    line.setGeometry(geometry);
    var material = new MeshLineMaterial({
    color: lineColors[index % 3],
    lineWidth: _style.lineWidth ? _style.lineWidth : 0.1,
    transparent: true,
    opacity: 1
    })
    return {
    curve: curve,
    lineMesh: new THREE.Mesh(line.geometry, material)
    }
    }
    
    1. 构造循环动画的小球
    // 线上滑动的小球
    var aGroup = new THREE.Group();
    for (var i = 0; i < animateDots.length; i++) {
    for (var j = 0; j < 50; j++) {
    var aGeo = new THREE.SphereGeometry(0.2, 10, 10);
    var aMaterial = new THREE.MeshBasicMaterial({
    color: lineColors[index % 3],//"rgb(27, 180, 176)",
    transparent: true,
    opacity: 1 - j * 0.02
    })
    var aMesh = new THREE.Mesh(aGeo, aMaterial);
    aGroup.add(aMesh);
    }
    }
    

    附上效果图

    迁徙图

  • 相关阅读:
    ABAP开发者上云的时候到了
    1074. 宇宙无敌加法器(20)
    1073. 多选题常见计分法(20)
    1072. 开学寄语(20)
    1071. 小赌怡情(15)
    1049. Counting Ones (30)
    1047. Student List for Course (25)
    1044. Shopping in Mars (25)
    1043. Is It a Binary Search Tree (25)
    1040. Longest Symmetric String (25)
  • 原文地址:https://www.cnblogs.com/giser-s/p/12928577.html
Copyright © 2011-2022 走看看