Skip to content

Commit

Permalink
fix(module:graph): resolve minimap memory leaks (#7052)
Browse files Browse the repository at this point in the history
  • Loading branch information
arturovt committed Nov 12, 2021
1 parent 567b0b3 commit f93960c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 28 deletions.
46 changes: 26 additions & 20 deletions components/graph/core/minimap.ts
Expand Up @@ -14,37 +14,27 @@ import { NzZoomTransform } from '../interface';
const FRAC_VIEWPOINT_AREA = 0.8;

export class Minimap {
private minimap: HTMLElement;
private canvas: HTMLCanvasElement;
private canvasRect: ClientRect;
private canvasBuffer: HTMLCanvasElement;
private minimapSvg: SVGSVGElement;
private viewpoint: SVGRectElement;
private scaleMinimap!: number;
private scaleMain!: number;
private maxWidth: number;
private translate!: [number, number];
private viewpointCoord: { x: number; y: number };
private minimapSize!: { width: number; height: number };
private labelPadding: number;

private svg: SVGSVGElement;
private zoomG: SVGGElement;
private mainZoom: ZoomBehavior<NzSafeAny, NzSafeAny>;
private unlisteners: VoidFunction[] = [];

constructor(
svg: SVGSVGElement,
zoomG: SVGGElement,
mainZoom: ZoomBehavior<NzSafeAny, NzSafeAny>,
minimap: HTMLElement,
maxWidth: number,
labelPadding: number
private svg: SVGSVGElement,
private zoomG: SVGGElement,
private mainZoom: ZoomBehavior<NzSafeAny, NzSafeAny>,
private minimap: HTMLElement,
private maxWidth: number,
private labelPadding: number
) {
this.svg = svg;
this.labelPadding = labelPadding;
this.zoomG = zoomG;
this.mainZoom = mainZoom;
this.maxWidth = maxWidth;
const minimapElement = select(minimap);
const minimapSvgElement = minimapElement.select('svg');
const viewpointElement = minimapSvgElement.select('rect');
Expand All @@ -61,7 +51,8 @@ export class Minimap {
this.updateViewpoint();
};
this.viewpointCoord = { x: 0, y: 0 };
const dragEvent = drag().subject(Object).on('drag', handleEvent);
const subject = drag().subject(Object);
const dragEvent = subject.on('drag', handleEvent);
viewpointElement.datum(this.viewpointCoord as NzSafeAny).call(dragEvent as NzSafeAny);

// Make the minimap clickable.
Expand All @@ -72,13 +63,22 @@ export class Minimap {
}
handleEvent(event);
});
this.unlisteners.push(() => {
subject.on('drag', null);
minimapSvgElement.on('click', null);
});
this.viewpoint = viewpointElement.node() as SVGRectElement;
this.minimapSvg = minimapSvgElement.node() as SVGSVGElement;
this.minimap = minimap;
this.canvasBuffer = minimapElement.select('canvas.buffer').node() as HTMLCanvasElement;
this.update();
}

destroy(): void {
while (this.unlisteners.length) {
this.unlisteners.pop()!();
}
}

private minimapOffset(): { x: number; y: number } {
return {
x: (this.canvasRect.width - this.minimapSize.width) / 2,
Expand Down Expand Up @@ -190,7 +190,7 @@ export class Minimap {
zoomGSelection.attr('transform', zoomTransform);

const image = document.createElement('img');
image.onload = () => {
const onLoad = (): void => {
// Draw the svg content onto the buffer canvas.
const context = this.canvasBuffer.getContext('2d');
context!.clearRect(0, 0, this.canvasBuffer.width, this.canvasBuffer.height);
Expand All @@ -204,7 +204,13 @@ export class Minimap {
[this.canvas, this.canvasBuffer] = [this.canvasBuffer, this.canvas];
});
};

image.addEventListener('load', onLoad);
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;

this.unlisteners.push(() => {
image.removeEventListener('load', onLoad);
});
}

/**
Expand Down
16 changes: 8 additions & 8 deletions components/graph/graph-minimap.component.ts
Expand Up @@ -3,7 +3,7 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { ChangeDetectionStrategy, Component, ElementRef } from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, OnDestroy } from '@angular/core';

import { ZoomBehavior } from 'd3-zoom';

Expand Down Expand Up @@ -40,25 +40,25 @@ import { NzZoomTransform } from './interface';
'[class.nz-graph-minimap]': 'true'
}
})
export class NzGraphMinimapComponent {
export class NzGraphMinimapComponent implements OnDestroy {
minimap?: Minimap;
constructor(private elementRef: ElementRef<HTMLElement>) {}

ngOnDestroy(): void {
this.minimap?.destroy();
}

init(containerEle: ElementRef, zoomBehavior: ZoomBehavior<NzSafeAny, NzSafeAny>): void {
const svgEle = containerEle.nativeElement.querySelector('svg');
const zoomEle = containerEle.nativeElement.querySelector('svg > g');
this.minimap = new Minimap(svgEle, zoomEle, zoomBehavior, this.elementRef.nativeElement, 150, 0);
}

zoom(transform: NzZoomTransform): void {
if (this.minimap) {
this.minimap.zoom(transform);
}
this.minimap?.zoom(transform);
}

update(): void {
if (this.minimap) {
this.minimap.update();
}
this.minimap?.update();
}
}

0 comments on commit f93960c

Please sign in to comment.