G6
G6 copied to clipboard
力导向图在vue中,碰撞检测问题
问题描述
vue版本2.6.1 @antv/g6版本4.3.11 原封不动复制官网的例子,加入到vue的mounted生命周期,加进去后一个是没有动画,于是手动加了个animate:true 但碰撞检测和重叠都有点问题 链接里用的vue3,不过这不重要,vue3,vue2,antv/g6 4.3 4.5都会有问题,是我语法用的有问题还是怎样 这是官网的实例连接 https://g6.antv.vision/zh/examples/net/forceDirected#forceBubbles
<template>
<div id="test" />
</template>
<script>
import G6 from '@antv/g6'
export default {
mounted() {
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value,
enumerable: true,
configurable: true,
writable: true
})
} else {
obj[key] = value
}
return obj
}
const colors = [
'#BDD2FD',
'#BDEFDB',
'#C2C8D5',
'#FBE5A2',
'#F6C3B7',
'#B6E3F5',
'#D3C6EA',
'#FFD8B8',
'#AAD8D8',
'#FFD6E7'
]
const strokes = [
'#5B8FF9',
'#5AD8A6',
'#5D7092',
'#F6BD16',
'#E8684A',
'#6DC8EC',
'#9270CA',
'#FF9D4D',
'#269A99',
'#FF99C3'
]
const data = {
nodes: [
{
id: '0',
label: '0',
value: 10,
cluster: 'a',
description: 'this is node 0, \nand the value of it is 10'
},
{
id: '1',
label: '1',
value: 20,
cluster: 'b',
description: 'this is node 1, \nand the value of it is 20'
},
{
id: '2',
label: '2',
value: 5,
cluster: 'a',
description: 'this is node 2, \nand the value of it is 5'
},
{
id: '3',
label: '3',
value: 10,
cluster: 'a',
description: 'this is node 3, \nand the value of it is 10'
},
{
id: '4',
label: '4',
value: 12,
cluster: 'c',
subCluster: 'sb',
description: 'this is node 4, \nand the value of it is 12'
},
{
id: '5',
label: '5',
value: 18,
cluster: 'c',
subCluster: 'sa',
description: 'this is node 5, \nand the value of it is 18'
},
{
id: '6',
label: '6',
value: 3,
cluster: 'c',
subCluster: 'sa',
description: 'this is node 6, \nand the value of it is 3'
},
{
id: '7',
label: '7',
value: 7,
cluster: 'b',
subCluster: 'sa',
description: 'this is node 7, \nand the value of it is 7'
},
{
id: '8',
label: '8',
value: 21,
cluster: 'd',
subCluster: 'sb',
description: 'this is node 8, \nand the value of it is 21'
},
{
id: '9',
label: '9',
value: 9,
cluster: 'd',
subCluster: 'sb',
description: 'this is node 9, \nand the value of it is 9'
}
],
edges: []
}
const tipDiv = document.createElement('div')
tipDiv.innerHTML = 'Try to click or drag a bubble!'
const graphDiv = document.getElementById('test')
graphDiv.appendChild(tipDiv)
const container = document.getElementById('test')
const width = container.scrollWidth
const height = (container.scrollHeight || 500) - 20
const graph = new G6.Graph({
container: 'test',
width,
height,
animate: true,
layout: {
type: 'force',
nodeStrength: 30,
collideStrength: 0.7,
linkDistance: 50,
alphaDecay: 0.01,
preventOverlap: true
},
modes: {
default: ['drag-node']
},
defaultNode: {
size: [10, 10]
}
})
// mapping
const nodes = data.nodes
const nodeMap = new Map()
const clusterMap = new Map()
let clusterId = 0
nodes.forEach((node) => {
nodeMap.set(node.id, node)
// cluster
if (node.cluster && clusterMap.get(node.cluster) === undefined) {
clusterMap.set(node.cluster, clusterId)
clusterId++
}
const cid = clusterMap.get(node.cluster)
if (!node.style) node.style = {}
node.style.fill = colors[cid % colors.length]
node.style.stroke = strokes[cid % strokes.length]
node.x = width / 2 + 200 * (Math.random() - 0.5)
node.y = height / 2 + 200 * (Math.random() - 0.5)
})
// map the value to node size
let maxNodeValue = -9999
let minNodeValue = 9999
nodes.forEach(function(n) {
if (maxNodeValue < n.value) maxNodeValue = n.value
if (minNodeValue > n.value) minNodeValue = n.value
})
const nodeSizeRange = [10, 30]
const nodeSizeDataRange = [minNodeValue, maxNodeValue]
scaleNodeProp(nodes, 'size', 'value', nodeSizeDataRange, nodeSizeRange)
nodes.forEach(function(node) {
node.oriSize = node.size
node.oriLabel = node.label
})
function refreshDragedNodePosition(e) {
const model = e.item.get('model')
model.fx = e.x
model.fy = e.y
}
graph.on('node:dragstart', function(e) {
graph.layout()
refreshDragedNodePosition(e)
})
graph.on('node:drag', function(e) {
refreshDragedNodePosition(e)
})
graph.on('node:dragend', function(e) {
e.item.get('model').fx = null
e.item.get('model').fy = null
})
graph.on('node:click', function(e) {
const node = e.item
const states = node.getStates()
let clicked = false
const model = node.getModel()
let size = 200
let labelText = 'NODE: ' + model.id + '\n' + model.description
states.forEach(function(state) {
if (state === 'click') {
clicked = true
size = model.oriSize
labelText = model.oriLabel
}
})
graph.setItemState(node, 'click', !clicked)
graph.updateItem(node, {
size,
label: labelText
})
graph.layout()
})
graph.data(data)
graph.render()
if (typeof window !== 'undefined') {
window.onresize = () => {
if (!graph || graph.get('destroyed')) return
if (!container || !container.scrollWidth || !container.scrollHeight) return
graph.changeSize(container.scrollWidth, container.scrollHeight - 20)
}
}
function scaleNodeProp(elements, propName, refPropName, dataRange, outRange) {
const outLength = outRange[1] - outRange[0]
const dataLength = dataRange[1] - dataRange[0]
elements.forEach(function(n) {
if (propName.split('.')[0] === 'style') {
if (n.style) {
n.style[propName.split('.')[1]] =
((n[refPropName] - dataRange[0]) * outLength) / dataLength + outRange[0]
} else {
n.style = _defineProperty(
{},
propName.split('.')[1],
((n[refPropName] - dataRange[0]) * outLength) / dataLength + outRange[0]
)
}
} else {
n[propName] = ((n[refPropName] - dataRange[0]) * outLength) / dataLength + outRange[0]
}
})
}
}
}
</script>
<style lang="scss" scoped>
#test {
height: 800px;
}
</style>
重现链接
https://stackblitz.com/edit/vue-da2vvw?file=package.json,src%2FApp.vue
重现步骤
先是升级了最新版本不行,后面降级成4.3.11也不行,但单独新建html可以正常显示
预期行为
碰撞检测能正常,并且不会重叠
平台
- 操作系统: [macOS, Windows, Linux, React Native ...]
- 网页浏览器: [Google Chrome, Safari, Firefox]
- G6 版本: [4.3.11 ]
屏幕截图或视频(可选)
补充说明(可选)
No response
我似乎也是的 Vue3框架 仿着官方例子写的力导引demo,发现动画没有出现 type: 'force', 的demo效果像官方示例中 type: 'forceAtlas2' 的效果一样
纯html里使用没啥问题 我后来实在没办法,在项目里引的iframe
不用加 animate: true,在 layout 配置中加一行:onTick: () => graph.refreshPositions(), 相当于在布局过程中每一次迭代调用一次节点位置更新
因为 force 是引用的 d3 的 force,盲猜 Vue 可能和 d3 的 onTick 有点冲突?
这个我试了一下 可以解决初始化时候的动画效果 初始化完毕拖拽节点发现还是没有碰撞动画
这个我试了一下 可以解决初始化时候的动画效果 初始化完毕拖拽节点发现还是没有碰撞动画
你是不是没加 animate:true 我是有动画,但是碰撞检测有问题
不用加 animate: true,在 layout 配置中加一行:onTick: () => graph.refreshPositions(), 相当于在布局过程中每一次迭代调用一次节点位置更新
因为 force 是引用的 d3 的 force,盲猜 Vue 可能和 d3 的 onTick 有点冲突?
你这样我试了下,确实能解决问题。但每次点击的话,会卡顿,还是没官网那样丝滑
看了一下是最近的小版本有一些问题,刚刚发布了 4.7.1, 不需要配置 onTick,默认带有动画,你们试试。
看了一下是最近的小版本有一些问题,刚刚发布了 4.7.1, 不需要配置 onTick,默认带有动画,你们试试。
好的,我再试试
看了一下是最近的小版本有一些问题,刚刚发布了 4.7.1, 不需要配置 onTick,默认带有动画,你们试试。
依旧还是不行,目前引用的最新版本4.7.2,但拖动气泡时候,周边气泡碰撞时无动画
我也有这个问题
在上面 demo 来看好像没有问题,出现问题的 demo 再给一个?
尊敬的用户,您好。我们很重视您的 issue,但由于我们没有得到可追踪复现的 demo,我们暂时认为这个问题已经解决。如果还有任何问题,请随时根据 issue 模版再开启新的 issue。