3d-force-graph示例学习记录
此文章仅用来记录3d-force-graph示例学习过程中的问题,以及相关笔记。
·
此文章仅用来记录3d-force-graph示例学习过程中的问题,以及相关笔记。
1.basic (基本)
const Graph = ForceGraph3D()(document.getElementById('3d-graph')).graphData(gData);
2.async-load (异步加载)
// URL scheme "file" is not supported. 未解决
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.jsonUrl('../datasets/miserables.json')
.nodeLabel('id')//鼠标悬浮至mesh上显示标签,标签内容未id
.nodeAutoColorBy('group');//按照group进行分类
报错:URL scheme "file" is not supported. 未解决,改为:
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData) //直接把json内容粘贴到gData
.nodeLabel('id')
.nodeAutoColorBy('group');
效果:
3.larger-graph
新知识点:
onNodeClick:监听事件单击,在新页面打开
const Graph = ForceGraph3D()(elem)
.jsonUrl('../datasets/blocks.json')
.nodeAutoColorBy('user')
.nodeLabel(node => `${node.user}: ${node.description}`)
.onNodeClick(
node => window.open(`https://bl.ocks.org/${node.user}/${node.id}`, '_blank') //单击在新页面打开
);
4.Directional arrows(带方向的箭头)
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.linkDirectionalArrowLength(3.5) //箭头长度
.linkDirectionalArrowRelPos(1) //箭头位置偏移 source指向target
.linkCurvature(0.25); //曲度
效果:
5.Directional moving particles Directional moving particles(定向移动例粒子)
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.nodeAutoColorBy('group')
.linkDirectionalParticles('value') //粒子个数
.linkDirectionalParticleSpeed(d => d.value * 0.001); //粒子运动速度
效果(部分截图):
6.Curved lines and self links(曲线和自链接)
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.nodeLabel('id')
.linkCurvature('curvature') //曲率 数值越大 弯曲程度越小
.linkCurveRotation('rotation') // 链接旋转方向
.linkDirectionalParticles(2)
.graphData(gData);
7.Auto-colored nodes/links
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.nodeAutoColorBy('group') //节点根据group着色
.linkAutoColorBy(d => gData.nodes[d.source].group) //链接根据group着色
.linkOpacity(0.5) //链接透明度
.graphData(gData);
效果:
8.Text as nodes(文本作为节点)
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.jsonUrl('../datasets/miserables.json')
.nodeAutoColorBy('group')
.nodeThreeObject(node => {
const sprite = new SpriteText(node.id);
// sprite.material.depthWrite = false; // make sprite background transparent
sprite.color = node.color;
sprite.textHeight = 8;
return sprite;
});
// Spread nodes a little wider
Graph.d3Force('charge').strength(-120); //设定引力,是排斥还是吸引
效果:
9.Images as nodes (图像作为节点)
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.nodeThreeObject(({ img }) => {
const imgTexture = new THREE.TextureLoader().load(`./imgs/${img}`); //创建纹理贴图
const material = new THREE.SpriteMaterial({ map: imgTexture });
const sprite = new THREE.Sprite(material);
sprite.scale.set(12, 12);
return sprite;
})
.graphData(gData);
效果:
10.HTML in nodes
const Graph = ForceGraph3D({
extraRenderers: [new THREE.CSS2DRenderer()]
})(document.getElementById('3d-graph'))
.graphData(gData)
.nodeAutoColorBy('group')
.nodeThreeObject(node => {
const nodeEl = document.createElement('div');
nodeEl.textContent = node.id;
nodeEl.style.color = node.color;
nodeEl.className = 'node-label';
return new THREE.CSS2DObject(nodeEl);
})
.nodeThreeObjectExtend(true); //节点对象访问器函数、属性或布尔值,用于确定在使用自定义nodeThreeObject(false)时是替换默认节点还是扩展它(true)
效果:(nodeThreeObjectExtend分别是true false)
11.Custom node geometriesxiao
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.nodeThreeObject(
({ id }) =>
new THREE.Mesh(
[
// 方块
new THREE.BoxGeometry(
Math.random() * 20,
Math.random() * 20,
Math.random() * 20
),
// 锥体
new THREE.ConeGeometry(Math.random() * 10, Math.random() * 20),
// 圆柱
new THREE.CylinderGeometry(
Math.random() * 10,
Math.random() * 10,
Math.random() * 20
),
// 十二面体
new THREE.DodecahedronGeometry(Math.random() * 10),
// 球体
new THREE.SphereGeometry(Math.random() * 10),
// 圆环
new THREE.TorusGeometry(Math.random() * 10, Math.random() * 2),
// 环面扭结
new THREE.TorusKnotGeometry(Math.random() * 10, Math.random() * 2)
][id % 7],
new THREE.MeshLambertMaterial({
color: Math.round(Math.random() * Math.pow(2, 24)),
transparent: true,
opacity: 0.75
})
)
)
.graphData(gData);
效果:
12.Gradient Links(渐变链接)
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.nodeColor(node => nodeColorScale(node.id)) //id=0,color=c1;id=1,color=c2....id=4,color=c1...
.linkThreeObject(link => {
const colors = new Float32Array(
[].concat(
...[link.source, link.target]
.map(nodeColorScale)
.map(d3.color)
.map(({ r, g, b }) => [r, g, b].map(v => v / 255))
)
);
const material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors });
const geometry = new THREE.BufferGeometry();
geometry.setAttribute(
'position',
new THREE.BufferAttribute(new Float32Array(2 * 3), 3) //三个为一组 作为坐标
);
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); //三个为一组 作为颜色
return new THREE.Line(geometry, material);
})
.graphData(gData);
效果:
13.Text in Links
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.nodeAutoColorBy('group')
.linkThreeObjectExtend(true)
.linkThreeObject(link => {
// extend link with text sprite
const sprite = new SpriteText(`${link.source} > ${link.target}`);
sprite.color = 'lightgrey';
sprite.textHeight = 1.5;
return sprite;
})
.linkPositionUpdate((sprite, { start, end }) => {
const middlePos = Object.assign(
...['x', 'y', 'z'].map(c => ({
[c]: start[c] + (end[c] - start[c]) / 2 // calc middle point
}))
);
// Position sprite
Object.assign(sprite.position, middlePos);
});
效果:
14.Orbit controls && Fly controls
const Graph = ForceGraph3D({ controlType: 'orbit' })(document.getElementById('3d-graph'))
.jsonUrl('../datasets/miserables.json')
.nodeLabel('id')
.nodeAutoColorBy('group');
const Graph = ForceGraph3D({ controlType: 'fly' })(document.getElementById('3d-graph'))
.jsonUrl('../datasets/miserables.json')
.nodeLabel('id')
.nodeAutoColorBy('group');
设置threejs控制器的类型,效果相当于:
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls = new TrackballControls(this.camera, this.renderer.domElement);
15.Camera automatic orbitting
const distance = 1400;
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.enableNodeDrag(false) //节点拖拽
.enableNavigationControls(false) //拖拽
.showNavInfo(false)
.cameraPosition({ z: distance })
.graphData(gData);
// camera orbit
// 每10ms更新一下相机的位置
let angle = 0;
setInterval(() => {
Graph.cameraPosition({
x: distance * Math.sin(angle),
z: distance * Math.cos(angle)
});
angle += Math.PI / 300;
}, 10);
相当于:camera.position.set(position);
16.Click to focus on node
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.nodeAutoColorBy('group')
//点击事件
.onNodeClick(node => {
// Aim at node from outside it
const distance = 40;
const distRatio = 1 + distance / Math.hypot(node.x, node.y, node.z);
Graph.cameraPosition(
{ x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }, // new position
node, // lookAt ({ x, y, z })
3000 // ms transition duration
);
});
17.Click to expand/collapse nodes
const Graph = ForceGraph3D()(elem)
.graphData(getPrunedTree())
.linkDirectionalParticles(2)
//子节点折叠 red;子节点展开 yellow;无子节点 green;
.nodeColor(node =>
!node.childLinks.length ? 'green' : node.collapsed ? 'red' : 'yellow'
)
.onNodeHover(
node => (elem.style.cursor = node && node.childLinks.length ? 'pointer' : null)
)
//点击事件调用getPrunedTree()更新gdata
.onNodeClick(node => {
if (node.childLinks.length) {
node.collapsed = !node.collapsed; // toggle collapse state
Graph.graphData(getPrunedTree());
}
});
18.Fix nodes after dragging
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.nodeAutoColorBy('group')
.onNodeDragEnd(node => {
node.fx = node.x;
node.fy = node.y;
node.fz = node.z;
});
拖动节点后,该节点位置不变。
19.Fit graph to canvas
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.cooldownTicks(100) //冷却时间 参数为时间
.graphData(gData);
// fit to canvas when engine stops
Graph.onEngineStop(() => Graph.zoomToFit(400));
渲染完成后,会适应画布大小。
20.Highlight nodes/links
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
//node颜色
.nodeColor(node =>
highlightNodes.has(node)
? node === hoverNode
? 'rgb(255,0,0,1)'
: 'rgba(255,160,0,0.8)'
: 'rgba(0,255,255,0.6)'
)
.linkWidth(link => (highlightLinks.has(link) ? 4 : 1))
.linkDirectionalParticles(link => (highlightLinks.has(link) ? 4 : 0))
.linkDirectionalParticleWidth(4)
.onNodeHover(node => {
// no state change
if ((!node && !highlightNodes.size) || (node && hoverNode === node)) return;
highlightNodes.clear();
highlightLinks.clear();
if (node) {
highlightNodes.add(node);
node.neighbors.forEach(neighbor => highlightNodes.add(neighbor));
node.links.forEach(link => highlightLinks.add(link));
}
hoverNode = node || null;
updateHighlight();
})
.onLinkHover(link => {
highlightNodes.clear();
highlightLinks.clear();
if (link) {
highlightLinks.add(link);
highlightNodes.add(link.source);
highlightNodes.add(link.target);
}
updateHighlight();
});
效果:
21.Multiple Node Selection
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.graphData(gData)
.nodeRelSize(9) //节点大小
.nodeColor(node => (selectedNodes.has(node) ? 'yellow' : 'grey'))
.onNodeClick((node, event) => {
if (event.ctrlKey || event.shiftKey || event.altKey) {
// multi-selection
selectedNodes.has(node) ? selectedNodes.delete(node) : selectedNodes.add(node);
} else {
// single-selection
const untoggle = selectedNodes.has(node) && selectedNodes.size === 1;
selectedNodes.clear();
!untoggle && selectedNodes.add(node);
}
Graph.nodeColor(Graph.nodeColor()); // update color of selected nodes
})
.onNodeDrag((node, translate) => {
if (selectedNodes.has(node)) {
// moving a selected node
[...selectedNodes]
.filter(selNode => selNode !== node) // don't touch node being dragged
.forEach(node =>
['x', 'y', 'z'].forEach(
coord => (node[`f${coord}`] = node[coord] + translate[coord])
)
); // translate other nodes by same amount
}
})
.onNodeDragEnd(node => {
if (selectedNodes.has(node)) {
// finished moving a selected node
[...selectedNodes]
.filter(selNode => selNode !== node) // don't touch node being dragged
.forEach(node =>
['x', 'y', 'z'].forEach(coord => (node[`f${coord}`] = undefined))
); // unfix controlled nodes
}
});
效果:按住alt 、 shift、alt均可以进行多选。
22.Dynamic data changes
const Graph = ForceGraph3D()(elem)
.enableNodeDrag(false)
.onNodeClick(removeNode)
.graphData(initData);
//定时添加节点,并连接dst为已有的随机节点
setInterval(() => {
const { nodes, links } = Graph.graphData();
const id = nodes.length;
Graph.graphData({
nodes: [...nodes, { id }],
links: [...links, { source: id, target: Math.round(Math.random() * (id - 1)) }]
});
}, 1000);
//
function removeNode(node) {
let { nodes, links } = Graph.graphData();
links = links.filter(l => l.source !== node && l.target !== node); // Remove links attached to node
nodes.splice(node.id, 1); // Remove node 从node.id开始删除1个元素
//修正其他节点的id
nodes.forEach((n, idx) => {
n.id = idx;
}); // Reset node ids to array index
Graph.graphData({ nodes, links });
}
23.Node collision detection(节点碰撞检测)
const N = 50;
const nodes = [...Array(N).keys()].map(() => ({
// Initial velocity in random direction
// 随机方向上的初始速度
vx: Math.random(),
vy: Math.random(),
vz: Math.random()
}));
const Graph = ForceGraph3D()(document.getElementById('3d-graph'));
Graph.cooldownTime(Infinity)
.d3AlphaDecay(0) //alpha 衰减率
.d3VelocityDecay(0) //默认为 0.4,较低的衰减系数可以使得迭代次数更多,其布局结果也会更理性,但是可能会引起数值不稳定从而导致震荡。
// Deactivate existing forces
.d3Force('center', null) //centering作用力可以使得节点布局开之后围绕某个中心
.d3Force('charge', null) //作用力应用在所用的节点之间
// Add collision and bounding box forces
.d3Force('collide', d3.forceCollide(Graph.nodeRelSize()))
.d3Force('box', () => {
const CUBE_HALF_SIDE = Graph.nodeRelSize() * N * 0.5;
nodes.forEach(node => {
const x = node.x || 0,
y = node.y || 0,
z = node.z || 0;
// bounce on box walls
if (Math.abs(x) > CUBE_HALF_SIDE) {
node.vx *= -1;
}
if (Math.abs(y) > CUBE_HALF_SIDE) {
node.vy *= -1;
}
if (Math.abs(z) > CUBE_HALF_SIDE) {
node.vz *= -1;
}
});
})
// Add nodes
.graphData({ nodes, links: [] });
24.暂停、恢复动画
const distance = 1400;
let isRotationActive = true;
const Graph = ForceGraph3D()(document.getElementById('3d-graph'))
.enableNodeDrag(false)
.enableNavigationControls(false)
.showNavInfo(true)
.cameraPosition({ z: distance })
.graphData(gData);
// camera orbit
let angle = 0;
//使得物体旋转
setInterval(() => {
if (isRotationActive) {
Graph.cameraPosition({
x: distance * Math.sin(angle),
z: distance * Math.cos(angle)
});
angle += Math.PI / 300;
}
}, 10);
document.getElementById('rotationToggle').addEventListener('click', event => {
isRotationActive = !isRotationActive;
event.target.innerHTML = `${isRotationActive ? 'Pause' : 'Resume'} Rotation`;
});
let isAnimationActive = true;
document.getElementById('animationToggle').addEventListener('click', event => {
isAnimationActive ? Graph.pauseAnimation() : Graph.resumeAnimation();
isAnimationActive = !isAnimationActive;
event.target.innerHTML = `${isAnimationActive ? 'Pause' : 'Resume'} Animation`;
});
初学结束~~~Fighting!
点击阅读全文
更多推荐
活动日历
查看更多
直播时间 2025-02-26 16:00:00


直播时间 2025-01-08 16:30:00


直播时间 2024-12-11 16:30:00


直播时间 2024-11-27 16:30:00


直播时间 2024-11-21 16:30:00


所有评论(0)