Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
HARP-11780: Make events non-global to allow garbage collection of Map…
Browse files Browse the repository at this point in the history
…View and DataSource (#1807)
  • Loading branch information
ninok committed Aug 31, 2020
1 parent 89f4c03 commit 7436af3
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 54 deletions.
8 changes: 6 additions & 2 deletions @here/harp-mapview/lib/DataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { MapView } from "./MapView";
import { Tile } from "./Tile";

const logger = LoggerManager.instance.create("DataSource");
const UPDATE_EVENT = { type: "update" };

/**
* Options for a {@link DataSource}.
Expand Down Expand Up @@ -84,6 +83,11 @@ export interface DataSourceOptions {
* Derive a class from `DataSource` to contribute data and geometries to the {@link MapView}.
*/
export abstract class DataSource extends THREE.EventDispatcher {
/**
* Keep the update event here to avoid a global reference to the datasource (and thus prevent garbage collection).
*/
private readonly UPDATE_EVENT = { type: "update" };

/**
* A counter to generate unique names for each `DataSource`, if no name is provided in the
* constructor.
Expand Down Expand Up @@ -626,6 +630,6 @@ export abstract class DataSource extends THREE.EventDispatcher {
* Sends a request to the {@link MapView} to redraw the scene.
*/
requestUpdate() {
this.dispatchEvent(UPDATE_EVENT);
this.dispatchEvent(this.UPDATE_EVENT);
}
}
122 changes: 70 additions & 52 deletions @here/harp-mapview/lib/MapView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,37 +187,10 @@ const DEFAULT_STENCIL_VALUE = 1;
* The type of `RenderEvent`.
*/
export interface RenderEvent extends THREE.Event {
type:
| MapViewEventNames.Render
| MapViewEventNames.FirstFrame
| MapViewEventNames.FrameComplete
| MapViewEventNames.ThemeLoaded
| MapViewEventNames.AnimationStarted
| MapViewEventNames.AnimationFinished
| MapViewEventNames.MovementStarted
| MapViewEventNames.MovementFinished
| MapViewEventNames.ContextLost
| MapViewEventNames.ContextRestored
| MapViewEventNames.CopyrightChanged;
type: MapViewEventNames;
time?: number;
}

// Event type: cast needed to workaround wrong THREE.js typings.
const UPDATE: RenderEvent = { type: MapViewEventNames.Update } as any;
const RENDER_EVENT: RenderEvent = { type: MapViewEventNames.Render } as any;
const DID_RENDER_EVENT: RenderEvent = { type: MapViewEventNames.AfterRender } as any;
const FIRST_FRAME_EVENT: RenderEvent = { type: MapViewEventNames.FirstFrame } as any;
const FRAME_COMPLETE_EVENT: RenderEvent = { type: MapViewEventNames.FrameComplete } as any;
const THEME_LOADED_EVENT: RenderEvent = { type: MapViewEventNames.ThemeLoaded } as any;
const ANIMATION_STARTED_EVENT: RenderEvent = { type: MapViewEventNames.AnimationStarted } as any;
const ANIMATION_FINISHED_EVENT: RenderEvent = { type: MapViewEventNames.AnimationFinished } as any;
const MOVEMENT_STARTED_EVENT: RenderEvent = { type: MapViewEventNames.MovementStarted } as any;
const MOVEMENT_FINISHED_EVENT: RenderEvent = { type: MapViewEventNames.MovementFinished } as any;
const CONTEXT_LOST_EVENT: RenderEvent = { type: MapViewEventNames.ContextLost } as any;
const CONTEXT_RESTORED_EVENT: RenderEvent = { type: MapViewEventNames.ContextRestored } as any;
const COPYRIGHT_CHANGED_EVENT: RenderEvent = { type: MapViewEventNames.CopyrightChanged } as any;
const DISPOSE_EVENT: RenderEvent = { type: MapViewEventNames.Dispose } as any;

const cache = {
vector2: [new THREE.Vector2()],
vector3: [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
Expand Down Expand Up @@ -779,6 +752,51 @@ export interface LookAtParams {
* linked to datasources.
*/
export class MapView extends EventDispatcher {
/**
* Keep the events here to avoid a global reference to MapView (and thus prevent garbage collection).
*/
private readonly UPDATE_EVENT: RenderEvent = { type: MapViewEventNames.Update };
private readonly RENDER_EVENT: RenderEvent = { type: MapViewEventNames.Render };
private readonly DID_RENDER_EVENT: RenderEvent = { type: MapViewEventNames.AfterRender };
private readonly FIRST_FRAME_EVENT: RenderEvent = { type: MapViewEventNames.FirstFrame };
private readonly FRAME_COMPLETE_EVENT: RenderEvent = {
type: MapViewEventNames.FrameComplete
};

private readonly THEME_LOADED_EVENT: RenderEvent = {
type: MapViewEventNames.ThemeLoaded
};

private readonly ANIMATION_STARTED_EVENT: RenderEvent = {
type: MapViewEventNames.AnimationStarted
};

private readonly ANIMATION_FINISHED_EVENT: RenderEvent = {
type: MapViewEventNames.AnimationFinished
};

private readonly MOVEMENT_STARTED_EVENT: RenderEvent = {
type: MapViewEventNames.MovementStarted
};

private readonly MOVEMENT_FINISHED_EVENT: RenderEvent = {
type: MapViewEventNames.MovementFinished
};

private readonly CONTEXT_LOST_EVENT: RenderEvent = {
type: MapViewEventNames.ContextLost
};

private readonly CONTEXT_RESTORED_EVENT: RenderEvent = {
type: MapViewEventNames.ContextRestored
};

private readonly COPYRIGHT_CHANGED_EVENT: RenderEvent = {
type: MapViewEventNames.CopyrightChanged
};

private readonly DISPOSE_EVENT: RenderEvent = { type: MapViewEventNames.Dispose };

/**
* The instance of {@link MapRenderingManager} managing the rendering of the map. It is a public
* property to allow access and modification of some parameters of the rendering process at
Expand Down Expand Up @@ -1295,8 +1313,8 @@ export class MapView extends EventDispatcher {
*/
dispose(freeContext = true) {
// Enforce listeners that we are about to dispose.
DISPOSE_EVENT.time = Date.now();
this.dispatchEvent(DISPOSE_EVENT);
this.DISPOSE_EVENT.time = Date.now();
this.dispatchEvent(this.DISPOSE_EVENT);

this.m_disposed = true;

Expand Down Expand Up @@ -1533,8 +1551,8 @@ export class MapView extends EventDispatcher {
for (const dataSource of this.m_tileDataSources) {
dataSource.setTheme(this.m_theme);
}
THEME_LOADED_EVENT.time = Date.now();
this.dispatchEvent(THEME_LOADED_EVENT);
this.THEME_LOADED_EVENT.time = Date.now();
this.dispatchEvent(this.THEME_LOADED_EVENT);
this.update();
}

Expand Down Expand Up @@ -2475,8 +2493,8 @@ export class MapView extends EventDispatcher {
beginAnimation() {
if (this.m_animationCount++ === 0) {
this.update();
ANIMATION_STARTED_EVENT.time = Date.now();
this.dispatchEvent(ANIMATION_STARTED_EVENT);
this.ANIMATION_STARTED_EVENT.time = Date.now();
this.dispatchEvent(this.ANIMATION_STARTED_EVENT);
}
}

Expand All @@ -2489,8 +2507,8 @@ export class MapView extends EventDispatcher {
}

if (this.m_animationCount === 0) {
ANIMATION_FINISHED_EVENT.time = Date.now();
this.dispatchEvent(ANIMATION_FINISHED_EVENT);
this.ANIMATION_FINISHED_EVENT.time = Date.now();
this.dispatchEvent(this.ANIMATION_FINISHED_EVENT);
}
}

Expand Down Expand Up @@ -2843,7 +2861,7 @@ export class MapView extends EventDispatcher {
return;
}

this.dispatchEvent(UPDATE);
this.dispatchEvent(this.UPDATE_EVENT);

// Skip if update is already in progress
if (this.m_updatePending) {
Expand Down Expand Up @@ -3571,8 +3589,8 @@ export class MapView extends EventDispatcher {
return;
}

RENDER_EVENT.time = frameStartTime;
this.dispatchEvent(RENDER_EVENT);
this.RENDER_EVENT.time = frameStartTime;
this.dispatchEvent(this.RENDER_EVENT);

this.m_stencilValue = DEFAULT_STENCIL_VALUE;
this.m_renderOrderStencilValues.clear();
Expand Down Expand Up @@ -3774,8 +3792,8 @@ export class MapView extends EventDispatcher {
stats.appResults.set("firstFrame", frameStartTime);
}

FIRST_FRAME_EVENT.time = frameStartTime;
this.dispatchEvent(FIRST_FRAME_EVENT);
this.FIRST_FRAME_EVENT.time = frameStartTime;
this.dispatchEvent(this.FIRST_FRAME_EVENT);
}

this.m_visibleTiles.disposePendingTiles();
Expand Down Expand Up @@ -3823,8 +3841,8 @@ export class MapView extends EventDispatcher {
stats.addMemoryInfo();
}

DID_RENDER_EVENT.time = frameStartTime;
this.dispatchEvent(DID_RENDER_EVENT);
this.DID_RENDER_EVENT.time = frameStartTime;
this.dispatchEvent(this.DID_RENDER_EVENT);

// After completely rendering this frame, it is checked if this frame was the first complete
// frame, with no more tiles, geometry and labels waiting to be added, and no animation
Expand All @@ -3844,8 +3862,8 @@ export class MapView extends EventDispatcher {
}
}

FRAME_COMPLETE_EVENT.time = frameStartTime;
this.dispatchEvent(FRAME_COMPLETE_EVENT);
this.FRAME_COMPLETE_EVENT.time = frameStartTime;
this.dispatchEvent(this.FRAME_COMPLETE_EVENT);
}
}

Expand Down Expand Up @@ -4244,15 +4262,15 @@ export class MapView extends EventDispatcher {
private movementStarted() {
this.m_textElementsRenderer.movementStarted();

MOVEMENT_STARTED_EVENT.time = Date.now();
this.dispatchEvent(MOVEMENT_STARTED_EVENT);
this.MOVEMENT_STARTED_EVENT.time = Date.now();
this.dispatchEvent(this.MOVEMENT_STARTED_EVENT);
}

private movementFinished() {
this.m_textElementsRenderer.movementFinished();

MOVEMENT_FINISHED_EVENT.time = Date.now();
this.dispatchEvent(MOVEMENT_FINISHED_EVENT);
this.MOVEMENT_FINISHED_EVENT.time = Date.now();
this.dispatchEvent(this.MOVEMENT_FINISHED_EVENT);

// render at the next possible time.
if (!this.animating) {
Expand Down Expand Up @@ -4327,7 +4345,7 @@ export class MapView extends EventDispatcher {
}
}
this.m_copyrightInfo = newCopyrightInfo;
this.dispatchEvent(COPYRIGHT_CHANGED_EVENT);
this.dispatchEvent(this.COPYRIGHT_CHANGED_EVENT);
}

private getRenderedTilesCopyrightInfo(): CopyrightInfo[] {
Expand Down Expand Up @@ -4432,7 +4450,7 @@ export class MapView extends EventDispatcher {
* Note: The renderer `this.m_renderer` may not be initialized when this function is called.
*/
private readonly onWebGLContextLost = (event: Event) => {
this.dispatchEvent(CONTEXT_LOST_EVENT);
this.dispatchEvent(this.CONTEXT_LOST_EVENT);
logger.warn("WebGL context lost", event);
};

Expand All @@ -4442,7 +4460,7 @@ export class MapView extends EventDispatcher {
* Note: The renderer `this.m_renderer` may not be initialized when this function is called.
*/
private readonly onWebGLContextRestored = (event: Event) => {
this.dispatchEvent(CONTEXT_RESTORED_EVENT);
this.dispatchEvent(this.CONTEXT_RESTORED_EVENT);
if (this.m_renderer !== undefined) {
if (this.m_theme !== undefined && this.m_theme.clearColor !== undefined) {
this.m_renderer.setClearColor(new THREE.Color(this.m_theme.clearColor));
Expand Down

0 comments on commit 7436af3

Please sign in to comment.