前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mapboxGL实现旋转的地球

mapboxGL实现旋转的地球

作者头像
lzugis
发布2022-09-21 10:45:36
1.2K0
发布2022-09-21 10:45:36
举报

概述

许久未更新,这一篇是凑数的,用最新的mapboxGL2.10的版本实现一个旋转的地球的效果。

实现效果

在这里插入图片描述
在这里插入图片描述

实现

为效果好一点,添加了一个canvas的星空动画,实现代码如下:

代码语言:javascript
复制
  class Star {
    constructor(canvas, gradientImage, maxStars = 100) {
      this.ctx = canvas.getContext('2d')
      this.gradientImage = gradientImage
      //星星移动的半径
      this.orbitRadius = this.random(this.maxOrbit(canvas.width, canvas.height));
      //星星大小,半径越小,星星也越小,即外面的星星会比较大
      this.radius = this.random(60, this.orbitRadius) / 6;
      //所有星星都是以屏幕的中心为圆心
      this.orbitX = canvas.width / 2;
      this.orbitY = canvas.height / 2;
      //利用正弦余弦算出真正的x、y位置
      this.timePassed = this.random(0, maxStars);
      //星星移动速度
      this.speed = this.random(this.orbitRadius) / 80000;
      //星星图像的透明度
      this.alpha = this.random(2, 10) / 10;
    }

    maxOrbit(x, y) {
      const max = Math.max(x, y), diameter = Math.round(Math.sqrt(max * max + max * max));
      //星星移动范围,值越大范围越小,
      return diameter / 2;
    }

    random(min, max) {
      if(arguments.length < 2) {
        max = min;
        min = 0;
      }
      if(min > max) {
        const hold = max;
        max = min;
        min = hold;
      }
      //返回min和max之间的一个随机值
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    draw() {
      const x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX,
        y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY,
        twinkle = this.random(10);
      if(twinkle === 1 && this.alpha > 0) {
        this.alpha -= 0.05;
      } else if(twinkle === 2 && this.alpha < 1) {
        this.alpha += 0.05;
      }
      this.globalAlpha = this.alpha;
      this.ctx.drawImage(this.gradientImage, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);
      this.timePassed += this.speed;
    }
  }

  class StarBackground {
    constructor(pDom) {
      this.pDom = pDom ? (typeof pDom === 'string' ? document.getElementById(pDom) : pDom) : document.body
      this._init()
      return Promise.resolve()
    }
    _init() {
      this.canvas = document.createElement('canvas')
      this.canvas.width = this.pDom.offsetWidth
      this.canvas.height = this.pDom.offsetHeight
      this.ctx = this.canvas.getContext('2d')
      this.pDom.appendChild(this.canvas)
      this.hue = 217 //色调色彩
      this.stars = [] //保存所有星星
      this.count = 0  //用于计算星星
      this.maxStars = 120; //星星数量
      this._creatGradientImage()
      //初始化所有星星
      for(let i = 0; i < this.maxStars; i++) {
        this.stars.push(new Star(this.canvas, this.gradientImage, this.maxStars))
      }
      this._animation()
    }
    _animation () {
      this.ctx.globalCompositeOperation = 'source-over';
      this.ctx.globalAlpha = 0.5; //尾巴
      this.ctx.fillStyle = 'hsla(' + this.hue + ', 64%, 6%, 2)';
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
      this.ctx.globalCompositeOperation = 'lighter';
      for(let i = 1, l = this.stars.length; i < l; i++) {
        this.stars[i].draw();
      }
      window.requestAnimationFrame(() => {
        this._animation()
      });
    }
    _creatGradientImage() {
      this.gradientImage = document.createElement('canvas')
      const ctx = this.gradientImage.getContext('2d');
      this.gradientImage.width = 100;
      this.gradientImage.height = 100;
      const half = this.gradientImage.width / 2
      const gradient = ctx.createRadialGradient(half, half, 0, half, half, half);
      gradient.addColorStop(0.025, '#fff');
      gradient.addColorStop(0.1, 'hsl(' + this.hue + ', 61%, 33%)');
      gradient.addColorStop(0.25, 'hsl(' + this.hue + ', 64%, 6%)');
      gradient.addColorStop(1, 'transparent');
      ctx.fillStyle = gradient;
      ctx.beginPath();
      ctx.arc(half, half, half, 0, Math.PI * 2);
      ctx.fill();
    }
  }

旋转的地球的实现比较简单,只需要改变lon的值即可,实现代码如下:

代码语言:javascript
复制
new StarBackground('map').then(addMap)

  function addMap() {
    const mapStyle = {
      "version": 8,
      "name": "Dark",
      "sources": {
        "earth-image": {
          type: 'image',
          url: 'img/map1.png',
          coordinates: [
            [-180, 85.051128780],
            [180, 85.051128780],
            [180, -85.051128780],
            [-180, -85.051128780]
          ]
        },
        "earth-cloud": {
          type: 'image',
          url: 'img/map2.png',
          coordinates: [
            [-180, 85.051128780],
            [180, 85.051128780],
            [180, -85.051128780],
            [-180, -85.051128780]
          ]
        },
        'province': {
          type: 'geojson',
          data: 'assets/china.geojson'
        }
      },
      "layers": [{
        'id': 'earth-image',
        'source': 'earth-image',
        'type': 'raster',
        'paint': {
          'raster-opacity': 1,
          'raster-fade-duration': 0
        }
      },{
        'id': 'earth-cloud',
        'source': 'earth-cloud',
        'type': 'raster',
        'paint': {
          'raster-opacity': 0.65,
          'raster-fade-duration': 0
        }
      },{
        'id': 'province-line',
        'source': 'province',
        "type": "line",
        "paint": {
          "line-color": "#ff0000",
          'line-width': 1,
          'line-opacity': 0.8
        }
      }]
    };
    const zoom = 1.2
    let center = [116.4, 39.9]
    var map = new mapboxgl.Map({
      container: 'map',
      maxZoom: zoom,
      minZoom: zoom,
      zoom: zoom,
      center: center,
      style: mapStyle,
      attributionControl: false,
      interactive: false,
      projection: 'globe'
    });
    let play = true, playFlag = 0
    map.on('load', () => {
      const ele = document.createElement('div');
      ele.setAttribute('class', 'my-marker');
      const option = {
        element: ele,
        anchor: 'center',
        offset: [0, 0]
      };
      new mapboxgl.Marker(option)
        .setLngLat([114.0259737,	22.54605355])
        .addTo(map);
      const animate = () => {
        let [x, y] = center
        x -= 0.5
        if(x === -180) x = 180
        center = [x, y]
        map.setCenter(center)
        playFlag = requestAnimationFrame(animate)
      }
      animate()
      document.getElementById('play').onclick = function () {
        play = !play
        play ?  animate() : cancelAnimationFrame(playFlag)
        this.src = play ? 'img/pause.png' : 'img/play.png'
      }
    })
  }

说明: 本文代码可移步mapboxgl-example获取。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 实现效果
  • 实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档