antv-G6知识图谱安装--使用(实例)--连接线修改成动态,并添加跟随线移动的光圈,设置分支跟踪定位功能

这系列文章主要是完成一个图谱的自定义修改(最近太忙了长篇分段更新自己使用流程)
1. 连接线修改成动态,并添加跟随线移动的光圈
2. 自定义卡片样式和文字内容
3. 自定义伸缩节点的样式,并添加动画样式
3. 自定义弹窗样式
4. 自定义弹窗样式
5. 更新图谱
6. 设置分支跟踪定位功能

antv-G6知识图谱安装--使用(实例)

  • 官网地址➡️[添加链接描述](https://g6.antv.antgroup.com/manual/introduction)
  • 前言
  • 1. 安装---引入antv/g6
  • 2. 官网指引
  • 3. 找一个实例作自定义修改
    • 1. 先择一个dome图谱
    • 2. 在vue2+js中使用
        • 1. 创建vue文件并引入`import G6 from '@antv/g6';`
        • 2. 复制官网图谱实例(附上代码)
    • 3. 设置流动线,链接线上自定义一个运动的小球
        • 1. 官网dome地址
        • 2. 结合官网修改代码
        • 3. 运行后样式
    • 4 . 更新图谱
    • 5. 支点跟随--聚焦一个节点
      • 1. 官网地址
      • 2. graph.render();后添加聚焦节点代码
      • 3. 运行后效果
  • 下篇地址[自定义卡片--收缩节点并添加动画--自定义弹窗样式](https://blog.csdn.net/men_gqi/article/details/132476175?spm=1001.2014.3001.5502)

官网地址➡️添加链接描述

前言

提示:antv-G6初次使用(实例+分析注释)项目需要时间紧,直接网上找的加上官网信息,主要内容都有注释


1. 安装—引入antv/g6

  1. 在项目中使用 NPM 包引入
npm install --save @antv/g6
  1. 在需要用的 G6 的 JS 文件中导入:
import G6 from '@antv/g6';

在这里插入图片描述

2. 官网指引

按照一下创建一个项目之后,大概知道了图谱绘制流程,个人觉得和echart使用有点点相似
在这里插入图片描述

3. 找一个实例作自定义修改

1. 先择一个dome图谱

在这里插入图片描述

2. 在vue2+js中使用

1. 创建vue文件并引入import G6 from '@antv/g6';

2. 复制官网图谱实例(附上代码)

我不需要缩小图谱后更换样式,就删除了。

<template><div class="atlasDome"><div id="container" class="container"></div></div>
</template><script>
import G6 from '@antv/g6';
export default {name: "atlasDome",components: {},data() {return {mockData: {id: 'g1',//id是唯一的不能重复name: 'Name1',//名字label: '538.90',//金额currency: 'Yuan',//单位rate: 1.0,//百分比进度条status: 'B',//三角形颜色,可以模拟预警信息variableName: 'V1',//三角形前边小名称variableValue: 0.341,//百分比variableUp: false,//也是控制三角形样式变化的children: [{id: 'g12',name: 'Deal with LONG label LONG label LONG label LONG label',label: '338.00',rate: 0.627,status: 'R',currency: 'Yuan',variableName: 'V2',variableValue: 0.179,variableUp: true,children: [{id: 'g121',name: 'Name3',collapsed: true,label: '138.00',rate: 0.123,status: 'B',currency: 'Yuan',variableName: 'V2',variableValue: 0.27,variableUp: true,children: [{id: 'g1211',name: 'Name4',label: '138.00',rate: 1.0,status: 'B',currency: 'Yuan',variableName: 'V1',variableValue: 0.164,variableUp: false,children: [],},],},{id: 'g122',name: 'Name5',collapsed: true,label: '100.00',rate: 0.296,status: 'G',currency: 'Yuan',variableName: 'V1',variableValue: 0.259,variableUp: true,children: [],},],},{id: 'g13',name: 'Name9',label: '100.90',rate: 0.187,status: 'B',currency: 'Yuan',variableName: 'V2',variableValue: 0.221,variableUp: true,children: [{id: 'g131',name: 'Name10',label: '33.90',rate: 0.336,status: 'R',currency: 'Yuan',variableName: 'V1',variableValue: 0.12,variableUp: true,children: [],},{id: 'g132',name: 'Name11',label: '67.00',rate: 0.664,status: 'G',currency: 'Yuan',variableName: 'V1',variableValue: 0.241,variableUp: false,children: [],},],},{id: 'g14',name: 'Name12',label: '100.00',rate: 0.186,status: 'G',currency: 'Yuan',variableName: 'V2',variableValue: 0.531,variableUp: true,children: [],},],}};},computed: {},created() {this.$nextTick(() => {this.initAtial()})},mounted() {},methods: {initAtial() {const colors = {B: '#5B8FF9',R: '#F46649',Y: '#EEBC20',G: '#5BD8A6',DI: '#A7A7A7',};//  组件propsconst props = {data: this.mockData,config: {padding: [20, 50],defaultLevel: 3,defaultZoom: 0.8,modes: { default: ['zoom-canvas', 'drag-canvas'] },},};const container = document.getElementById('container');const width = container.scrollWidth;const height = container.scrollHeight || 500;// 默认配置const defaultConfig = {width,height,modes: {default: ['zoom-canvas', 'drag-canvas'],},fitView: true,animate: true,defaultNode: {type: 'flow-rect',},defaultEdge: {type: 'extra-shape-edge',// type: 'cubic-horizontal',style: {stroke: '#CED4D9',},},layout: {type: 'indented',direction: 'LR',dropCap: false,indent: 300,getHeight: () => {return 60;},},};// 自定义节点、边const registerFn = () => {/*** 自定义节点*/G6.registerNode('flow-rect',{shapeType: 'flow-rect',draw(cfg, group) {const {name = '',variableName,variableValue,variableUp,label,collapsed,currency,status,rate} = cfg;const grey = '#CED4D9';const rectConfig = {width: 202,height: 60,lineWidth: 1,fontSize: 12,fill: '#fff',radius: 4,stroke: grey,opacity: 1,};const nodeOrigin = {x: -rectConfig.width / 2,y: -rectConfig.height / 2,};const textConfig = {textAlign: 'left',textBaseline: 'bottom',};const rect = group.addShape('rect', {attrs: {x: nodeOrigin.x,y: nodeOrigin.y,...rectConfig,},});const rectBBox = rect.getBBox();// 标签标题group.addShape('text', {attrs: {...textConfig,x: 12 + nodeOrigin.x,y: 20 + nodeOrigin.y,text: name.length > 28 ? name.substr(0, 28) + '...' : name,fontSize: 12,opacity: 0.85,fill: '#000',cursor: 'pointer',},// 必须在G6 3.3及更高版本中分配。它可以是你想要的任何字符串,但在自定义项类型中应该是唯一的                                name: 'name-shape',});// 价格const price = group.addShape('text', {attrs: {...textConfig,x: 12 + nodeOrigin.x,y: rectBBox.maxY - 12,text: label,fontSize: 16,fill: '#000',opacity: 0.85,},});// 标签的货币group.addShape('text', {attrs: {...textConfig,x: price.getBBox().maxX + 5,y: rectBBox.maxY - 12,text: currency,fontSize: 12,fill: '#000',opacity: 0.75,},});// 百分比const percentText = group.addShape('text', {attrs: {...textConfig,x: rectBBox.maxX - 8,y: rectBBox.maxY - 12,text: `${((variableValue || 0) * 100).toFixed(2)}%`,fontSize: 12,textAlign: 'right',fill: colors[status],},});// 三角形比例const symbol = variableUp ? 'triangle' : 'triangle-down';const triangle = group.addShape('marker', {attrs: {...textConfig,x: percentText.getBBox().minX - 10,y: rectBBox.maxY - 12 - 6,symbol,r: 6,fill: colors[status],},});// 变量名group.addShape('text', {attrs: {...textConfig,x: triangle.getBBox().minX - 4,y: rectBBox.maxY - 12,text: variableName,fontSize: 12,textAlign: 'right',fill: '#000',opacity: 0.45,},});// bottom line backgroundconst bottomBackRect = group.addShape('rect', {attrs: {x: nodeOrigin.x,y: rectBBox.maxY - 4,width: rectConfig.width,height: 4,radius: [0, 0, rectConfig.radius, rectConfig.radius],fill: '#E0DFE3',},});bottomBackRect.set('capture', false);// bottom percentconst bottomRect = group.addShape('rect', {attrs: {x: nodeOrigin.x,y: rectBBox.maxY - 4,width: rate * rectBBox.width,height: 4,radius: [0, 0, 0, rectConfig.radius],fill: colors[status],},});bottomRect.set('capture', false);// 矩形if (cfg.children && cfg.children.length) {group.addShape('rect', {attrs: {x: rectConfig.width / 2 - 8,y: -8,width: 16,height: 16,stroke: 'rgba(0, 0, 0, 0.25)',cursor: 'pointer',fill: '#fff',},// must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item typename: 'collapse-back',modelId: cfg.id,});// collpase textgroup.addShape('text', {attrs: {x: rectConfig.width / 2,y: -1,textAlign: 'center',textBaseline: 'middle',text: collapsed ? '+' : '-',fontSize: 16,cursor: 'pointer',fill: 'rgba(0, 0, 0, 0.25)',},// must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item typename: 'collapse-text',modelId: cfg.id,});}this.drawLinkPoints(cfg, group);return rect;},update(cfg, item) {const { level, status, name } = cfg;const group = item.getContainer();let mask = group.find(ele => ele.get('name') === 'mask-shape');let maskLabel = group.find(ele => ele.get('name') === 'mask-label-shape');if (level === 0) {group.get('children').forEach(child => {if (child.get('name')?.includes('collapse')) return;child.hide();})if (!mask) {mask = group.addShape('rect', {attrs: {x: -101,y: -30,width: 202,height: 60,opacity: 0,fill: colors[status]},// must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item typename: 'mask-shape',});maskLabel = group.addShape('text', {attrs: {fill: '#fff',fontSize: 20,x: 0,y: 10,text: name.length > 28 ? name.substr(0, 16) + '...' : name,textAlign: 'center',opacity: 0,},// must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item typename: 'mask-label-shape',});const collapseRect = group.find(ele => ele.get('name') === 'collapse-back');const collapseText = group.find(ele => ele.get('name') === 'collapse-text');collapseRect?.toFront();collapseText?.toFront();} else {mask.show();maskLabel.show();}mask.animate({ opacity: 1 }, 200);maskLabel.animate({ opacity: 1 }, 200);return mask;} else {group.get('children').forEach(child => {if (child.get('name')?.includes('collapse')) return;child.show();})mask?.animate({ opacity: 0 }, {duration: 200,callback: () => mask.hide()});maskLabel?.animate({ opacity: 0 }, {duration: 200,callback: () => maskLabel.hide()});}this.updateLinkPoints(cfg, group);},setState(name, value, item) {if (name === 'collapse') {const group = item.getContainer();const collapseText = group.find((e) => e.get('name') === 'collapse-text');if (collapseText) {if (!value) {collapseText.attr({text: '-',});} else {collapseText.attr({text: '+',});}}}},getAnchorPoints() {return [[0, 0.5],[1, 0.5],];},},'rect',);G6.registerEdge('flow-cubic',{getControlPoints(cfg) {let controlPoints = cfg.controlPoints; // 指定controlPointsif (!controlPoints || !controlPoints.length) {const { startPoint, endPoint, sourceNode, targetNode } = cfg;const { x: startX, y: startY, coefficientX, coefficientY } = sourceNode? sourceNode.getModel(): startPoint;const { x: endX, y: endY } = targetNode ? targetNode.getModel() : endPoint;let curveStart = (endX - startX) * coefficientX;let curveEnd = (endY - startY) * coefficientY;curveStart = curveStart > 40 ? 40 : curveStart;curveEnd = curveEnd < -30 ? curveEnd : -30;controlPoints = [{ x: startPoint.x + curveStart, y: startPoint.y },{ x: endPoint.x + curveEnd, y: endPoint.y },];}return controlPoints;},getPath(points) {const path = [];path.push(['M', points[0].x, points[0].y]);path.push(['C',points[1].x,points[1].y,points[2].x,points[2].y,points[3].x,points[3].y,]);return path;},},'single-line',);};registerFn();const { data } = props;let graph = null;const initGraph = (data) => {if (!data) {return;}const { onInit, config } = props;const tooltip = new G6.Tooltip({// offsetX和offsetY包含父容器的内边距offsetX: 20,offsetY: 30,// 允许工具提示显示的项目类型// 允许出现 tooltip 的 item 类型itemTypes: ['node'],// 自定义提示条的内容// 自定义 tooltip 内容getContent: (e) => {const outDiv = document.createElement('div');//outDiv.style.padding = '0px 0px 20px 0px';const nodeName = e.item.getModel().name;let formatedNodeName = '';for (let i = 0; i < nodeName.length; i++) {formatedNodeName = `${formatedNodeName}${nodeName[i]}`;if (i !== 0 && i % 20 === 0) formatedNodeName = `${formatedNodeName}<br/>`;}outDiv.innerHTML = `${formatedNodeName}`;return outDiv;},shouldBegin: (e) => {if (e.target.get('name') === 'name-shape' || e.target.get('name') === 'mask-label-shape') return true;return false;},});graph = new G6.TreeGraph({container: 'container',...defaultConfig,...config,plugins: [tooltip],});if (typeof onInit === 'function') {onInit(graph);}graph.data(data);graph.render();const handleCollapse = (e) => {const target = e.target;const id = target.get('modelId');const item = graph.findById(id);const nodeModel = item.getModel();nodeModel.collapsed = !nodeModel.collapsed;graph.layout();graph.setItemState(item, 'collapse', nodeModel.collapsed);};graph.on('collapse-text:click', (e) => {handleCollapse(e);});graph.on('collapse-back:click', (e) => {handleCollapse(e);});};initGraph(data);if (typeof window !== 'undefined')window.onresize = () => {console.log(container.scrollWidth, container.scrollHeight)if (!graph || graph.get('destroyed')) return;if (!container || !container.scrollWidth || !container.scrollHeight) return;graph.changeSize(container.scrollWidth, container.scrollHeight);};}}
};
</script><style lang="scss" scoped>
.atlasDome {width: 1920px;height: 1080px;display: flex;align-items: center;justify-content: center;background-color: #03132F;}.container {width: 1000px;height: 800px;background-color: #ffffff;
}
</style>

3. 设置流动线,链接线上自定义一个运动的小球

1. 官网dome地址

https://g6.antv.antgroup.com/zh/examples/scatter/edge/#edge
在这里插入图片描述

2. 结合官网修改代码

在这里插入图片描述

     // 使用额外的矩形自定义边缘G6.registerEdge('extra-shape-edge',{afterDraw(cfg, group) {// 获取图形组中的第一个图形,在这里就是边的路径图形const shape = group.get('children')[0];// 获取路径上的0.25位点坐标 // 在该点上放置一个圆形const quatile = shape.getPoint(0.25);const quatileColor = cfg.quatileColor || '#9cdff1';//这里可以在数据中设置,来动态更新颜色const circle = group.addShape('circle', {attrs: {r: 3,fill: quatileColor || '#9cdff1',x: quatile.x,y: quatile.y,},});circle.animate((ratio) => {ratio ;const tmpPoint = shape.getPoint(ratio);return {x: tmpPoint.x,y: tmpPoint.y,};},{repeat: true, // 是否重复执行动画duration: 2000, // the duration for executing once},); let index = 0;// 定义动画逻辑shape.animate(() => {index -= 0.8;if (index > 55) {index = 0;}// 设置线型和线型偏移量const res = {lineDash:[4, 2, 1, 2], // 设置虚线的实际线段长度和间隔长度lineDashOffset: -index, // 设置虚线的偏移量};// 返回修改后的配置,包括线型和线型偏移量return res;},{repeat: true, // 是否循环执行动画duration: 5000,// 单次动画执行的时间},);},update: undefined,},'cubic',);

3. 运行后样式

屏幕录制2023-09-11 14.03.38

4 . 更新图谱

要把graph设置成全局变量或者放在this上

       <button @click="update"> 更新图谱</button>// 更新图谱update() {// graph是Graph的实例graph.changeData(this.mockData);// 若不指定该参数,则使用当前图上的数据重新渲染graph.changeData();// 根据提供的数据渲染视图。graph.render();}

5. 支点跟随–聚焦一个节点

1. 官网地址

https://g6.antv.antgroup.com/zh/examples/interaction/position/#moveAnimate
在这里插入图片描述

2. graph.render();后添加聚焦节点代码

    function handleNodeClick(event) {const item = event.item;// animately move the graph to focus on the item.// the second parameter controlls whether move with animation, the third parameter is the animate configurationgraph.focusItem(item, true, {easing: 'easeCubic',duration: 500,});}// listen to the node click eventgraph.on('node:click', handleNodeClick);

3. 运行后效果

聚焦节点

下篇地址自定义卡片–收缩节点并添加动画–自定义弹窗样式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/106566.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

普通用户使用spark的client无法更新Ranger策略

普通用户使用spark的client无法更新Ranger策略 报错图片&#xff1a; WARN org.apache.ranger.admin.client.RangerAdminRESTClient: Error getting Roles. secureModetrue, usercaojianxiangUCDIPA.VIATRIS.CC (auth:KERBEROS)&#xff0c;responsef"httpStatusCode&quo…

多线程-锁的种类

1 作用 Java中的锁主要用于保障多并发线程情况下数据的一致性。在多线程编程中为了保障数据的一致性&#xff0c;我们通常需要在使用对象或者方法之前加锁&#xff0c;这时如果有其他线程也需要使用该对象或者该方法,则首先要获得锁,如果某个线程发现锁正在被其他线程使用,就会…

Java基于SpringBoot+Vue的 4S店车辆管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 功能总览4 系统设计4.1 系统设计主要功能4.2 数据库设计4.2.1 数据库设计规范4.2…

产品波士顿矩阵

随着公司产品的增多&#xff0c;每个产品的生命周期节点各不相同&#xff0c;很多时候我们往往在产品结构、资源分配方面会产生各种问题&#xff0c;导致需要发展的产品得不到资源&#xff0c;消耗资源的产品却有无法增长&#xff0c;所谓不聚焦导致的问题其实是资源和发展错配…

【RocketMQ】设计理念与核心概念扫盲

【RocketMQ】设计理念与核心概念扫盲 文章目录 【RocketMQ】设计理念与核心概念扫盲一、RocketMQ的设计理念和目标1.1、设计理念1.2、设计目标 二、RocketMQ的核心概念扫盲篇2.1、部署架构2.1.1、Nameserver2.1.2、Broker2.1.3、Client 2.2、消息订阅模型2.2.1、消费模式2.2.2、…

C语言实现扫雷小游戏

1.首先扫雷游戏要存储布置好的雷信息&#xff0c;需要一个二维数组 不是雷放* 雷&#xff1a;# 不是雷&#xff1a;0 雷&#xff1a;1 2. 给2个二维数组 9*9 一个存放雷的信息&#xff0c;一个存放布置好雷的信息 3.为了防止在统计坐标周围的…

React基础

目录 TODO1 React概述 React的使用 React脚手架的使用 全局安装 npx安装 在脚手架中使用React JSX 1. JSX的基本使用 1.1 为什么用JSX 1.2 JSX简介 1.3 使用步骤 1.4 脚手架中能用JSX 1.5 注意点 2. 在JSX中使用JavaScript表达式 2.1 嵌入js表达式 2.2 注意点 3…

把数组b中的值拷贝给数组a numpy.copyto(a,b)

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 把数组b中的值拷贝给数组a numpy.copyto(a,b) [太阳]选择题 请问关于以下代码最后输出结果的是&#xff1f; import numpy as np to np.array([1, 2]) print("【显示】to ",to) …

springboot启动流程梳理

启动顺序主要针对SpringApplication.run&#xff08;&#xff09;方法的梳理 一 SpringApplication类的实例化 ApplicationContextInitializer 实现类的资源配置文件读取以及实现相关类的实例化 1&#xff09;.加载 ApplicationContextInitializer 实现类 &#xff0c;由 Spri…

RBTree模拟实现

一、概念 概念&#xff1a;红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出俩倍&a…

Matplotlib | 高阶绘图案例【3】- 五大战区高校排名

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. 数据处理2.1 高效数据2.2 学校排名 &#x1f3f3;️‍&#x1f308; 3. 绘图3.1 绘制图布&#xff0c;设置极坐标系3.2 绘制学校排名柱状图3.3 绘制五大战区扇形区域3.4 添加战区、学校…

前端面试经典题--页面布局

题目 假设高度已知&#xff0c;请写出三栏布局&#xff0c;其中左、右栏宽度各为300px&#xff0c;中间自适应。 五种解决方式代码 浮动解决方式 绝对定位解决方式 flexbox解决方式 表格布局 网格布局 源代码 <!DOCTYPE html> <html lang"en"> <…