d3.js 如何将D3 & Three.js对象集成为Vue 3组件?

flmtquvp  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(160)

我试图创建一个基于D3 & Three.js对象的Vue 3组件,我在网上找到了Mike Bostock编写的这个对象。
这是我想使用的对象:https://bl.ocks.org/mbostock/2b85250396c17a79155302f91ec21224
它是以HTML代码的形式提供的,当复制到html文件中时可以立即工作。
我已经下载了d3、three和其他依赖项,并使用loadScript加载了其他脚本。我使用Vite作为工具。当我在页面上加载组件时,什么也没有出现。控制台中也没有错误。
这是我到目前为止所拥有的Vue代码。这是一个可靠的方法吗?有没有更好的方法来集成这个对象?我对Vue还是一个新手,任何帮助都是非常感谢的。

  • 谢谢-谢谢
<template>

 <div id="globe" style="height:500px; width:700px"></div>

</template>

<script>
import * as THREE from 'three';
import * as d3 from 'd3'
import { loadScript } from "vue-plugin-load-script";
import { onMounted } from 'vue';

loadScript("https://unpkg.com/three@0.84");
loadScript("https://unpkg.com/topojson-client@3");
loadScript("https://unpkg.com/d3-array@1");
loadScript("https://unpkg.com/d3-collection@1");
loadScript("https://unpkg.com/d3-dispatch@1");
loadScript("https://unpkg.com/d3-request@1");
loadScript("https://unpkg.com/d3-timer@1");

var globe = document.getElementById('globe');

onMounted(() => {
    console.log('mounted!') 

  var radius = 228,
  mesh,
  graticule,
  scene = new THREE.Scene,
  camera = new THREE.PerspectiveCamera(70, globe.clientWidth/globe.clientHeight, 1, 1000),
  renderer = new THREE.WebGLRenderer({alpha: true});

  camera.position.z = 400;
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(globe.clientWidth, globe.clientHeight);
  globe.appendChild(renderer.domElement);

  d3.json("https://unpkg.com/world-atlas@1/world/50m.json", function(error, topology) {
    if (error) throw error;
    scene.add(graticule = wireframe(graticule10(), new THREE.LineBasicMaterial({color: 0xaaaaaa})));
    scene.add(mesh = wireframe(topojson.mesh(topology, topology.objects.land), new THREE.LineBasicMaterial({color: 0xff0000})));
    d3.timer(function(t) {
      graticule.rotation.x = mesh.rotation.x = Math.sin(t / 11000) * Math.PI / 3 - Math.PI / 2;
      graticule.rotation.z = mesh.rotation.z = t / 10000;
      renderer.render(scene, camera);
    });
  });

  // Converts a point [longitude, latitude] in degrees to a THREE.Vector3.
  function vertex(point) {
    var lambda = point[0] * Math.PI / 180,
        phi = point[1] * Math.PI / 180,
        cosPhi = Math.cos(phi);
    return new THREE.Vector3(
      radius * cosPhi * Math.cos(lambda),
      radius * cosPhi * Math.sin(lambda),
      radius * Math.sin(phi)
    );
  }

  // Converts a GeoJSON MultiLineString in spherical coordinates to a THREE.LineSegments.
  function wireframe(multilinestring, material) {
    var geometry = new THREE.Geometry;
    multilinestring.coordinates.forEach(function(line) {
      d3.pairs(line.map(vertex), function(a, b) {
        geometry.vertices.push(a, b);
      });
    });
    return new THREE.LineSegments(geometry, material);
  }

  // See https://github.com/d3/d3-geo/issues/95
  function graticule10() {
    var epsilon = 1e-6,
        x1 = 180, x0 = -x1, y1 = 80, y0 = -y1, dx = 10, dy = 10,
        X1 = 180, X0 = -X1, Y1 = 90, Y0 = -Y1, DX = 90, DY = 360,
        x = graticuleX(y0, y1, 2.5), y = graticuleY(x0, x1, 2.5),
        X = graticuleX(Y0, Y1, 2.5), Y = graticuleY(X0, X1, 2.5);

    function graticuleX(y0, y1, dy) {
      var y = d3.range(y0, y1 - epsilon, dy).concat(y1);
      return function(x) { return y.map(function(y) { return [x, y]; }); };
    }

    function graticuleY(x0, x1, dx) {
      var x = d3.range(x0, x1 - epsilon, dx).concat(x1);
      return function(y) { return x.map(function(x) { return [x, y]; }); };
    }

    return {
      type: "MultiLineString",
      coordinates: d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X)
          .concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y))
          .concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return Math.abs(x % DX) > epsilon; }).map(x))
          .concat(d3.range(Math.ceil(y0 / dy) * dy, y1 + epsilon, dy).filter(function(y) { return Math.abs(y % DY) > epsilon; }).map(y))
    };
  }

})


</script>
qco9c6ql

qco9c6ql1#

我不认为您需要使用loadscript来加载d3 & THREEjs依赖项,因为您正在导入的npm包已经包含了这些依赖项。
您还需要安装topojson-client并将其导入。

npm i topojson-client

下面的代码对我有用。screenshot
关于我所做更改的一些说明:
1.使用合成API时,<script>标记需要设置属性。<script setup>

  1. THREE.Geometry在线框函数中使用,但在较新的THREEjs版本中已弃用,您可能需要使用THREE.BufferGeometry。
  2. d3.json()对我不起作用,而且我对d3也不是很熟悉,所以我只是用fetch来获取json。
    1.我使用模板引用来获得div元素,但是你原来的方法也应该可以。
<script setup>
import * as THREE from 'three'
import * as d3 from 'd3'
import * as topojson from 'topojson-client'
import { onMounted, ref } from 'vue'
const globe = ref(null)

onMounted(() => {
  var radius = 228,
    mesh,
    graticule,
    scene = new THREE.Scene(),
    camera = new THREE.PerspectiveCamera(70, globe.value.clientWidth/globe.value.clientHeight, 1, 1000),
    renderer = new THREE.WebGLRenderer({ alpha: true })

  camera.position.z = 400
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(globe.value.clientWidth, globe.value.clientHeight)
  globe.value.appendChild(renderer.domElement)

  fetch('https://unpkg.com/world-atlas@1/world/50m.json')
    .then(res => res.json())
    .then(topology => {
      scene.add(
        (graticule = wireframe(
          graticule10(),
          new THREE.LineBasicMaterial({ color: 0xaaaaaa })
        ))
      )
      scene.add(
        (mesh = wireframe(
          topojson.mesh(topology, topology.objects.land),
          new THREE.LineBasicMaterial({ color: 0xff0000 })
        ))
      )
      d3.timer(function (t) {
        graticule.rotation.x = mesh.rotation.x =
          (Math.sin(t / 11000) * Math.PI) / 3 - Math.PI / 2
        graticule.rotation.z = mesh.rotation.z = t / 10000
        renderer.render(scene, camera)
      })
    })

  // Converts a point [longitude, latitude] in degrees to a THREE.Vector3.
  function vertex (point) {
    var lambda = (point[0] * Math.PI) / 180,
      phi = (point[1] * Math.PI) / 180,
      cosPhi = Math.cos(phi)
    return new THREE.Vector3(
      radius * cosPhi * Math.cos(lambda),
      radius * cosPhi * Math.sin(lambda),
      radius * Math.sin(phi)
    )
  }

  // Converts a GeoJSON MultiLineString in spherical coordinates to a THREE.LineSegments.
  function wireframe (multilinestring, material) {
    var points = []
    multilinestring.coordinates.forEach(function (line) {
      d3.pairs(line.map(vertex), function (a, b) {
        points.push(a, b)
      })
    })
    var geometry = new THREE.BufferGeometry().setFromPoints(points)
    return new THREE.LineSegments(geometry, material)
  }

  // See https://github.com/d3/d3-geo/issues/95
  function graticule10 () {
    var epsilon = 1e-6,
      x1 = 180,
      x0 = -x1,
      y1 = 80,
      y0 = -y1,
      dx = 10,
      dy = 10,
      X1 = 180,
      X0 = -X1,
      Y1 = 90,
      Y0 = -Y1,
      DX = 90,
      DY = 360,
      x = graticuleX(y0, y1, 2.5),
      y = graticuleY(x0, x1, 2.5),
      X = graticuleX(Y0, Y1, 2.5),
      Y = graticuleY(X0, X1, 2.5)

    function graticuleX (y0, y1, dy) {
      var y = d3.range(y0, y1 - epsilon, dy).concat(y1)
      return function (x) {
        return y.map(function (y) {
          return [x, y]
        })
      }
    }

    function graticuleY (x0, x1, dx) {
      var x = d3.range(x0, x1 - epsilon, dx).concat(x1)
      return function (y) {
        return x.map(function (x) {
          return [x, y]
        })
      }
    }

    return {
      type: 'MultiLineString',
      coordinates: d3
        .range(Math.ceil(X0 / DX) * DX, X1, DX)
        .map(X)
        .concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y))
        .concat(
          d3
            .range(Math.ceil(x0 / dx) * dx, x1, dx)
            .filter(function (x) {
              return Math.abs(x % DX) > epsilon
            })
            .map(x)
        )
        .concat(
          d3
            .range(Math.ceil(y0 / dy) * dy, y1 + epsilon, dy)
            .filter(function (y) {
              return Math.abs(y % DY) > epsilon
            })
            .map(y)
        )
    }
  }
})
</script>

<template>
  <div ref="globe" style="height:500px; width:700px"></div>
</template>

我的软件包. json

"dependencies": {
    "d3": "^7.4.4",
    "three": "^0.139.2",
    "topojson-client": "^3.1.0",
    "vue": "^3.2.25"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.3.1",
    "vite": "^2.9.2"
  }

相关问题