ARTICLE DETAIL

资讯详情

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

cytoscape.js 集合原地移除元素:eles.unmerge() 方法与源码级原理详解

cytoscape.js 集合原地移除元素:eles.unmerge() 方法与源码级原理详解 数据可视化【免费下载链接】cytoscape.jsGraph theory (network) library for visualisation and analysis项目地址https://gitcode.com/gh_mirrors/cy/cytoscape.js点击查看免费下载eles.unmerge()是 cytoscape.js 中用于原地in-place从调用集合中移除元素的集合方法与eles.merge()互为逆操作。本文以官方 API 文档 unmerge.md 为主体结合源码实现与测试用例讲解其调用方式、性能特性、适用边界以及背后的map索引与末位元素补位实现原理帮助你安全、高效地管理自定义元素集合。方法概览eles.unmerge( eles | selector )将指定元素从调用集合中移除并且直接修改调用集合本身而不是返回一个新集合。因此它的返回值仍是原集合便于链式调用集合的length会随之减小eles[ i ]中的对应槽位也会被清空或调整。该方法声明在集合的原型方法集中源码位于 src/collection/filter.mjs属于集合构建与过滤collection building and filtering一族 API。参数说明unmerge接受两类参数参数形式含义说明单个元素从集合中移除该元素例如var e cy.$(#e); col.unmerge( e );集合collection依次移除集合中的每个元素内部通过unmergeOne()逐元素处理选择器字符串selector先将选择器对图中所有可变元素过滤再移除匹配元素等价于col.unmerge( cy.mutableElements().filter( selector ) )空值 / 未传参不做任何操作直接返回自身源码中if( !toRemove ){ return this; }从 src/collection/filter.mjs 的实现可以看出字符串选择器会在底层先转换为集合if( toRemove is.string( toRemove ) ){ let selector toRemove; toRemove cy.mutableElements().filter( selector ); }注意选择器是针对图中全部可变元素mutable elements即未被移除的节点与边进行过滤而不是针对调用集合本身过滤。也就是说col.unmerge(#e)等价于把图中 id 为e的元素如果它在col中从col移除如果该元素本就不在col中则调用不会产生任何效果。官方示例官方文档 unmerge.md 给出了两种典型用法均以cy.collection()创建的全新空集合作为操作对象传入集合参数var col cy.collection(); // new, empty collection var e cy.$(#e); col.merge( cy.nodes() ); // 先把图中所有节点并入 col col.unmerge( e ); // 再把 #e 节点从 col 中移除传入选择器参数var col cy.collection(); // new, empty collection col.merge( cy.nodes() ); // 先把图中所有节点并入 col col.unmerge(#e); // 用选择器形式移除 #e两种写法效果等价区别仅在于参数形态。使用选择器时代码更简洁但会触发一次针对全图元素的过滤运算。核心注意事项为什么官方强调仅用于自建集合官方文档对该方法标注了两个important-indicator级别的警告这是使用unmerge前必须理解的两条铁律该方法会修改调用集合本身。它与返回新集合的eles.filter()、eles.remove()语义完全不同——filter()返回一个新的、满足条件的集合原集合不受影响而unmerge会直接改变调用者。因此除非确实需要以原地方式回收集合以获得性能收益否则默认应优先考虑eles.filter()或eles.remove()这类非破坏性写法。只应在cy.collection()自建的新集合上使用。因为cy.$()、cy.nodes()等查询方法返回的集合通常来自图内部的查询结果直接对这些集合调用unmerge可能会无意中修改其他仍在使用的集合引用导致难以排查的副作用。官方建议通过cy.collection()创建独立集合后再进行 merge/unmerge 操作从而把影响范围控制在自己手里。为什么会有性能收益从实现看unmerge的查找与删除都围绕集合内部的_private.map索引进行。Collection是一个基于数组且带有 id → { ele, index } 映射表的数据结构src/collection/index.mjs 中Collection.prototype Object.create(Array.prototype)同时维护_private.map。unmergeOne通过map.get( id )在O(1) 时间内定位元素位置src/collection/filter.mjs随后由unmergeAt完成真正的移除。相比每次都构造全新数组的纯函数式写法在需要高频、增量维护一个临时集合例如动画帧内、渲染缓存队列、图算法中间结果时原地操作能显著减少对象分配与垃圾回收压力。源码级实现原理unmerge在 src/collection/filter.mjs 中由四个方法协作完成自底向上分别是1.unmergeAt(i)按下标移除并末位补位unmergeAt: function( i ){ let ele this[i]; let id ele.id(); let _p this._private; let map _p.map; // remove ele this[ i ] undefined; map.delete( id ); let unmergedLastEle i this.length - 1; // replace empty spot with last ele in collection if( this.length 1 !unmergedLastEle ){ let lastEleI this.length - 1; let lastEle this[ lastEleI ]; let lastEleId lastEle._private.data.id; this[ lastEleI ] undefined; this[ i ] lastEle; map.set( lastEleId, { ele: lastEle, index: i } ); } // the collection is now 1 ele smaller this.length--; return this; }这段实现有两个值得注意的设计O(1) 删除先把被删槽位置为undefined并从map中摘除索引如果被删的不是最后一个元素则把集合末尾元素搬移到空出的下标并同步更新map中该末尾元素的索引。这样避免了大数组删除中间元素时的整体平移开销代价是集合内元素顺序不再稳定。顺序稳定性由于末位补位机制unmerge之后集合内剩余元素的相对顺序可能发生变化末尾元素会被移动到被删位置。如果你的业务逻辑依赖集合顺序请改用filter()重建集合。2.unmergeOne(ele)按元素 id 定位并删除unmergeOne: function( ele ){ ele ele[0]; let _p this._private; let id ele._private.data.id; let map _p.map; let entry map.get( id ); if( !entry ){ return this; // no need to remove } let i entry.index; this.unmergeAt(i); return this; }它通过map直接命中元素在数组中的下标。若目标 id 不在映射表中元素本就不在集合内则安全地跳过不做任何修改。3.unmerge(toRemove)对外主入口unmerge: function( toRemove ){ let cy this._private.cy; if( !toRemove ){ return this; } if( toRemove is.string( toRemove ) ){ let selector toRemove; toRemove cy.mutableElements().filter( selector ); } for( let i 0; i toRemove.length; i ){ this.unmergeOne( toRemove[ i ] ); } return this; // chaining }逐个元素调用unmergeOne最终返回this以支持链式调用。4.unmergeBy(toRmFn)按谓词批量移除内部工具unmergeBy: function( toRmFn ){ for( let i this.length - 1; i 0; i-- ){ let ele this[i]; if( toRmFn(ele) ){ this.unmergeAt(i); } } return this; }unmergeBy是从后往前遍历并按条件移除的内部工具方法虽然没有出现在公开 API 文档中但在仓库内部被大量使用例如src/collection/algorithms/dijkstra.mjs 中移除自环边edges.unmergeBy( ele ele.isLoop() )src/collection/algorithms/bellman-ford.mjs 同样用于过滤自环src/collection/algorithms/karger-stein.mjs 的随机最小割算法中移除自环边。这说明原地删除这一能力正是图算法实现高性能中间集合管理的基石。与merge的对称关系unmerge与 merge.md 中讲解的eles.merge()是一对对称操作merge把元素并入调用集合按 id 去重已在集合中的元素不会重复添加unmerge把元素移出调用集合。两者都原地修改集合、都返回this支持链式调用、都被官方限定为仅用于cy.collection()自建集合。与之对应还有不修改原集合的纯函数版本eles.add( eles )返回新集合this.spawnSelf()不会污染原集合src/collection/filter.mjseles.not( eles )、eles.difference()、eles.xor()、eles.filter()等均返回新集合。当你只是想得到去掉某些元素之后的结果而不想动原集合时优先选择这些非破坏性 API。测试用例验证仓库测试文件 test/collection-building-and-filtering.mjs 中有两个针对unmerge的专门用例可作为行为契约的权威参考eles.unmerge()先构造cy.$(#n1, #n2)两元素集合逐一unmerge(n1)、unmerge(n2)每步断言hasElementWithId结果与eles.length同步递减最终长度为 0 且eles[0]、eles[1]均不存在。eles.unmerge() last ele验证先删末尾元素、再删剩余元素的场景确认即使删除的是末位元素补位逻辑与length收缩依然正确。这两个用例从正面印证了本文所述的核心行为元素确实从调用集合中移除、集合长度正确收缩、未删除元素仍然保留。典型应用场景虽然公开文档强调unmerge应谨慎使用但在仓库内部它仍是渲染与动画链路中的高频工具例如src/core/animation/step-all.mjs动画推进时把已完成的动画元素从待处理集合中原地摘除避免反复重建集合src/extensions/renderer/canvas/ele-texture-cache.mjs纹理缓存队列中移出已处理的元素src/extensions/renderer/canvas/layered-texture-cache.mjs清空分层纹理缓存出队集合src/core/index.mjs元素从图中移除时同步从_private.elements集合中摘除。可以看到临时集合 增量 merge/unmerge是 cytoscape.js 内部在渲染循环和算法中间态中控制对象分配、降低 GC 压力的标准做法——这正是官方文档所说performance in some cases的出处。实践建议小结默认使用非破坏 API日常业务中筛选子集用eles.filter()从图中删除元素用eles.remove()避免集合被意外修改。自建集合才用 unmerge需要原地维护集合时务必从cy.collection()空集合或cy.collection( eles, opts )起步不应对查询结果直接调用。cy.collection()的实现见 src/core/search.mjs无参时返回空集合传选择器/元素/数组时返回对应集合。留意顺序变化unmerge采用末位补位策略剩余元素顺序可能改变对顺序敏感的场景请改用filter()。配合 merge 使用col.merge( ... ).unmerge( ... )链式组合可高效维护一个与图状态同步的增量集合适合动画、临时选中集、渲染队列等高频场景。注意选择器语义col.unmerge(#e)中的选择器作用于全图可变元素而非col本身只移除col中已存在的元素未包含的元素会被安全忽略。赞分享数据可视化【免费下载链接】cytoscape.jsGraph theory (network) library for visualisation and analysis项目地址https://gitcode.com/gh_mirrors/cy/cytoscape.js点击查看免费下载相关推荐Cytoscape.js 元素类移除指南removeClass() 的用法、源码原理与性能优化Cytoscape.js 元素类移除指南removeClass 的用法、源码原理与性能优化 导读 eles.removeClass 是 Cytoscape.j数据可视化Cytoscape.js 元素类名操作全解析eles.addClass() 用法与源码级原理Cytoscape.js 元素类名操作全解析eles.addClass 用法与源码级原理 Cytoscape.js 中class类名是连接图元素与样式系数据可视化Cytoscape.js 集合事件监听器移除eles.removeListener() 方法详解与源码解析Cytoscape.js 集合事件监听器移除eles.removeListener 方法详解与源码解析 导读 在 Cytoscape.js 中 eles.r数据可视化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表