ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

G6 鱼眼放大镜(Fisheye)插件完全指南:focus+context 交互式局部放大实战

G6 鱼眼放大镜(Fisheye)插件完全指南:focus+context 交互式局部放大实战 G6 鱼眼放大镜Fisheye插件完全指南focuscontext 交互式局部放大实战【免费下载链接】G6♾ A Graph Visualization Framework in JavaScript.项目地址: https://gitcode.com/gh_mirrors/g6/G6Fisheye 鱼眼放大镜是 G6 图可视化框架内置的交互插件专为 focuscontext焦点上下文探索场景设计它用一个可移动的圆形透镜放大关注区域内的节点同时保持周边上下文以及上下文与关注中心的关系不丢失。本文基于 G6 官方文档与源码实现系统讲解 Fisheye 插件的配置项、交互触发方式、畸变算法原理、样式定制与动态更新 API并给出可直接运行的完整代码示例。读完本文你将能够在自己的 G6 应用中一键接入鱼眼放大镜并针对半径、畸变因子、外观样式和节点样式做精细化定制。概述为什么需要鱼眼放大镜在大规模图可视化场景中节点数量多、布局密集直接放大画布往往导致查看区域外的重要上下文被裁剪。鱼眼放大镜Fisheye采用的是一种“非线性放大”策略以透镜圆心为中心对半径范围内的节点做距离相关的放大变换——越靠近中心放大倍数越大越靠近边缘越接近原始尺寸从而在突出关注区域的同时保留整体视图的连续感。从源码注释packages/g6/src/plugins/fisheye/index.ts可以看到其设计目标Fisheye 鱼眼放大镜是为 focuscontext 的探索场景设计的它能够保证在放大关注区域的同时保证上下文以及上下文与关注中心的关系不丢失。典型使用场景演示与汇报在演示过程中需要突出展示某些区域内容引导观众视线聚焦局部细节审查需要局部放大查看密集区域的细节如节点标签、连边走向时同时不想失去整体视图大图探索在包含大量节点和边的大型关系图中通过透镜扫视不同区域快速定位感兴趣的子图。基本用法一行配置接入鱼眼Fisheye 是 G6 内置插件无需单独安装扩展包直接在Graph的plugins数组中声明即可。最简单的配置方式只需要插件类型字符串const graph new Graph({ plugins: [fisheye], });带完整参数的最基本初始化示例const graph new Graph({ plugins: [ { type: fisheye, trigger: drag, // 通过拖拽移动鱼眼 d: 1.5, // 设置畸变因子 r: 120, // 设置鱼眼半径 showDPercent: true, // 显示畸变程度 }, ], });执行graph.render()后将鼠标移动到画布上即可看到圆形透镜跟随出现透镜内的节点被放大并重新分布。配置项全解Fisheye 插件的全部配置项定义在源码接口FisheyeOptions中packages/g6/src/plugins/fisheye/index.ts默认值见Fisheye.defaultOptions同文件第 156-166 行。下表为完整配置项说明属性描述类型默认值必选type插件类型stringfisheye✓key插件的唯一标识可用于获取插件实例或更新插件选项string-trigger控制鱼眼放大镜的移动方式支持三种配置pointermove始终跟随鼠标移动、click点击画布时移动到点击位置、drag通过拖拽移动pointermove|drag|clickpointermover鱼眼放大镜半径number120maxR鱼眼放大镜可调整的最大半径配合scaleRBy使用number画布宽高的最小值的一半minR鱼眼放大镜可调整的最小半径number0d畸变因子number1.5maxD鱼眼放大镜可调整的最大畸变因子number5minD鱼眼放大镜可调整的最小畸变因子number0scaleRBy调整鱼眼放大镜范围半径的方式wheel滚轮或drag拖拽wheel|drag-scaleDBy调整鱼眼放大镜畸变因子的方式wheel滚轮或drag拖拽wheel|drag-showDPercent是否在鱼眼放大镜中显示畸变因子数值booleantruestyle鱼眼放大镜圆形透镜样式详见下文 style 小节object-nodeStyle在鱼眼放大镜中的节点样式NodeStyle | ((datum: NodeData) NodeStyle){ label: true }preventDefault是否阻止默认事件booleantrue关键参数详解r半径透镜的物理作用范围单位为画布坐标像素。源码中透镜实际渲染为一个圆形元素其直径等于r * 2见 renderLens。默认值 120适合中等画布画布较大时可适当调大。d畸变因子决定透镜内节点被拉伸的“强度”。d越大靠近中心的节点被放得越大边缘到中心的尺寸过渡越陡峭。默认值 1.5取值区间建议在 05 之间minD/maxD默认即为此范围。trigger透镜移动方式。默认为pointermove即透镜始终跟随鼠标click模式适合触摸屏或需要精确落点的场景drag模式适合在探索大图时“抓住”透镜拖动浏览。nodeStyle透镜内节点的渲染样式默认{ label: true }即进入透镜的节点自动显示标签。它既可以是普通样式对象也可以是接收NodeData返回样式的函数便于按节点数据动态定制。preventDefault默认true会阻止滚轮等事件触发的浏览器默认行为如页面滚动避免与透镜缩放操作冲突。style透镜圆形样式style对应 G6 圆形元素Circle的样式属性CircleStyleProps用于配置鱼眼放大镜本身的外观填充、描边、透明度、阴影、线段端点等。源码中的默认透镜样式defaultLensStyle为{ fill: #ccc, // 填充颜色 fillOpacity: 0.1, // 填充透明度 lineWidth: 2, // 线宽 stroke: #000, // 描边颜色 strokeOpacity: 0.8, // 描边透明度 labelFontSize: 12, // 畸变百分比标签字号 }完整可配置属性如下属性描述类型默认值fill填充颜色string | Pattern | null#cccstroke描边颜色string | Pattern | null#000opacity整体透明度number | string-fillOpacity填充透明度number | string0.1strokeOpacity描边透明度number | string-lineWidth线宽度number | string2lineCap线段端点样式butt|round|square-lineJoin线段连接处样式miter|round|bevel-shadowColor阴影颜色string-shadowBlur阴影模糊程度number-shadowOffsetX阴影 X 方向偏移number-shadowOffsetY阴影 Y 方向偏移number-完整样式属性参考 元素 - 节点 - 内置节点 - 通用样式属性 - style。交互缩放控制半径与畸变因子的动态调整通过scaleRBy和scaleDBy可以分别控制透镜半径与畸变因子的实时调整方式支持滚轮wheel和拖拽drag两种手势。示例const graph new Graph({ plugins: [ { type: fisheye, // 通过滚轮调整半径 scaleRBy: wheel, // 通过拖拽调整畸变因子 scaleDBy: drag, // 设置半径和畸变因子的范围 minR: 50, maxR: 200, minD: 1, maxD: 3, }, ], });手势与优先级规则重要当trigger、scaleRBy、scaleDBy三者可能同时使用拖拽drag手势时同一手势只能绑定给一个配置项优先级顺序为triggerscaleRByscaleDBy即如果三者都设为drag只会为trigger绑定拖拽事件移动透镜优先同理如果scaleRBy和scaleDBy同时设为wheel只会为scaleRBy绑定滚轮事件此时滚轮只调节半径。这一优先级逻辑与源码 bindEvents 中的事件绑定分支完全一致代码依次判断trigger、scaleRBy、scaleDBy三者都要求drag时按三目运算符链trigger drag ? this.onDrag : scaleRBy drag ? this.scaleRByDrag : this.scaleDByDrag取优先级最高者滚轮同理取scaleRBy wheel ? this.scaleRByWheel : this.scaleDByWheel。调整步长与范围约束源码定义了两个增量常量index.tsconst R_DELTA 0.05; // 半径每次缩放的比例系数 const D_DELTA 0.1; // 畸变因子每次调整的步长半径滚轮上滚/拖拽正方向时按r / (1 - R_DELTA)放大下滚时按r * (1 - R_DELTA)缩小并始终被约束在[minR, maxR]内maxR未设置时取画布宽高最小值的二分之一见 scaleR。畸变因子每次0.1或-0.1被约束在[minD, maxD]内见 scaleD。代码示例从基础到深度定制基础用法最简配置方式const graph new Graph({ plugins: [fisheye], });自定义样式透镜外观 节点样式可以同时定制透镜本身的外观以及透镜内节点的样式包括基础样式、标签、图标等const graph new Graph({ plugins: [ { type: fisheye, r: 150, d: 2, style: { fill: #2f54eb, // 鱼眼区域的填充颜色 fillOpacity: 0.2, // 填充区域的透明度 stroke: #1d39c4, // 鱼眼边框的颜色 strokeOpacity: 0.8, // 边框的透明度 lineWidth: 1.5, // 边框的线宽 shadowColor: #1d39c4, // 阴影颜色 shadowBlur: 10, // 阴影的模糊半径 shadowOffsetX: 0, // 阴影的水平偏移 shadowOffsetY: 0, // 阴影的垂直偏移 cursor: pointer, // 鼠标悬停时的指针样式 }, nodeStyle: { // 节点基础样式 size: 40, // 节点大小 fill: #d6e4ff, // 节点填充颜色 stroke: #2f54eb, // 节点边框颜色 lineWidth: 2, // 节点边框宽度 shadowColor: #2f54eb, // 节点阴影颜色 shadowBlur: 5, // 节点阴影模糊半径 cursor: pointer, // 鼠标悬停时的指针样式 // 标签样式 label: true, // 是否显示标签 labelFontSize: 14, // 标签字体大小 labelFontWeight: bold, // 标签字体粗细 labelFill: #1d39c4, // 标签文字颜色 labelBackground: true, // 是否显示标签背景 labelBackgroundFill: #fff, // 标签背景填充颜色 labelBackgroundStroke: #1d39c4, // 标签背景边框颜色 labelBackgroundOpacity: 0.8, // 标签背景透明度 labelBackgroundPadding: [4, 8, 4, 8], // 标签背景内边距 [上,右,下,左] // 图标样式 icon: true, // 是否显示图标 iconFontFamily: iconfont, // 图标字体 iconText: \ue6f6, // 图标的 Unicode 编码 iconFill: #1d39c4, // 图标颜色 iconSize: 16, // 图标大小 iconFontWeight: normal, // 图标字体粗细 }, }, ], });官方文档中该示例对应的完整可运行版本含 5 个节点、5 条边的图数据与graph.render()import { Graph } from antv/g6; const graph new Graph({ container: container, width: 400, height: 300, data: { nodes: [ { id: node-1, style: { x: 150, y: 100 } }, { id: node-2, style: { x: 250, y: 100 } }, { id: node-3, style: { x: 200, y: 180 } }, { id: node-4, style: { x: 120, y: 180 } }, { id: node-5, style: { x: 280, y: 180 } }, ], edges: [ { id: edge-1, source: node-1, target: node-2 }, { id: edge-2, source: node-1, target: node-3 }, { id: edge-3, source: node-2, target: node-3 }, { id: edge-4, source: node-3, target: node-4 }, { id: edge-5, source: node-3, target: node-5 }, ], }, node: { style: { size: 30, fill: #e6f7ff, stroke: #1890ff, lineWidth: 1, label: false, icon: false, }, }, edge: { style: { stroke: #91d5ff, lineWidth: 1, }, }, plugins: [ { type: fisheye, key: fisheye, r: 100, d: 2, style: { fill: #2f54eb, fillOpacity: 0.2, stroke: #1d39c4, strokeOpacity: 0.8, lineWidth: 1.5, shadowColor: #1d39c4, shadowBlur: 10, shadowOffsetX: 0, shadowOffsetY: 0, cursor: pointer, }, nodeStyle: { size: 40, fill: #d6e4ff, stroke: #2f54eb, lineWidth: 2, shadowColor: #2f54eb, shadowBlur: 5, cursor: pointer, label: true, labelFontSize: 14, labelFontWeight: bold, labelFill: #1d39c4, labelBackground: true, labelBackgroundFill: #fff, labelBackgroundStroke: #1d39c4, labelBackgroundOpacity: 0.8, labelBackgroundPadding: [4, 8, 4, 8], icon: true, iconFontFamily: iconfont, iconText: \ue6f6, iconFill: #1d39c4, iconSize: 16, iconFontWeight: normal, }, }, ], }); graph.render();实际案例在关系大图上使用鱼眼官方文档提供了一个真实场景案例——基于relations.json关系数据节点大小由id长度动态计算使用分组调色板着色并接入drag-canvas行为与鱼眼插件透镜内显示标签和图标import { Graph, iconfont } from antv/g6; const style document.createElement(style); style.innerHTML import url(${iconfont.css});; document.head.appendChild(style); fetch(https://assets.antv.antgroup.com/g6/relations.json) .then((res) res.json()) .then((data) { const graph new Graph({ container: container, autoFit: view, data, node: { style: { size: (datum) datum.id.length * 2 10, label: false, labelText: (datum) datum.id, labelBackground: true, icon: false, iconFontFamily: iconfont, iconText: \ue6f6, iconFill: #fff, }, palette: { type: group, field: (datum) datum.id, color: [#1783FF, #00C9C9, #F08F56, #D580FF], }, }, edge: { style: { stroke: #e2e2e2, }, }, plugins: [{ key: fisheye, type: fisheye, nodeStyle: { label: true, icon: true } }], }); graph.render(); });说明iconfont是 G6 内置的图标字体资源为节点图标提供字体定义关系数据也可替换为仓库自带的 packages/g6/tests/dataset/relations.json 进行本地实验。底层原理鱼眼畸变算法与渲染流程G6 的 Fisheye 插件本质是一个继承自BasePlugin的运行时插件类export class Fisheye extends BasePluginFisheyeOptions见 packages/g6/src/plugins/fisheye/index.ts并在 packages/g6/src/plugins/index.ts 统一导出注册。透镜渲染透镜是一个绘制在transient瞬态图层上的Circle圆形元素index.ts首次创建时new Circle({ style })并appendChild到瞬态层之后每次移动只更新位置size: r * 2与畸变百分比标签。这样透镜本身不会污染主画布的元素树销毁时随插件destroy()一并清除。畸变映射公式renderFocusElementsindex.ts对半径r内的每个节点执行非线性映射分子 (d 1) * r 放大后的距离 分子 * 原始距离 / (d * 原始距离 r) 新位置 圆心 放大后的距离 * (节点相对圆心的单位方向向量)当节点恰好在圆心距离为 0时映射后仍在圆心当节点在透镜边缘距离 r时放大后的距离 r即边缘节点保持原位与透镜外上下文无缝衔接d越大靠近圆心的节点被拉伸得越远形成更明显的“放大镜”效果。这也是鱼眼透镜能与外部上下文平滑过渡、不产生视觉断裂的根本原因。样式更新与差异计算updateStyleindex.ts利用arrayDiff对比上一次与当前放大节点集合的enter / keep / exit差异进入或保持的节点应用放大后的样式退出的节点恢复为进入透镜前记录的原始样式prevOriginStyleMap随后更新这些节点关联的边保证边端点与节点新位置同步实现拖拽过程中的平滑过渡。事件系统与手势绑定事件绑定bindEvents遵循“同一手势只绑定一个功能”的原则trigger为click/drag时监听画布CLICK为pointermove时监听POINTER_MOVE需要拖拽时监听DRAG_START/DRAG_END并按优先级选择DRAG处理函数移动/调半径/调畸变滚轮缩放监听原生WHEEL事件并设置{ passive: false }以便preventDefault生效滚轮/拖拽的有效性校验要求鼠标位置位于透镜半径r内见isWheelValid、isDragValid避免误操作。插件还实现了update(options)与destroy()index.ts更新时先解绑旧事件、合并新配置、再重新绑定运行时动态调整参数无需重建实例。运行时动态更新与参数调试Fisheye 插件配置了key后即可通过 G6 的插件管理能力在运行时获取实例或更新参数const graph new Graph({ plugins: [{ type: fisheye, key: fisheye }], }); // 运行时更新切换移动方式为 click调整畸变因子 graph.updatePlugin({ key: fisheye, trigger: click, d: 2.5, }); graph.render(); // 获取插件实例类型为 Fisheye const fisheye graph.getPluginInstance(fisheye);官方文档配套的交互演示packages/site/common/api/plugins/fisheye.md正是利用graph.updatePlugin({ key: fisheye, [property]: value })配合 GUI 面板实时调节trigger、r、d、scaleRBy、scaleDBy、showDPercent、preventDefault等参数非常适合作为理解各配置项手感差异的调试入口。测试验证与快照保障仓库为 Fisheye 插件提供了完整的单元测试 packages/g6/tests/unit/plugins/fisheye.spec.ts覆盖了pointermove/drag/click三种方式移动透镜的快照滚轮与拖拽调节半径scaleRBy与畸变因子scaleDBy的增大/缩小行为showDPercent开关对畸变百分比标签的影响自定义透镜样式如虚线lineDash: [5, 5]与节点样式如halo: true的渲染效果。测试通过dispatchCanvasEvent模拟鼠标与滚轮事件、通过toMatchSnapshot对比渲染结果是验证插件行为、防止回归的重要参考。对应的 demo 入口为 packages/g6/tests/demos/plugin-fisheye.ts可在本地pnpm dev环境下直接体验。小结Fisheye 鱼眼放大镜是 G6 内置插件中实现 focuscontext 交互最直接的方案通过trigger控制透镜移动方式r/d控制放大范围与强度scaleRBy/scaleDBy支持运行时交互微调style/nodeStyle提供视觉定制updatePlugin支持运行时动态改参。结合本文给出的完整代码示例与源码原理分析你可以快速在关系图、知识图谱、组织架构等可视化场景中落地局部聚焦能力。【免费下载链接】G6♾ A Graph Visualization Framework in JavaScript.项目地址: https://gitcode.com/gh_mirrors/g6/G6创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表