From 56cb08602df6fdf2fd635985bf81f09fa373a601 Mon Sep 17 00:00:00 2001 From: Yanyan-Wang Date: Mon, 30 Oct 2023 18:39:50 +0800 Subject: [PATCH] fix: update lod-controller disableLod --- packages/g6/src/item/node.ts | 17 +++- packages/g6/src/runtime/controller/item.ts | 2 +- packages/g6/src/runtime/controller/layout.ts | 22 ++--- packages/g6/src/runtime/controller/plugin.ts | 8 +- packages/g6/src/runtime/graph.ts | 29 ++++-- .../src/stdlib/plugin/lodController/index.ts | 95 ++++++++----------- packages/g6/src/types/layout.ts | 4 +- packages/g6/tests/demo/item/label.ts | 31 +++--- 8 files changed, 115 insertions(+), 93 deletions(-) diff --git a/packages/g6/src/item/node.ts b/packages/g6/src/item/node.ts index 4e6602882f..bb42ba5e29 100644 --- a/packages/g6/src/item/node.ts +++ b/packages/g6/src/item/node.ts @@ -174,6 +174,10 @@ export default class Node extends Item { isNaN(position.z as number) ) return; + const viewportPosition = graph.getViewportByCanvas(position); + labelGroup.style.x = viewportPosition.x; + labelGroup.style.y = viewportPosition.y; + labelGroup.style.z = viewportPosition.z || 0; if (animate && !disableAnimate && animates?.update) { const groupAnimates = animates.update.filter( ({ shapeId, fields = [] }) => @@ -199,10 +203,6 @@ export default class Node extends Item { group.style.x = position.x; group.style.y = position.y; group.style.z = position.z; - const viewportPosition = graph.getViewportByCanvas({ x, y, z }); - labelGroup.style.x = viewportPosition.x; - labelGroup.style.y = viewportPosition.y; - labelGroup.style.z = viewportPosition.z || 0; onfinish(displayModel.id, !animate); } /** @@ -214,7 +214,14 @@ export default class Node extends Item { } const { graph, group, labelGroup, displayModel, shapeMap, renderExt } = this; - const [x, y, z] = group.getPosition(); + + let [x, y, z] = group.getPosition(); + if (group.getAnimations().length) { + const { x: dataX, y: dataY, z: dataZ } = displayModel.data; + x = dataX as number; + y = dataY as number; + z = dataZ as number; + } const zoom = graph.getZoom(); const { x: vx, y: vy, z: vz } = graph.getViewportByCanvas({ x, y, z }); if (labelGroup.style.x !== vx) { diff --git a/packages/g6/src/runtime/controller/item.ts b/packages/g6/src/runtime/controller/item.ts index 5222743c40..7b8330f822 100644 --- a/packages/g6/src/runtime/controller/item.ts +++ b/packages/g6/src/runtime/controller/item.ts @@ -1239,7 +1239,7 @@ export class ItemController { return { id, data: { - ...item.displayModel, + ...item.displayModel.data, ...item.renderExt.mergedStyles, lodLevels: item.lodLevels, }, diff --git a/packages/g6/src/runtime/controller/layout.ts b/packages/g6/src/runtime/controller/layout.ts index 2d88ac6db2..fc216c8607 100644 --- a/packages/g6/src/runtime/controller/layout.ts +++ b/packages/g6/src/runtime/controller/layout.ts @@ -108,19 +108,19 @@ export class LayoutController { animationEffectTiming = { duration: 1000, } as Partial, - preset, + presetLayout, execute, ...rest } = options; - // preset layout + // presetLayout layout const nodesWithPosition = await this.presetLayout( layoutData, nodeSize, width, height, center, - preset, + presetLayout, params, layoutGraphCore, ); @@ -160,16 +160,16 @@ export class LayoutController { ); } } else { - const { preset } = options; + const { presetLayout } = options; - // preset layout + // presetLayout layout const nodesWithPosition = await this.presetLayout( layoutData, nodeSize, width, height, center, - preset, + presetLayout, params, layoutGraphCore, ); @@ -335,24 +335,24 @@ export class LayoutController { width, height, center, - preset, + presetLayout, params, layoutGraphCore, ) => { - // preset has higher priority than the positions in data - if (preset?.type) { + // presetLayout has higher priority than the positions in data + if (presetLayout?.type) { const presetPositions = await this.layoutOnce( layoutData, nodeSize, width, height, center, - preset, + presetLayout, params, layoutGraphCore, ); presetPositions.nodes.forEach((node) => { - layoutGraphCore.updateNodeData(node.id, { + layoutGraphCore.mergeNodeData(node.id, { x: node.data.x, y: node.data.y, }); diff --git a/packages/g6/src/runtime/controller/plugin.ts b/packages/g6/src/runtime/controller/plugin.ts index d7f8018f23..4abe8c6937 100644 --- a/packages/g6/src/runtime/controller/plugin.ts +++ b/packages/g6/src/runtime/controller/plugin.ts @@ -10,6 +10,7 @@ type Listener = (event: IG6GraphEvent) => void; const REQUIRED_PLUGINS = [ { + key: 'lod-controller', type: 'lod-controller', pluginClass: LodController, }, @@ -90,6 +91,11 @@ export class PluginController { ) ) { plugins.push(required.type); + + if (!this.graph.specification.plugins) { + this.graph.specification.plugins = []; + } + this.graph.specification.plugins.push(required); } }); @@ -170,7 +176,7 @@ export class PluginController { } if (action === 'update') { - pluginCfgs.forEach(this.updatePlugin); + pluginCfgs.forEach(this.updatePlugin.bind(this)); return; } } diff --git a/packages/g6/src/runtime/graph.ts b/packages/g6/src/runtime/graph.ts index 9c79eb1ac9..026374b848 100644 --- a/packages/g6/src/runtime/graph.ts +++ b/packages/g6/src/runtime/graph.ts @@ -2020,7 +2020,10 @@ export class Graph /** * Layout the graph (with current configurations if cfg is not assigned). */ - public async layout(options?: LayoutOptions, disableAnimate = false) { + public async layout( + options?: Partial, + disableAnimate = false, + ) { this.emit('beforelayout'); const { graphCore } = this.dataController; const formattedOptions = { @@ -2285,12 +2288,15 @@ export class Graph | PluginBase, ) { const { plugins } = this.specification; - const { key } = plugin; + const { key, type } = plugin as { + key: string; + type: string; + [cfg: string]: unknown; + }; if (!key) { console.warn( - 'Update plugin failed, the key for the plugin to be updated should be assign.', + `The key for the plugin is not found. G6 will update the first plugin with type ${type}`, ); - return; } if (!plugins) { console.warn( @@ -2299,12 +2305,21 @@ export class Graph return; } const oldPlugin = plugins?.find((p) => { - if (typeof p === 'string') return p === key; - return p.key === key; + if (typeof p === 'string') return p === key || p === type; + return ( + p.key === key || + ( + p as { + key: string; + type: string; + [cfg: string]: unknown; + } + ).type === type + ); }); if (!oldPlugin) { console.warn( - 'Update plugin failed, the key for the plugin to be updated should be assign.', + `Update plugin failed, the plugin with key ${key} or type ${type} is not found.`, ); return; } diff --git a/packages/g6/src/stdlib/plugin/lodController/index.ts b/packages/g6/src/stdlib/plugin/lodController/index.ts index d71fb77049..4438c9159c 100644 --- a/packages/g6/src/stdlib/plugin/lodController/index.ts +++ b/packages/g6/src/stdlib/plugin/lodController/index.ts @@ -68,6 +68,7 @@ export class LodController extends Base { } public getEvents() { + if (this.graph.rendererType === 'webgl-3d') return; return { afterrender: this.onAfterRender, afterlayout: this.onAfterLayout, @@ -81,47 +82,10 @@ export class LodController extends Base { } protected onAfterRender = () => { - this.clearCache(); // show the shapes with lod when diableLod is true const { graph, options } = this; - const graphZoom = graph.getZoom(); - if (options.disableLod) { - const models = graph.getAllNodesData().concat(graph.getAllEdgesData()); - models.forEach((model) => { - const displayModel = this.getDisplayModel(model.id); - const { lodLevels, ...others } = displayModel.data; - const lodLevelsEmpty = isEmptyObj(lodLevels); - const currentZoomLevel = lodLevelsEmpty - ? 0 - : getZoomLevel(lodLevels as any, graphZoom); - const shapeIdsToShow = []; - Object.keys(others).forEach((shapeId) => { - if (shapeId === 'keyShape') return; - const val = others[shapeId] as any; - if ( - typeof val !== 'object' || - !Object.keys(val).length || - isArray(val) - ) { - return; - } - if (val.visible === false) return; - if ( - lodLevelsEmpty || - val.lod === 'auto' || - val.lod > currentZoomLevel - ) { - shapeIdsToShow.push(shapeId); - } - }); - if (shapeIdsToShow.length) { - graph.showItem(model.id, { - shapeIds: shapeIdsToShow, - disableAnimate: options.disableAnimate, - }); - } - }); - } + + this.clearCache(); this.debounce = 80; if (options.debounce === undefined || options.debounce === 'auto') { @@ -156,7 +120,7 @@ export class LodController extends Base { private updateVisible = (zoomRatio = 1) => { const { graph, cacheViewModels, options } = this; - const { cellSize, numberPerCell, disableAnimate } = options; + const { cellSize, numberPerCell, disableAnimate, disableLod } = options; const graphZoom = graph.getZoom(); const { inView } = cacheViewModels || this.groupItemsByView(1); @@ -173,7 +137,7 @@ export class LodController extends Base { const lodInvisibleIds = new Map(); inView.forEach((model) => { const displayModel = this.getDisplayModel(model.id); - const { lodLevels, ...others } = displayModel.data; + const { lodLevels, x, y, z, ...others } = displayModel.data; const lodLevelsEmpty = isEmptyObj(lodLevels); const currentZoomLevel = lodLevelsEmpty ? 0 @@ -220,8 +184,8 @@ export class LodController extends Base { const { center } = bounds; const param = graphZoom / cellSize; // rowIdx = (center[i] * graphZoom + offset[i]) - offset[i] / cellSize = center[i] * param - const rowIdx = Math.floor(center[0] * param); - const colIdx = Math.floor(center[1] * param); + const rowIdx = Math.floor((center[0] || x) * param); + const colIdx = Math.floor((center[1] || y) * param); const cellIdx = `${rowIdx}-${colIdx}`; const cellNodeIds = cells.get(cellIdx) || []; cellNodeIds.push(model.id); @@ -253,13 +217,14 @@ export class LodController extends Base { const { lodVisibleShapeIds, autoVisibleShapeIds, invisibleShapeIds } = candidateShapeMap.get(id); - if (invisibleShapeIds.length) { + if (!disableLod && invisibleShapeIds.length) { graph.hideItem(id, { shapeIds: invisibleShapeIds, disableAnimate }); } const item = graph.itemController.itemMap.get(id); if ( - item.labelGroup.children.length && - (rest > 0 || (zoomRatio >= 1 && this.shownIds.has(id))) + disableLod || + (item.labelGroup.children.length && + (rest > 0 || (zoomRatio >= 1 && this.shownIds.has(id)))) ) { const shapeIdsToShow = lodVisibleShapeIds.concat(autoVisibleShapeIds); if (shapeIdsToShow.length) { @@ -269,7 +234,7 @@ export class LodController extends Base { }); } if (this.labelPositionDirty.has(id)) { - item.updateLabelPosition(); + item.updateLabelPosition(disableLod); this.labelPositionDirty.delete(id); } shownIds.set(id, 1); @@ -279,7 +244,7 @@ export class LodController extends Base { lodVisibleShapeIds.includes('labelShape') && this.labelPositionDirty.has(id) ) { - item.updateLabelPosition(); + item.updateLabelPosition(disableLod); this.labelPositionDirty.delete(id); } lodVisibleShapeIds.length && @@ -287,17 +252,20 @@ export class LodController extends Base { shapeIds: lodVisibleShapeIds, disableAnimate, }); - autoVisibleShapeIds.length && + if (!disableLod && autoVisibleShapeIds.length) { graph.hideItem(id, { shapeIds: autoVisibleShapeIds, disableAnimate, }); + } } }); }); - lodInvisibleIds.forEach((shapeIds, id) => { - shapeIds.length && graph.hideItem(id, { shapeIds, disableAnimate }); - }); + if (!disableLod) { + lodInvisibleIds.forEach((shapeIds, id) => { + shapeIds.length && graph.hideItem(id, { shapeIds, disableAnimate }); + }); + } this.shownIds = shownIds; }; @@ -322,9 +290,10 @@ export class LodController extends Base { if ( !item || !item.labelGroup.children.length || - item.labelGroup.style.visibility === 'hidden' || !item.shapeMap.labelShape || - item.shapeMap.labelShape.style.visibility === 'hidden' + (!options.disableLod && + (item.labelGroup.style.visibility === 'hidden' || + item.shapeMap.labelShape.style.visibility === 'hidden')) ) { return; } @@ -333,7 +302,7 @@ export class LodController extends Base { if (!labelShape) return; const updatePosition = () => { // adjust labels'positions for visible items - item.updateLabelPosition(); + item.updateLabelPosition(options.disableLod); this.labelPositionDirty.delete(model.id); }; const { visible, lod } = labelShape; @@ -445,6 +414,11 @@ export class LodController extends Base { inView = []; outView = []; models.forEach((model) => { + if (!this.modelCanvasIdxMap.get(model.id)) { + outView.push(model); + if (!previousOutView.has(model.id)) newlyOutView.push(model); + return; + } const { rowIdx, colIdx } = this.modelCanvasIdxMap.get(model.id); if (atBoundary(rowIdx, colIdx)) { const renderBounds = this.getRenderBBox(model.id); @@ -468,6 +442,10 @@ export class LodController extends Base { // zoom-out const outViewNew = []; outView.forEach((model) => { + if (!this.modelCanvasIdxMap.get(model.id)) { + outViewNew.push(model); + return; + } const { rowIdx, colIdx } = this.modelCanvasIdxMap.get(model.id); if (atBoundary(rowIdx, colIdx)) { const renderBounds = this.getRenderBBox(model.id); @@ -490,6 +468,11 @@ export class LodController extends Base { // zoom-in const inViewNew = []; inView.forEach((model) => { + if (!this.modelCanvasIdxMap.get(model.id)) { + outView.push(model); + newlyOutView.push(model); + return; + } const { rowIdx, colIdx } = this.modelCanvasIdxMap.get(model.id); if (atBoundary(rowIdx, colIdx)) { const renderBounds = this.getRenderBBox(model.id); @@ -524,6 +507,7 @@ export class LodController extends Base { const cellIdx = `${rowIdx}-${colIdx}`; const cell = canvasCells.get(cellIdx) || []; cell.push(model.id); + canvasCells.set(cellIdx, cell); idxMap.set(model.id, { rowIdx, colIdx }); }); graph.getAllEdgesData().forEach((model) => { @@ -535,6 +519,7 @@ export class LodController extends Base { const cellIdx = `${centerRowIdx}-${centerColIdx}`; const cell = canvasCells.get(cellIdx) || []; cell.push(model.id); + canvasCells.set(cellIdx, cell); idxMap.set(model.id, { rowIdx: centerRowIdx, colIdx: centerColIdx }); }); this.modelCanvasIdxMap = idxMap; diff --git a/packages/g6/src/types/layout.ts b/packages/g6/src/types/layout.ts index f97150d91b..a745462d80 100644 --- a/packages/g6/src/types/layout.ts +++ b/packages/g6/src/types/layout.ts @@ -59,7 +59,7 @@ export type ImmediatelyInvokedLayoutOptions = { */ execute: (graph: GraphCore, options?: any) => Promise; } & Animatable & { - preset?: PureLayoutOptions; + presetLayout?: Partial; }; type CustomLayout = { @@ -70,7 +70,7 @@ type CustomLayout = { export type StandardLayoutOptions = PureLayoutOptions & Animatable & Workerized & { - preset?: PureLayoutOptions; + presetLayout?: Partial; }; export type LayoutOptions = diff --git a/packages/g6/tests/demo/item/label.ts b/packages/g6/tests/demo/item/label.ts index 067e1ddab9..a659fb80f4 100644 --- a/packages/g6/tests/demo/item/label.ts +++ b/packages/g6/tests/demo/item/label.ts @@ -1731,7 +1731,7 @@ export default ( plugins: [ // { // type: 'lod-controller', - // // disableLod: true, + // disableLod: true, // // disableAnimate: false, // }, ], @@ -1821,8 +1821,10 @@ export default ( // }, }, labelBackgroundShape: { - opacity: 0.1, - fill: '#00f', + opacity: 1, + fill: '#fff', + // opacity: 0.1, + // fill: '#00f', // lod: model.id === 'node1' ? 0 : 'auto', }, iconShape: { @@ -1832,9 +1834,9 @@ export default ( }; }, layout: { - preset: { - type: 'concentric', - }, + // presetLayout: { + // type: 'concentric', + // }, type: 'force', linkDistance: 100, edgeStrength: 1000, @@ -1845,6 +1847,8 @@ export default ( }, }); + let disable = false; + graph.on('canvas:click', (e) => { // const { x, y } = graph.getNodeData('Mlle.Gillenormand')?.data || {}; // graph.updateData('node', { @@ -1867,10 +1871,15 @@ export default ( // graph.hideItem('Marius'); // graph.showItem('Marius'); - console.log( - 'click', - graph.itemController.itemMap.get('Gervais')?.labelGroup, - ); + disable = !disable; + graph.updatePlugin({ + key: 'lod-controller', + type: 'lod-controller', + disableLod: disable, + }); + + // console.log(graph.itemController.itemMap.get('Gillenormand')); + // console.log(graph.itemController.itemMap.get('Child2')); }); let allData = { ...data }; graph.on('node:click', (e) => { @@ -1897,7 +1906,7 @@ export default ( }; graph.changeData(allData, 'mergeReplace', false); graph.layout({ - preset: {}, + presetLayout: {}, }); }); return graph;