@equinor/esv-intersection
Version:
Intersection component package with testing and automatic documentation.
324 lines (284 loc) • 8.7 kB
text/typescript
import { IntersectionReferenceSystem } from './IntersectionReferenceSystem';
import { LayerManager } from './LayerManager';
import { Layer } from '../layers';
import { ControllerOptions } from './interfaces';
import { ZoomPanHandler } from './ZoomPanHandler';
import { LayerOptions, OnRescaleEvent, ReferenceSystemOptions } from '..';
import { Axis } from '../components';
import { overlay, Overlay } from './overlay';
import { HORIZONTAL_AXIS_MARGIN, VERTICAL_AXIS_MARGIN } from '../constants';
/**
* API for controlling data and layers
*/
export class Controller {
private _referenceSystem: IntersectionReferenceSystem | undefined;
private layerManager: LayerManager;
private _overlay: Overlay<Controller>;
/**
* Interface to control layers, reference system, axis and overlay. overlay is created on instantiation, does not currently support opt-out.
* @param options
* @param options.container (required) Currently only supports HTMLElement
* @param options.scaleOptions (optional) currently supports formats listed in examples below
* @example scaleOptions = { xMin: 0, xMax: 100, yMin: 0, yMax: 100 }
* @example scaleOptions = { xBounds: [0 , 100], yBounds: [0, 100] }
* @param options.axisOptions (optional) creates axis with supplied labels, currently only supports creating axis on instantiation
* @param options.layers (optional) list of layers
* @param options.path (optional) creates a reference system based on an array of 3d coordinates
* @param options.referenceSystem (optional) sets reference system, takes priority over path if both are supplied
*/
constructor(options: ControllerOptions) {
const {
container,
axisOptions,
scaleOptions,
referenceSystem,
layers,
path,
} = options;
this._referenceSystem =
referenceSystem || (path && new IntersectionReferenceSystem(path));
this._overlay = overlay(this, container);
this.layerManager = new LayerManager(
this._overlay.elm.node() as HTMLElement,
scaleOptions,
axisOptions,
);
if (layers) {
this.layerManager.addLayers(layers);
this.setOverlayZIndex(layers);
}
}
/**
* Sets reference system, overrides any existing reference systems in place
* @param referenceSystem IntersectionReferenceSystem
*/
setReferenceSystem(referenceSystem: IntersectionReferenceSystem): Controller {
this._referenceSystem = referenceSystem;
this.layerManager.setReferenceSystem(referenceSystem);
return this;
}
/**
* Creates new reference system based on path, overrides any existing reference systems in place
* @param path array of coords
* @param options optional
* @param options.trajectoryAngle (optional) angle in degrees
*/
updatePath(path: number[][], options?: ReferenceSystemOptions): Controller {
this.setReferenceSystem(new IntersectionReferenceSystem(path, options));
return this;
}
/**
* Clears data from all mounted layers
* @param includeReferenceSystem - (optional) if true also removes reference system, default is true
*/
clearAllData(includeReferenceSystem = true): Controller {
this.layerManager.clearAllData(includeReferenceSystem);
return this;
}
/**
* Adds layer to list, and initializes it
* @param layer layer object
* @param params (optional) adds additional parameters to the onUpdateEvent
*/
addLayer(layer: Layer<unknown>, params?: LayerOptions<unknown>): Controller {
this.layerManager.addLayer(layer, params);
this.setOverlayZIndex(this.layerManager.getLayers());
return this;
}
/**
* Remove and unmount layer from list
* @param layerId string id
*/
removeLayer(layerId: string): Controller {
this.layerManager.removeLayer(layerId);
return this;
}
/**
* Remove and unmount all layers from list
*/
removeAllLayers(): Controller {
this.layerManager.removeAllLayers();
return this;
}
/**
* Find first layer with given id, returns undefined if none are found
* @param layerId string id
*/
getLayer(layerId: string): Layer<unknown> | undefined {
return this.layerManager.getLayer(layerId);
}
/**
* Sets visibility to true and rescales the layer
* @param layerId string id
*/
showLayer(layerId: string): Controller {
this.layerManager.showLayer(layerId);
return this;
}
/**
* Sets visibility to false
* @param layerId string id
*/
hideLayer(layerId: string): Controller {
this.layerManager.hideLayer(layerId);
return this;
}
/**
* Adjust layers, axis, overlay, and zoom according to inputted dimensions
* @param width (required)
* @param height (required)
*/
adjustToSize(width: number, height: number): Controller {
this.layerManager.adjustToSize(width, height);
const dimensions = {
width: Math.max(width - HORIZONTAL_AXIS_MARGIN, 0),
height: Math.max(height - VERTICAL_AXIS_MARGIN, 0),
};
this.overlay.elm.dispatch('resize', {
detail: dimensions,
bubbles: true,
cancelable: true,
});
return this;
}
/**
* Set new viewport
* @param cx - center X pos
* @param cy - center Y pos
* @param displ - displacement
* @param duration - duration of transition
*/
setViewport(
cx?: number,
cy?: number,
displacement?: number,
duration?: number,
): Controller {
this.zoomPanHandler.setViewport(cx, cy, displacement, duration);
return this;
}
/**
* Sets bounds for zoom and pan handler
* @param xBounds - domain in x-direction
* @param yBounds - domain in y-direction
*/
setBounds(xBounds: [number, number], yBounds: [number, number]): Controller {
this.zoomPanHandler.setBounds(xBounds, yBounds);
return this;
}
/**
* Display both axes
*/
showAxis(): Controller {
this.layerManager.showAxis();
return this;
}
/**
* Hide both axes
*/
hideAxis(): Controller {
this.layerManager.hideAxis();
return this;
}
/**
* Shows labels in x and y
*/
showAxisLabels(): Controller {
this.layerManager.showAxisLabels();
return this;
}
/**
* Hide labels in x and y
*/
hideAxisLabels(): Controller {
this.layerManager.hideAxisLabels();
return this;
}
/**
* Sets domain offset, offset is subtracted from domain
* @param x
* @param y
*/
setAxisOffset(x: number, y: number): Controller {
this.layerManager.setAxisOffset(x, y);
return this;
}
/**
* Sets domain offset in x-direction, offset is subtracted from domain
* @param x
*/
setXAxisOffset(x: number): Controller {
this.layerManager.setXAxisOffset(x);
return this;
}
/**
* Sets domain offset in y-direction, offset is subtracted from domain
* @param y
*/
setYAxisOffset(y: number): Controller {
this.layerManager.setYAxisOffset(y);
return this;
}
/**
* Defines min and max of how much one can zoom
* @param zoomlevels
*/
setZoomLevelBoundary(zoomlevels: [number, number]): Controller {
this.zoomPanHandler.setZoomLevelBoundary(zoomlevels);
return this;
}
/**
* Defines how far in one can zoom
* @param zoomlevel
*/
setMaxZoomLevel(zoomlevel: number): Controller {
this.zoomPanHandler.setMaxZoomLevel(zoomlevel);
return this;
}
/**
* Defines how far out one can zoom
* @param zoomlevel
*/
setMinZoomLevel(zoomlevel: number): Controller {
this.zoomPanHandler.setMinZoomLevel(zoomlevel);
return this;
}
/**
* Destroy Controller
* Convenience method for removing from DOM and clearing references
*/
destroy(): Controller {
this.layerManager.destroy();
this._overlay.destroy();
this._referenceSystem = undefined;
return this;
}
private getHighestZIndex(layers: Layer<unknown>[]): number {
const highestZIndex =
layers.length > 0
? layers.reduce((max, layers) =>
max.order > layers.order ? max : layers,
).order
: 1;
return highestZIndex;
}
private setOverlayZIndex(layers: Layer<unknown>[]): void {
const highestZIndex = this.getHighestZIndex(layers);
this.overlay.setZIndex(highestZIndex + 2);
}
get overlay(): Overlay<Controller> {
return this._overlay;
}
get referenceSystem(): IntersectionReferenceSystem | undefined {
return this._referenceSystem;
}
get zoomPanHandler(): ZoomPanHandler {
return this.layerManager.zoomPanHandler;
}
get axis(): Axis | undefined {
return this.layerManager.axis;
}
get currentStateAsEvent(): OnRescaleEvent {
return this.zoomPanHandler.currentStateAsEvent();
}
}