- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
通过官方文档,可知高亮相邻节点分为两种方法,文档描述并不是很清楚,对刚接触这个库的小白并不是很友好,慢慢总结慢慢来吧 。
是通过 内置的Behavior activate-relations 来实现,Behavior 是 G6 提供的定义图上交互事件的机制。与 交互模式 Mode 配合使用 。
activate-relations :当鼠标移到某节点时,突出显示该节点以及与其直接关联的节点和连线; 。
trigger: 'mouseenter'
。表示出发机制,可以是 mouseenter
、 click
; activeState: 'active'
。活跃节点状态,默认为 active
,可以与 graph 实例的 xxxStateStyles
结合实现丰富的视觉效果。 inactiveState: 'inactive'
。非活跃节点状态,默认值为 inactive
。同样可以与 graph 实例的 xxxStateStyles
结合实现丰富的视觉效果。
let drawGraph = document.getElementById("drawGraph");
this.graphWidth = drawGraph.scrollWidth;
this.graphHeight = drawGraph.scrollHeight || 1200;
graphG = new this.G6.Graph({
container: "drawGraph",
width: this.graphWidth,
height: this.graphHeight,
modes: {
default: [
{ type: "activate-relations", activeState: 'active', inactiveState: 'inactive' },
],
// default: ['activate-relations'] // 由于活跃节点及非活跃节点状态均采用默认值,因此可以简写为这种形式
},
nodeStateStyles:{}, // 配置节点状态样式
edgeStateStyles:{}, // 配置边状态样式
comboStateStyles:{}, // 配置分组状态样式
}
graphG.data(data);
graphG.render();
如果 仅采用内置的高亮节点 ,会采用默认的样式,最终的渲染效果为:
这种方式是通过 自定义状态 ,在通过实例提供的 setItemState 、 clearItemStates 设置和清除目标的状态信息,同样需要与graph 实例的 xxxStateStyles 结合实现.
graphG = new this.G6.Graph({
container: "drawGraph",
width: this.graphWidth,
height: this.graphHeight,
nodeStateStyles:{ // 配置节点状态样式,此处就先写一个,后续会有完整的案例分享
highlight: {
fill: "#db4437",
shadowColor: '#fff',
stroke: "#db4437",
cursor: "pointer",
'text-shape': {
lineWidth: 1,
fill: "#db4437",
stroke: "#db4437",
},
},
},
edgeStateStyles:{}, // 配置边状态样式
comboStateStyles:{}, // 配置分组状态样式
}
graphG.data(data);
graphG.render();
graphG.on("combo:mouseenter", (e) => {
let edgeItem = e.item
graphG.setItemState(edgeItem, 'highlight', true)
edgeItem.getEdges().forEach(edge => {
graphG.setItemState(edge.getTarget(), 'highlight', true)
graphG.setItemState(edge.getSource(), 'highlight', true)
graphG.setItemState(edge, 'highlight', true)
})
graphG.paint()
graphG.setAutoPaint(true)
});
graphG.on('combo:mouseleave', (e) => {
graphG.setAutoPaint(false)
graphG.getNodes().forEach(node => {
graphG.clearItemStates(node)
})
graphG.getEdges().forEach(edge => {
graphG.clearItemStates(edge)
})
graphG.getCombos().forEach(combo => {
graphG.clearItemStates(combo)
})
graphG.paint()
graphG.setAutoPaint(true)
})
如果仅 采用自定义高亮节点 ,最终的渲染效果为:
通过上面的案例,可以看出, combo:mouseenter 时相关联的 边和点 全部高亮,并且统一了连线的颜色,此时可能会与我们的需求相违背,可能连线还是想要保持原来的颜色,因为不同的颜色描述两点之间的不同类型的指向关系。那么此时在处理鼠标事件时,需要获取要节点和连线 原始样式.
graphG.on("combo:mouseenter", (e) => {
let comboItem = e.item;
const originStyle = comboItem._cfg.originStyle["circle-combo"].fill;
comboItem._cfg.styles.highlight.fill = originStyle;
graphG.setItemState(comboItem, "highlight", true);
comboItem.getEdges().forEach((edge) => {
const originStyle = edge._cfg.originStyle["edge-shape"].stroke; // 获取边edge 原始颜色
edge._cfg.styles.highlight.stroke = originStyle;
let edgeSource = edge.getSource();
let edgeTarget = edge.getTarget();
if ( edgeSource._cfg.type === "combo" && edgeSource._cfg.model.id =="100-600" ) {
const originStyle = edgeSource._cfg.originStyle["circle-combo"].fill; // 获取分组combo 原始颜色
edgeSource._cfg.styles.highlight.fill = originStyle;
}
if ( edgeTarget._cfg.type === "combo" && edgeTarget._cfg.model.id =="100-600" ) {
const originStyle = edgeTarget._cfg.originStyle["circle-combo"].fill;
edgeTarget._cfg.styles.highlight.fill = originStyle;
}
graphG.setItemState(edgeSource, "highlight", true);
graphG.setItemState(edgeTarget, "highlight", true);
graphG.setItemState(edge, "highlight", true);
});
});
那么此时最终的效果为:
其实两种方法与异曲同工之妙,都是进行状态的处理,只不过一个是帮我们处理了一部分状态与样式,可以直接拿来用,但往往内置的样式与我们实际使用时不相符,因此可以使用两者结合的方式,最终效果及完整demo,采用随机数来模拟实体与关系.
<template>
<div>
<div id="drawGraph"></div>
</div>
</template>
<script>
let graphG = null
export default {
mounted() {
this.initData();
},
methods: {
initData() {
let combos = [
{ id: '100-600', label: '100-600' },
{ id: '100-200', label: '100-200' },
{ id: '200-300', label: '200-300' },
{ id: '300-400', label: '300-400' },
{ id: '400-500', label: '400-500' },
{ id: '500-600', label: '500-600' },
]
let edges = [
{ source: '100-600', target: '100-200' },
{ source: '100-600', target: '200-300' },
{ source: '100-600', target: '300-400' },
{ source: '100-600', target: '400-500' },
{ source: '100-600', target: '500-600' },
]
// 生成(20-30)随机数 模拟节点node
let randomCount = Math.floor(Math.random() * 10) + 20;
let row_clo = Math.floor(Math.sqrt(randomCount));
let origin = [-150, 50], row = 110, clo = 150;
let nodes = []
for (let i = 0; i < randomCount; i++) {
let randomNum = String(Math.floor(Math.random() * 500) + 100); // 生成100-600之间的随机数,并与combo进行连线
let rowindex = Math.floor(i / row_clo);
let cloindex = i % row_clo;
let x = origin[0] + clo * cloindex
let y = origin[1] + row * rowindex
let node = {
label: randomNum,
id: randomNum,
x,
y,
style: {
fillOpacity: 0.5,
cursor: "pointer",
fill: randomNum % 5 == 0 ? "#81C7D4" : "#986DB2"
}
}
let index = Math.floor(randomNum / 100)
let edge = {
source: combos[index].id,
target: randomNum,
lineWidth: 1,
style: {
lineDash: [3, 3],
lineWidth: 0.5,
stroke: "#00AA90"
}
}
nodes.push(node)
edges.push(edge)
}
let data = { combos, edges, nodes }
console.log(data);
this.makeRelationData(data);
},
// 分组 点 连线处理
makeRelationData(data) {
if (graphG) {
graphG.destroy();
}
let drawGraph = document.getElementById("drawGraph");
this.graphWidth = drawGraph.scrollWidth;
this.graphHeight = drawGraph.scrollHeight || 1200;
let origin = [this.graphWidth / 2, 100];
let row = 150, clo = 180;
let combos = data.combos
let row_clo = Math.floor(Math.sqrt(combos.length));
for (let i = 0; i < combos.length; i++) {
let rowindex = Math.floor(i / row_clo) + 1;
let cloindex = (i % row_clo) + 1;
// 分组默认样式设置
if (i === 0) {
combos[i].x = this.graphWidth / 3
combos[i].y = this.graphHeight / 3
combos[i].style = {
fill: "#a5e4f0",
opacity: 0.5,
cursor: "pointer",
};
} else {
// 分组定位
combos[i].x = origin[0] + clo * cloindex;
combos[i].y = origin[1] + row * rowindex;
if (i % 2 === 1) {
combos[i].y += 40;
}
combos[i].style = {
fill: "#f6cd6b",
fillOpacity: 0.2,
}
}
}
this.drawQfast(data)
},
drawQfast(data) {
graphG = new this.G6.Graph({
container: "drawGraph",
width: this.graphWidth,
height: this.graphHeight,
modes: {
default: [
{ type: "zoom-canvas", enableOptimize: true, optimizeZoom: 0.2 },
{ type: "drag-canvas", enableOptimize: true },
{ type: "drag-node", enableOptimize: true, onlyChangeComboSize: true },
{ type: "drag-combo", enableOptimize: true, onlyChangeComboSize: true },
{ type: "activate-relations", activeState: 'active', inactiveState: 'inactive' },
],
},
defaultEdge: {
type: 'cubic-horizontal',
lineWidth: 1,
style: {
endArrow: true,
stroke: "#FAD069",
},
},
defaultNode: {
type: "circle",
size: 15,
labelCfg: {
position: "bottom",
style: {
fontSize: 15,
},
},
},
defaultCombo: {
cursor: "pointer",
opacity: 0,
type: "circle",
lineWidth: 1,
collapsed: true,
labelCfg: {
position: "top",
refY: 5,
style: {
fontSize: 16,
},
},
},
nodeStateStyles: {
highlight: {
fill: "#db4437",
shadowColor: '#fff',
stroke: "#db4437",
cursor: "pointer",
'text-shape': {
lineWidth: 1,
fill: "#db4437",
stroke: "#db4437",
},
},
inactive: {
stroke: '#eee',
lineWidth: 1,
'text-shape': {
fill: "#eee",
stroke: "#eee",
},
},
},
edgeStateStyles: {
hover: {
lineWidth: 3,
},
highlight: {
stroke: '#00AA90',
lineWidth: 3,
},
},
comboStateStyles: {
highlight: {
fill: "#f6cd6b",
opacity: 0.7,
cursor: "pointer",
'text-shape': {
fill: "#A5E4F0",
stroke: "#A5E4F0",
lineWidth: 1,
},
},
inactive: {
stroke: '#eee',
lineWidth: 1,
'text-shape': {
fill: "#eee",
stroke: "#eee",
},
},
},
});
graphG.data(data);
graphG.render(); // 渲染图
graphG.on("edge:mouseenter", (e) => {
graphG.setItemState(e.item, "hover", true);
});
graphG.on("edge:mouseleave", (e) => {
graphG.setItemState(e.item, "hover", false);
});
graphG.on("combo:mouseenter", (e) => {
let comboItem = e.item;
const originStyle = comboItem._cfg.originStyle["circle-combo"].fill;
comboItem._cfg.styles.highlight.fill = originStyle;
graphG.setItemState(comboItem, "highlight", true);
comboItem.getEdges().forEach((edge) => {
const originStyle = edge._cfg.originStyle["edge-shape"].stroke; // 获取边edge 原始颜色
edge._cfg.styles.highlight.stroke = originStyle;
let edgeSource = edge.getSource();
let edgeTarget = edge.getTarget();
if ( edgeSource._cfg.type === "combo" && edgeSource._cfg.model.id =="100-600" ) {
const originStyle = edgeSource._cfg.originStyle["circle-combo"].fill; // 获取分组combo 原始颜色
edgeSource._cfg.styles.highlight.fill = originStyle;
}
if ( edgeTarget._cfg.type === "combo" && edgeTarget._cfg.model.id =="100-600" ) {
const originStyle = edgeTarget._cfg.originStyle["circle-combo"].fill;
edgeTarget._cfg.styles.highlight.fill = originStyle;
}
graphG.setItemState(edgeSource, "highlight", true);
graphG.setItemState(edgeTarget, "highlight", true);
graphG.setItemState(edge, "highlight", true);
});
});
graphG.on('combo:mouseleave', () => {
graphG.setAutoPaint(false)
graphG.getNodes().forEach(node => {
graphG.clearItemStates(node)
})
graphG.getEdges().forEach(edge => {
graphG.clearItemStates(edge)
})
graphG.getCombos().forEach(combo => {
graphG.clearItemStates(combo)
})
graphG.paint()
graphG.setAutoPaint(true)
})
},
}
};
</script>
最后此篇关于可视化—AntVG6高亮相邻节点的两种方式的文章就讲到这里了,如果你想了解更多关于可视化—AntVG6高亮相邻节点的两种方式的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在寻找一种方法来创建根据价格选择我的产品的过滤器(选择下拉菜单)。 我知道这样的查询是完全可能的: SELECT * FROM products ORDER BY price ASC SELECT
函数参数中或显示尺寸时(高度,宽度)的顺序是否有约定? 最佳答案 我不知道大量的语言,但我使用过的语言(宽度,高度)。它更适合沿着 (x, y) 坐标线。 关于language-agnostic -
在我的表单中,我让用户输入房间的长度高度和宽度以获得 m2、m3 和瓦特的计算值。但是用户也应该能够直接输入 height 和 m2 来获取值。我尝试了很多语法,但 if else 不能正常工作。我知
我在 Elasticsearch 中创建了一个索引,看起来像 {"amazingdocs":{"aliases":{},"mappings":{"properties":{"Adj Close":{"
我有以下功能,我需要清除数据库中的所有图片列并移动到文件系统。当我一次性完成这一切时,内存太多并且会崩溃。我切换到递归函数并执行 20 次写入和批量操作。 我需要为大约 6 个表执行此操作。我的 Re
我正在编写一个函数来计算 PI 的值,并将其作为 double 值返回。到目前为止,一切都很好。但是一旦函数到达小数点后14位,它就不能再保存了。我假设这是因为 double 有限。我应该怎么做才能继
2020年是中国CDN行业从98年诞生到今天快速发展的第二十四年,相关数据显示,全国感知网速持续上扬,达到了3.29兆/秒,标志着在宽带中国的政策指导下,中国的网速水平正在大步赶上世界发达国家的水平
在 aerospike 集合中,我们有四个 bin userId、adId、timestamp、eventype,主键是 userId:timestamp。在 userId 上创建二级索引以获取特定用
$('#container').highcharts('Map', { title : { text : 'Highmaps basic demo'
有没有办法显示自定义宽度/高度的YouTube视频? 最佳答案 在YouTube网站上的this link中: You can resize the player by editing the obj
我使用 Highcharts ,我想在 Highcharts 状态下悬停时制作动态不同的颜色。 正如你可以看到不同的颜色,这就是我做的 var usMapChart , data = [] ; va
在所有节点上运行 tpstats 后。我看到很多节点都有大量的 ALL TIME BLOCKED NTR。我们有一个 4 节点集群,NTR ALL TIME BLOCKED 的值为: 节点 1:239
我发现 APC 上存在大量碎片 (>80%),但实际上性能似乎相当不错。我有 read another post这建议在 wordpress/w3tc 中禁用对象缓存,但我想知道减少碎片是否比首先缓存
对于我的脚本类(class),我们必须制作更高/更低的游戏。到目前为止,这是我的代码: import random seedVal = int(input("What seed should be u
我发现 APC 上存在大量碎片 (>80%),但实际上性能似乎相当不错。我有 read another post这建议在 wordpress/w3tc 中禁用对象缓存,但我想知道减少碎片是否比首先缓存
对于我的脚本类(class),我们必须制作更高/更低的游戏。到目前为止,这是我的代码: import random seedVal = int(input("What seed should be u
我已经 seen >2 字节的 unicode 代码点,如 U+10000 可以成对编写,如 \uD800\uDC00。它们似乎以半字节 d 开头,但我只注意到了这一点。 这个 split Actio
有人可以帮我理解为什么我的饼图百分比计算不正确吗?看截图: 根据我的计算,如 RHS 上所示,支出百分比应为 24.73%。传递给 Highcharts 的值如下:- 花费:204827099.36-
我阅读了有关该问题的所有答案,但我还没有找到任何解决方案。 我有一个应用程序,由我的 api 服务器提供。 Wildfly 8.1 和 Mysql 5.6。当查看时间到来时(Wildfly 服务器连接
我正在用选定的项目创建圆形导航。当用户单击任何项目时,它将移动到定义的特定点。一切都很好,除了当你继续点击项目时,当动画表现不同并且项目在 360 度圆中移动并且它被重置直到你重复场景时,我希望它
我是一名优秀的程序员,十分优秀!