D3js畫三維地球

  • 利用d3js在前端繪製三維地球並能夠進行旋轉
  • 代碼如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<style>
body, html {
    font-family: arial;
}
.map {
    float: left;
    padding: 5px;
    border: solid 1px #eee;
    border-radius: 5px;
}
.graticule {
  fill: none;
  stroke: #777;
  stroke-width: .5px;
  stroke-opacity: .5;
  pointer-events: all;
}
.land {
  fill: none;
  stroke: #000;
  stroke-width: 1;
}
</style>
</head>

<body>
<div id="map" class="map"></div>
<script>

// https://stackoverflow.com/questions/43772975/drag-rotate-projection-in-d3-v4

  var width = 600,
      height = 600,
      scale = 200,
      origin = {
        x: 55,
        y: -40
      };
  var world;
// 選擇body、div確定繪製地球位置和寬高
  var svg = d3.select('body').select('#map').append('svg')
    .attr('width', width)
    .attr('height', height);

  var group = svg.append("g").datum({
    x: 0,
    y: 0
  });
// 定義投影座標系統
  var projection = d3.geoOrthographic()
    .scale(scale)
    .translate([width / 2, height / 2])
    .rotate([origin.x, origin.y])
    .center([0, 0])
    .clipAngle(90);
// 生成地理投影路徑
  var geoPath = d3.geoPath()
    .projection(projection);
// 創建地球網格
  var graticule = d3.geoGraticule();

  // 地球縮放和拖拽
  svg.call(d3.zoom().on('zoom', zoomed));

  group.call(d3.drag().on('drag', dragged));

  // code snippet from http://stackoverflow.com/questions/36614251
  var lambda = d3.scaleLinear()
    .domain([-width, width])
    .range([-180, 180])

  var phi = d3.scaleLinear()
    .domain([-height, height])
    .range([90, -90]);
// 給地球添加網格並定義樣式
  group.append('path')
    .datum(graticule)
    .attr('class', 'graticule')
    .attr('d', geoPath);

  function dragged(d) {
    var r = {
      x: lambda((d.x = d3.event.x)),
      y: phi((d.y = d3.event.y))
    };
    projection.rotate([origin.x + r.x, origin.y + r.y]);
    updatePaths(svg, graticule, world, geoPath);
  };

  function zoomed() {
    var transform = d3.event.transform;
    var k = Math.sqrt(100 / projection.scale());
    projection.scale(scale * transform.k)
    updatePaths(svg, graticule, world, geoPath);
  };

  function updatePaths(svg, graticule, world, geoPath) {
     svg.selectAll('path.graticule').datum(graticule).attr('d', geoPath);
     svg.selectAll('path.land').datum(world).attr('d', geoPath);
  };
// 加載全球json數據,繪製陸地
  d3.json("world-110m.json", function(error, worldJSON) {
     if (error) throw error;
     world = topojson.feature(worldJSON, worldJSON.objects.land);
     group.append("path")
      .datum(world)
      .attr("class", "land")
      .attr("d", geoPath);
  });

  var i=0;

  function redraw(){
      let proj = projection.rotate([0.2 * i, 0, 0]),
          path = d3.geoPath().projection(projection)

      group.selectAll("path")
          .datum(world)
          .attr("class", "land")
          .attr("d", geoPath);

      group.select("path")
          .datum(graticule)
          .attr("class", "graticule")
          .attr("d", geoPath);

      i ++

      window.requestAnimationFrame(redraw)
  }
// 調用地球重繪函數
//window.requestAnimationFrame(redraw)

</script>

</body>
</html>

效果看下面
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章