96 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<head>
 | 
						|
  <style> body { margin: 0; } </style>
 | 
						|
 | 
						|
  <script src="3d-force-graph.min.js"></script>
 | 
						|
  <!--<script src="../../dist/3d-force-graph.js"></script>-->
 | 
						|
</head>
 | 
						|
 | 
						|
<body>
 | 
						|
  <div id="3d-graph"></div>
 | 
						|
  <div style="position: absolute; top: 5px; right: 5px;">
 | 
						|
    <button id="rotationToggle" style="margin: 8px; height: 25px; width: 150px;">
 | 
						|
      暂停旋转
 | 
						|
    </button>
 | 
						|
  </div>
 | 
						|
  <script type="importmap">{ "imports": { "three": "//unpkg.com/three/build/three.module.js" }}</script>
 | 
						|
  <script type="module">
 | 
						|
    import SpriteText from "//unpkg.com/three-spritetext/dist/three-spritetext.mjs";
 | 
						|
 | 
						|
    const distance = 2000;
 | 
						|
    let isRotationActive = true;
 | 
						|
 | 
						|
    // Random tree
 | 
						|
    const N = 1200;
 | 
						|
    const gData = {
 | 
						|
      nodes: [...Array(N).keys()].map(i => ({ id: i,group:Math.floor(i/150) })),
 | 
						|
      links: [...Array(N).keys()]
 | 
						|
        .filter(id => id)
 | 
						|
        .map(id => ({
 | 
						|
          source: id,
 | 
						|
          target: Math.round(Math.random() * (id-1))
 | 
						|
        }))
 | 
						|
    };
 | 
						|
    const Graph = ForceGraph3D()
 | 
						|
      (document.getElementById('3d-graph'))
 | 
						|
        .graphData(gData)
 | 
						|
        // .jsonUrl('./miserables.json')
 | 
						|
        .nodeAutoColorBy('group')
 | 
						|
        .nodeLabel('id')
 | 
						|
        .linkDirectionalParticles(4)
 | 
						|
        .linkDirectionalParticleWidth(4)
 | 
						|
        .linkDirectionalParticleSpeed(d => 4 * 0.001)// d.value
 | 
						|
        .linkWidth(4)
 | 
						|
        .nodeRelSize(6)
 | 
						|
        // .nodeThreeObject(node => {// 借助三方库 实现文字几何的展示
 | 
						|
        //   const sprite = new SpriteText(node.id);
 | 
						|
        //   sprite.material.depthWrite = false; // make sprite background transparent
 | 
						|
        //   sprite.color = node.color;// node.color
 | 
						|
        //   sprite.textHeight = 8;
 | 
						|
        //   return sprite;
 | 
						|
        // })
 | 
						|
        // .linkDirectionalArrowLength(3)// 让边带上箭头
 | 
						|
        // .linkDirectionalArrowRelPos(1)// 设置箭头位置
 | 
						|
        .onNodeClick(node => {
 | 
						|
          // Aim at node from outside it
 | 
						|
          const distance = 1800;
 | 
						|
          const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z);
 | 
						|
 | 
						|
          const newPos = node.x || node.y || node.z
 | 
						|
            ? { x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }
 | 
						|
            : { x: 0, y: 0, z: distance }; // special case if node is in (0,0,0)
 | 
						|
 | 
						|
          Graph.cameraPosition(
 | 
						|
            newPos, // new position
 | 
						|
            node, // lookAt ({ x, y, z })
 | 
						|
            3000  // ms transition duration
 | 
						|
          )
 | 
						|
        })
 | 
						|
        .cameraPosition({ z: distance })
 | 
						|
 | 
						|
    // Spread nodes a little wider
 | 
						|
    // Graph.d3Force('charge').strength(-120);
 | 
						|
 | 
						|
    // camera orbit
 | 
						|
    let angle = 0;
 | 
						|
    let time = setInterval(() => {
 | 
						|
      if (isRotationActive) {
 | 
						|
        Graph.cameraPosition({
 | 
						|
          x: distance * Math.sin(angle),
 | 
						|
          y: 0,
 | 
						|
          z: distance * Math.cos(angle),
 | 
						|
        });
 | 
						|
        angle += Math.PI / 500;
 | 
						|
      }
 | 
						|
    }, 10);
 | 
						|
 | 
						|
    document.getElementById('rotationToggle').addEventListener('click', event => {
 | 
						|
      if(isRotationActive){
 | 
						|
      isRotationActive = !isRotationActive
 | 
						|
      }else{
 | 
						|
      isRotationActive = !isRotationActive
 | 
						|
    }
 | 
						|
      event.target.innerHTML = `${(isRotationActive ? '暂停' : '重置')} 旋转`;
 | 
						|
    });
 | 
						|
 | 
						|
  </script>
 | 
						|
</body> |