三维地球旋转效果

代码语言:html

所属分类:三维

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Pirata+One&amp;display=block'>
<style>
  body {
  margin: 0;
  background-color: #f7f6f2;
  overflow: hidden;
}

.container {
  display: flex;
  justify-content: center;
  max-height: 100vmin;
  max-width: 100vmin;
  margin: 0 auto;
}

.globe {
  height: 100vmin;
  width: auto;
  cursor: -webkit-grab;
  cursor: grab;
}

.globe--dragging {
  cursor: -webkit-grabbing;
  cursor: grabbing;
}
</style>

</head>
<body translate="no">
<div class="container">
<canvas class="globe" width="1800" height="1600"></canvas>
</div>

<script>
      const markers = [{
  name: 'Uluru',
  lat: -25,
  long: 131 },

{
  name: 'Machu Picchu',
  lat: -13,
  long: -70 },

{
  name: 'Valley of the Kings',
  lat: 25,
  long: 32 },

{
  name: 'Stonehenge',
  lat: 51,
  long: -2 }];


const $ = {
  canvas: null,
  ctx: null,
  vCenter: 820,
  scroll: {
    lat: 0,
    long: 20 },

  markers: [],
  timing: {
    speed: 16,
    delta: 0,
    last: 0 },

  drag: {
    start: { x: 0, y: 0 },
    force: 0,
    prevX: 0,
    isDragging: false },

  colors: {
    pushPinBase: '#969799',
    pushPin: '#ed5c50',
    land: '#fac648', //'#ffc975',
    landShade: '#2c606e',
    ocean: '#2A7B96' },

  complexShapes: {
    // put complex shapes here
  } };


const lerp = (norm, min, max) => {
  return (max - min) * norm + min;
};

const norm = (value, min, max) => {
  return (value - min) / (max - min);
};

const map = (value, sourceMin, sourceMax, destMin, destMax) => {
  return lerp(norm(value, sourceMin, sourceMax), destMin, destMax);
};

const dragMove = e => {
  if ($.drag.isDragging) {
    let long = $.drag.start.long,
    clientX = e.targetTouches ? e.targetTouches[0].clientX : e.clientX,
    change = clientX - $.drag.start.x,
    prevChange = clientX - $.drag.prevX,
    canvasWidth = $.canvas.getBoundingClientRect().width;

    long += map(change, 0, canvasWidth, 0, 200);

    while (long < 0) {
      long += 360;
    }

    if (prevChange > 0 && $.drag.force < 0) {
      $.drag.force = 0;
    } else if (prevChange < 0 && $.drag.force > 0) {
      $.drag.force = 0;
    }

    $.drag.force += prevChange * (600 / canvasWidth);
    $.drag.prevX = clientX;
    $.scroll.long = Math.abs(long) % 360;
  }
};

const dragStart = e => {
  if (e.targetTouches) {
    e.preventDefault();
    $.drag.start = {
      x: e.targetTouches[0].clientX,
      y: e.targetTouches[0].clientY,
      long: $.scroll.long };

  } else {
    $.drag.start = {
      x: e.clientX,
      y: e.clientY,
      long: $.scroll.long };

  }
  $.timing.speed = 0;
  $.drag.isDragging = true;
  $.canvas.classList.add('globe--dragging');
};

const dragEnd = e => {
  if ($.drag.isDragging) {
    $.timing.speed = map($.drag.force, 0, 220, 0, 40);
    $.drag.isDragging = false;
    $.canvas.classList.remove('globe--dragging');
  }
};

const getRadius = latitude => {
  let yPart = Math.PI * 2,
  radius = 600,
  frame = map(latitude, 90, -90, 0, 1.65);

  return Math.max(Math.sin(yPart + frame) * radius, 0);
};

const latLongSphere = (lat, lon, radius) => {
  let x = 900,
  y = $.vCenter,
  z = 0;

  lon = -lon;
  let phi = (90 - lat) * (Math.PI / 180),
  teta = (lon + 180) * (Math.PI / 180);

  x -= -(radius * Math.sin(phi) * Math.cos(teta));
  y -= radius * Math.cos(phi);
  z = radius * Math.sin(phi) * Math.sin(teta);

  return {
    x, y, z };

};

const drawGlobe = (ctx, color) => {
  ctx.beginPath();
  ctx.arc(900, $.vCenter, 600, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
};

const getLandMassPaths = (name, radius, thickness) => {
  let landmassBasic = continents[name],
  landmass = null,
  first = true,
  rotated = false,
  paths = {
    ground: new Path2D(),
    top: new Path2D(),
    sections: [],
    isVisible: false },

  section = {
    ground: [],
    top: [] };


  // Complexify
  if ($.complexShapes[name]) {
    landmass = $.complexShapes[name];
  } else {
    landmass = complexify(landmassBasic, 1);
    $.complexShapes[name] = landmass;
  }

  for (let i = 0; i < landmass.length; i++) {
    let point = landmass[0],
    p = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius);

    if (p.z < 0) {
      landmass.splice(0, 0, landmass.pop());
      rotated = true;
    } else {
      break;
    }
  }

  let drawCurve = false,
  curveStart = null,
  sectionIsVisible = false;

  landmass.forEach(point => {
    let p = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius),
    p2 = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius + thickness);

    if (!sectionIsVisible && p.z > -200) {
      sectionIsVisible = true;
    }

    section.ground.push({
      x: p.x,
      y: p.y,
      z: p.z });

    section.top.push({
      x: p2.x,
      y: p2.y,
      z: p2.z });


    if (point.edge && !first) {
      if (sectionIsVisible) {
        paths.sections.push(Object.assign({}, section));
      }

      section = {
        ground: [{ x: p.x, y: p.y, z: p.z }],
        top: [{ x: p2.x, y: p2.y, z: p2.z }] };


      sectionIsVisible = false;
    }

    first = false;

    if (p.z > 0) {
      if (drawCurve) {
        drawCurve = false;
        closeCurve(paths.ground, curveStart, p, radius);
        closeCurve(paths.top, curveStart, p2, radius + thickness);
      } else {
        paths.ground.lineTo(p.x, p.y);
        paths.top.lineTo(p2.x, p2.y);
        paths.isVisible = true;
      }
    } else {
      // draw curve
      if (!drawCurve) {
        drawCurve = true;
        curveStart = {
          x: p.x,
          y: p.y,
          z: p.z };

      }
    }
  });

  // if the last point is in a curve
  if (drawCurve) {
    drawCurve = false;
    let point = landmass.slice(-1)[0],
    p = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius),
    p2 = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius + thickness);

    closeCurve(paths.ground, curveStart, p, radius);
    closeCurve(paths.top, curveStart, p2, radius + thickness);
  }

  let p = latLongSphere(landmass[0].lat + $.scroll.lat, landmass[0].long + $.scroll.long, radius),
  p2 = latLongSphere(landmass[0].lat + $.scroll.lat, landmass[0].long + $.scroll.long, radius + thickness);

  section.ground.push({
    x: p.x,
    y: p.y,
    z: p.z });

  section.top.push({
    x: p2.x,
    y: p2.y,
    z: p2.z });


  if (section) {
    paths.sections.push(Object.assign({}, section));
  }

  return paths;
};

const closeCurve = (path, curveStart, p, radius) => {
  // draw curve from curveStart på p
  let a1 = getAngle({ x: 900, y: $.vCenter }, curveStart),
  a2 = getAngle({ x: 900, y: $.vCenter }, p),
  compare = a1 - a2,
  startAngle = a1 * (Math.PI / 180),
  endAngle = a2 * (Math.PI / 180);

  path.arc(900, $.vCenter, radius, startAngle, endAngle, compare > 0 && compare < 180);
};

const getCirclePoint = (angle, radius) => {
  let radian = angle / 180 * Math.PI;

  return {
    x: radius * Math.cos(radian) + 900,
    y: radius * Math.sin(radian) + 800 };

};

const getAngle = (p1, p2) => {
  let dy = p2.y - p1.y,
  dx = p2.x - p1.x,
  theta = Math.atan2(dy, dx);
  theta *= 180 / Math.PI;
  return theta;
};

const complexify = (landmass, level) => {
  let complex = [];

  for (let i = 0; i < landmass.length - 1; i++) {
    let p1 = landmass[i],
    p2 = landmass[i + 1],
    steps = Math.floor(distanceBetween(p1, p2) / level);

    p1.edge = true;
    complex.push(p1);

    if (steps > 0) {
      let s = Math.floor(100 / steps);

      for (let i = 1; i <= steps; i++) {
        let percentage = i * s;

        if (percentage <= 100) {
          let p = {
            lat: map(percentage, 0, 100, p1.lat, p2.lat),
            long: map(percentage, 0, 100, p1.long, p2.long) };


          complex.push(p);
        }
      }
    }
  }

  let last = landmass.pop();
  last.edge = true;
  complex.push(last);

  return complex;
};

const distanceBetween = (p1, p2) => {
  let a = p1.long - p2.long,
  b =.........完整代码请登录后点击上方下载按钮下载查看

网友评论0