/// import * as React from 'react'; import { OrthographicCamera, Scene, ShaderMaterial, Vector3, WebGLRenderer } from 'three'; import { Label } from './drawing/shape/label'; import { AtlasColor } from './drawing/texture/atlas-color'; import { AtlasManager } from './drawing/texture/atlas-manager'; import { AtlasTexture } from './drawing/texture/atlas-texture'; import { Bounds } from './primitives/bounds'; import { IPoint } from './primitives/point'; import { ISize } from './primitives/size'; import { ISharedRenderContext } from './types'; import { IProjection } from './util/projection'; import { QuadTree } from './util/quad-tree'; import { IScreenContext } from './util/screen-context'; /** * This enum names the base methods that are passed into the applyPropsMethods * method. This allows subclasses to easily pick the property setting methods they need * from the base */ export declare enum BaseApplyPropsMethods { /** Initializes any context that needs to be set up before the props are set */ INITIALIZE = 0, /** Moment when any buffer changes should be applied */ BUFFERCHANGES = 1, /** Initializes camera properties to facilitate smoothe start up */ CAMERA = 2, /** Generates the labels as images within the atlas manager */ LABELS = 3, /** Generates the colors within the atlas manager */ COLORS = 4, /** Generates images within the atlas manager */ IMAGES = 5, } /** * This enum names the base methods that are passed into the animatedMethods * method. This allows subsclasses to easily pick the animated methods they need * from the base */ export declare enum BaseAnimatedMethods { /** Sets up the base context needed to execute most methods */ CONTEXT = 0, /** Sets up the inertia method for inertial panning */ INERTIA = 1, /** Animates the postion of the camera to a destination */ POSITION = 2, /** Zooms the camera based on a point of focus */ ZOOM = 3, } /** * This defines a response an apply props method can return. * * If this response is empty then it assumes all items are false. */ export interface IApplyPropsMethodResponse { /** * If set to true, the system will not execute any remaining apply props methods for this application of props * and will resume executing methods next time props are applied starting from the beginning of the list */ break?: boolean; } /** * This defines a response that an animated method can return. This will * give the method some control over the flow of animated methods. * * If this response is empty then it assumes all items are false. */ export interface IAnimatedMethodResponse { /** * If set to true, the system will not execute any remaining animated methods for the remainder of the frame * and will resume executing methods next frame from the beginning of the animated method list */ break?: boolean; /** * If this is set to true and returned, it will guarantee a redraw will happen after the animated methods * have finished executing */ doDraw?: boolean; /** * If set to true, the system will cease to animate until some task starts up the loop again by calling * animate() */ stop?: boolean; } export declare type AnimatedMethodOptions = { labelsReady?: boolean; colorsReady?: boolean; }; export declare type AnimatedMethodWithOptions = { options: AnimatedMethodOptions; method(): IAnimatedMethodResponse; }; export declare type AnimatedMethod = () => IAnimatedMethodResponse; export declare type AnimatedMethodLookup = { [key: number]: AnimatedMethod; }; export declare type ApplyPropsMethod = (props: T) => IApplyPropsMethodResponse; export declare type ApplyPropsMethodLookup = { [key: number]: ApplyPropsMethod; }; export interface IWebGLSurfaceProperties { /** * Sets the renderer's background color. If the opacity is less than one at initialization, * it enables 'transparent' canvas rendering which is much less efficient. All color values * are 0 - 1 */ backgroundColor: { /** Red channel 0-1 */ r: number; /** Green channel 0-1 */ g: number; /** Blue channel 0-1 */ b: number; /** Alpha channel 0-1 */ opacity: number; }; /** When true, will cause a camera recentering to take place when new base items are injected */ centerOnNewItems?: boolean; /** All of the unique colors used in the system */ colors?: AtlasColor[]; /** The forced size of the render surface */ height?: number; /** The unique images to be loaded into an atlas for rendering */ images?: AtlasTexture[]; /** All of the labels to be rendered by the system */ labels?: Label[]; /** Provides feedback when the surface is double clicked */ onDoubleClick?(e: React.MouseEvent): void; /** Provides feedback when the mouse has moved */ onMouse?(screen: IPoint, world: IPoint, isPanning: boolean): void; /** When provided provides image data every frame for the screen */ onRender?(image: string): void; /** * This is a handler that handles zoom changes the gpu-chart may request. * This includes moments such as initializing the camera to focus on a * provided viewport. */ onZoomRequest(zoom: number): void; /** * When specified, this context will pan by the indicated amount once. A new object must be * injected in order for the pan to happen again. */ pan?: Vector3; /** * If this is provided, then this will render within the rendering context provided, * however, this will retain it's own camera and own scene. */ renderContext?: ISharedRenderContext; /** This will be the view the camera focuses on when the camera is initialized */ viewport?: Bounds; /** The forced size of the render surface */ width?: number; /** The zoom level that the camera should apply */ zoom: number; } /** * The base component for the communications view */ export declare class WebGLSurface extends React.Component { /** This is the atlas manager for managing images and labels rendered as textures */ atlasManager: AtlasManager; /** Tracks the names of the atlas' generated */ atlasNames: { colors: string; images: string; labels: string; }; /** * List of methods that execute within the animation loop. Makes adding and removing these methods * simpler to manage, as well as gives a clear and optimized way of overriding existing methods * or reordering their execution */ animatedMethodList: (AnimatedMethod | AnimatedMethodWithOptions)[]; /** * If this is set to true during an animated method's lifecycle, then all subsequent animated methods * will not be executed for the current frame. Upon reaching the end of the frame, the break will reset * and the animated methods will attempt executing again */ animatedMethodBreak: boolean; /** * This is the last external panning operation applied to the camera. When a new pan * is applied that is not this pan object */ appliedPan: IPoint; /** * This viewport is the last viewport applied to the camera. * If the props inject a new viewport, this is updated with that value so * that the viewport will only be applied once if it doesn't change again. */ appliedViewport: Bounds; /** * The camera that 'looks' at our world and gives us the ability to convert * screen coordinates to world coordinates, and vice versa */ camera: OrthographicCamera; /** A camera that is used for projecting sizes to and from the screen to the world */ circleMaterial: ShaderMaterial; /** * This is the latest colors loading identifier, used to determine if the colors * last loaded matches the colors currently needing to be rendered. Fixes asynchronous * Issue where a new set of colors is requested before the previous set(s) have completed */ colorsCurrentLoadedId: number; /** This is the is of the current and most recent color group being loaded in */ colorsLoadId: number; /** Stores screen dimension info */ ctx: IScreenContext; /** * While this number is positive it will be decremented every frame. * While positive, mouse interactions will not occur. This utilizes frame ticks * as SOME values and numbers settle per frame, not necessarily within timelapses. * More often than not, there will only be a need for 1-2 frames of mouse disable to * allow the camera to be positioned in a correct location before screen to world projections * start taking place. */ disableMouseInteraction: number; /** Used to aid in mouse interactions */ distance: number; /** When set, forces a draw next animation frame */ forceDraw: boolean; /** * This stores the gl rendering context for reference when it's available */ gl: WebGLRenderingContext; /** Contains the methods for projecting between screen and world spaces */ projection: IProjection; /** The top level HTML element for this component */ renderEl: HTMLElement; /** The threejs renderer */ renderer: WebGLRenderer; scene: Scene; sizeCamera: OrthographicCamera | null; /** Keep track of the current zoom so it can be set in requestAnimationFrame */ currentZoom: number; /** Horizontal destination the camera will pan to */ destinationX: number; /** Vertical position the camera will pan to */ destinationY: number; /** The destination zoom level the camera used during panning */ destinationZoom: number; /** Is the camera currently in a panning state */ isPanning: boolean; /** Last known screen position of the mouse */ lastMousePosition: { x: number; y: number; }; /** List of methods to execute when applying props */ propsMethodList: ApplyPropsMethod[]; /** Inertial values for drag panning */ inertia: IPoint | null; inertiaBuild: number; inertiaDecay: number; inertiaMax: number; /** * All data is put into this quad tree so we can query spatial regions for * items */ quadTree: QuadTree> | null; /** * True if the shift key is currently being held * * Panning is affected by whether or not the shift key is being held down, but * I don't know how yet. */ shiftIsDown: boolean; stop: boolean; /** The current rendered position and zoom */ currentX: number; currentY: number; targetZoom: number; /** The (world) position the focus will zoom in and out of */ previousZoomToFit: number; zoomTargetX: number; zoomTargetY: number; /** When this is set, the draw loop continues to run. Used by the draw loop to complete animations */ animating: boolean; labels: Label[]; labelsReady: boolean; /** * This is the latest labels loading identifier, used to determine if the labels * last loaded matches the labels currently needing to be rendered. */ labelsCurrentLoadedId: number; labelsLoadId: number; /** When this is set to true, the atlas with the colors is now ready to be referenced */ colors: AtlasColor[]; colorsReady: boolean; /** This is a flag that allows some extra control over when an onRender can fire */ isRenderReady: boolean; /** Holds the items currently hovered over */ currentHoverItems: Bounds[]; /** Mouse in stage or not */ dragOver: boolean; /** * If this is true, we are waiting for the rendering context to become available * within this.props.renderContext */ waitForContext: boolean; images: AtlasTexture[]; imagesReady: boolean; /** * This is the latest images loading identifier, used to determine if the images * last loaded matches the images currently needing to be rendered. */ imagesCurrentLoadedId: number; imagesLoadId: number; /** * This is the update loop that operates at the requestAnimationFrame speed. * This updates the cameras current position and causes changes over time for * any property that has a start and a destination. */ animate: () => void; /** * This is a hook so subclasses can contribute animated methods to the animation loop and organize the base methods * as desired. * * @param {AnimatedMethodLookup} baseAnimatedMethods The base animated methods referenceable by name * @param {AnimatedMethod[]} orderedBaseAnimatedMethods The base animated methods in their default order for ease of use * * @return {AnimatedMethods[]} The list of animated methods in the order they are expected to be executed */ animatedMethods(baseAnimatedMethods: AnimatedMethodLookup, orderedBaseAnimatedMethods: (AnimatedMethod | AnimatedMethodWithOptions)[]): (AnimatedMethod | AnimatedMethodWithOptions)[]; /** * This generates the base animated methods lookup. * We do not make these methods a part of the class as this is the base class * We want the start up methods to be inconsequential to sub classes, thus allowing * us to override, sort, or replace the initial methods and have the method get garbage * collected and no longer a part of the object. It is recommended to make the sub classes * actually point to class methods for better clarity * * @return {ANimatedMethodLookup} The base animated methods in a lookup */ private animatedMethodsBase(); /** * This is a hook for subclasses to be able to apply buffer changes that rely * on colors rendered into the atlas after the system has prepped the colors for render. */ applyColorBufferChanges(props: T): void; /** * This is a hook for subclasses to be able to apply buffer changes that rely * on images rendered into the atlas after the system has prepped the images for render. */ applyImageBufferChanges(props: T): void; /** * This is a hook for subclasses to be able to apply label buffer changes after the system has * prepped the labels for render. */ applyLabelBufferChanges(props: T): void; /** * Applies new props injected into this component. * * Applying new props does not entail that a re-render will happen so we * handle application of props as a separate concept. Here we: * * set up zoom targetting and apply quested zoom levels * * Create our quad tree and associate properties to objects if a new dataset * is provided * * Analyze our dataset for interesting and useful metrics such as max and mins * to aid in visualization normalization * * @param {T} props The new properties for this component */ applyProps: (props: T) => void; /** * @override * This is a hook so subclasses can contribute property application methods to the applyProps process and organize the base methods * as desired. * * @param {ApplyPropsMethodLookup} basePropsMethods The base props methods referenceable by name * @param {ApplyPropsMethod[]} orderedBasePropsMethods The base animated methods in their default order for ease of use * * @return {ApplyPropsMethod[]} The list of property application methods in the order they are expected to be executed */ applyPropsMethods(basePropsMethods: ApplyPropsMethodLookup, orderedBasePropsMethods: ApplyPropsMethod[]): ApplyPropsMethod[]; /** * This is a hook so subclasses can contribute methods to the applying props procedure and organize the base methods * as desired. * * @return {ApplyPropsMethodLookup} The base apply props method that are indexed for ease of reference */ private applyPropsMethodsBase(); /** * This is a hook for sub components to have a location to update their buffers * * @param {T} props This is the next set of props that are going to be applied to this component */ applyBufferChanges(props: T): void; /** * @override * Start the update loop and register any interesting listeners */ componentDidMount(): void; /** * @override * This will set up any unchanging context as well as establish the set of methods * that are to be used within constructed method loops. */ componentWillMount(): void; /** * @override * Simply applies the new injected props * * @param {T} props The new properties to be applied to this component */ componentWillReceiveProps(props: T): void; /** * @override * Release listeners and stop update loop */ componentWillUnmount(): void; /** * This is the draw method executed from the animation loop. Everytime, this is * called, the webgl surface will be redrawn. */ draw(): void; /** * This initializes the surface and calls for sub class classes to initialize * their buffers * * @param {HTMLElement} el The DOM element this component is contained in * @param {number} w The width of the rendering * @param {number} h The height of the rendering */ init: (el: HTMLElement, w: number, h: number) => void; /** * This is a hook allowing sub classes to have a place to initialize their buffers * and materials etc. */ initBuffers(): void; /** * Initializes the camera and any contexts associated with it */ initCamera: () => void; /** * This is executed when our rendering surface (the canvas) changes in size in any * way. It will make sure our renderer matches the context to prevent scaling * and other deformations. */ resizeContext: () => boolean; /** * This method handles emitting the viewport and the current visible elements * to the subclass that needs detailed information regarding the viewport. */ emitViewport: () => void; /** * Hook for subclasses to when the mouse moves. Provides some information * about mouse location and interaction. * * @param {IPoint} mouse Position of the mouse relative to the canvas * @param {IPoint} world Position of the mouse relative to the world space * @param {boolean} isPanning The panning state of the mouse */ onMouse(mouse: IPoint, world: IPoint, isPanning: boolean): void; /** * Hook for subclasses to respond to mouse down events */ onMouseDown(): void; /** * Hook for subclasses to respond to mouse out events */ onMouseOut(): void; /** * Hook for subclasses to respond to mouse up events and the items that were interacted with in the process * * @param {React.MouseEvent} e The react synthetic event associated with the action * @param {Bounds[]} hitInside The items the mouse interacted with * @param {IPoint} mouse The location of the mouse on the screen * @param {IPoint} world The location of the mouse projected into the world * @param {IProjection} projection The projection methods to go between the screen and world space */ onMouseUp(e: React.MouseEvent, hitInside: Bounds[], mouse: IPoint, world: IPoint, projection: IProjection): void; /** * Hook for subclasses to respond to the mouse hovering over an item included in the quadtree * * @param {Bounds[]} hitInside The items hovered over by the mouse * @param {IPoint} mouse The location of the mouse on the screen relative to the canvas * @param {IPoint} world The location of the mouse projected to the world coordinates * @param {IProjection} projection The projection methods to go between the screen and world space */ onMouseHover(hitInside: Bounds[], mouse: IPoint, world: IPoint, projection: IProjection): void; /** * Hook for subclasses to respond to the mouse leaving an item included in the quadtree * * @param {Bounds[]} left The items no longer hovered over by the mouse * @param {IPoint} mouse The location of the mouse on the screen relative to the canvas * @param {IPoint} world The location of the mouse projected to the world coordinates * @param {IProjection} projection The projection methods to go between the screen and world space */ onMouseLeave(left: Bounds[], mouse: IPoint, world: IPoint, projection: IProjection): void; /** * Hook for subclasses to respond to changes in the viewport and currently visible items * * @param {Bounds[]} visible * @param {IProjection} projection The projection methods to go between the screen and world space * @param {IScreenContext} ctx */ onViewport(visible: Bounds[], projection: IProjection, ctx: IScreenContext): void; makeDraggable(element: HTMLElement, stage: WebGLSurface): void; /** * Handles mouse interactions when the mouse is pressed on the canvas. This * engages panning. * * @param {React.MouseEvent} e The mouse event from React */ handleMouseDown: (e: React.MouseEvent) => void; /** * Handles mouse interactions when the mouse is release or left the canvas. This * stops panning. * * @param {React.MouseEvent} e The mouse event from React */ handleMouseOut: (e: React.MouseEvent) => void; /** * Handles mouse interactions when the mouse is released on the canvas. This * stops panning and engages click events. * * @param {React.MouseEvent} e The mouse event from React */ handleMouseUp: (e: React.MouseEvent) => void; /** * Handles mouse interactions when the mouse is moving on the canvas. This * causes panning and hover events. * * @param {React.MouseEvent} e The mouse event from React */ handleMouseMove: (e: React.MouseEvent) => void; /** * Places the camera at a given location in world space * * @param {number} x The x-coordinate for the camera in world space * @param {number} y The x-coordinate for the camera in world space */ positionCamera(x: number, y: number): void; /** * Projects a screen coordinate to a world coordinate * * @param {number} x The x coord within the screen to project into the world * @param {number} y The y coord within the screen to project into the world * @param {object} obj An optional object in which the projected dimensions will * be injected to * * @return {object} Either a new object with the projected dimensions or the object * Insertted as a param that has the properties injected into */ screenToWorld(x: number, y: number, obj?: IPoint): IPoint; /** * Projects a size on the screen to the size represented in the world * * @param {number} w The size of the width on the screen to project to the world * @param {number} h The size of the height on the screen to project to the world * @param {object} obj An optional object in which the projected dimensions will * be injected to * * @return {object} Either a new object with the projected dimensions or the object * Insertted as a param that has the properties injected into */ screenSizeToWorld(w: number, h: number, obj?: ISize): ISize; /** * Projects a world coordinate to the screen * * @param {number} x The x coord in the world to project to the screen * @param {number} y The y coord in the world to project to the screen * @param {object} obj An optional object in which the projected dimensions will * be injected to * * @return {IPoint} Either a new object with the projected dimensions or the object * Insertted as a param that has the properties injected into */ worldToScreen(x: number, y: number, obj?: IPoint): IPoint; /** * Projects a size within the world to how it would appear on the screen * * @param {number} w The size of the width on the screen to project to the world * @param {number} h The size of the height on the screen to project to the world * @param {object} obj An optional object in which the projected dimensions will * be injected to * * @return {object} Either a new object with the projected dimensions or the object * Insertted as a param that has the properties injected into */ worldSizeToScreen(w: number, h: number, obj?: ISize): ISize; /** * Sets the zoom level the camera will view the world with * * @param {number} zoom The zoom level. Must be > 0 */ zoomCamera(zoom: number): void; /** * This is a hook allowing a sub class to update uniforms when the camera is changed in * any way */ updateCameraUniforms(): void; /** * We make the ref application be a declared function so react does not find the need to execute the * application numerous times for a detected changed method * * @param {HTMLElement} n This is the canvas element from the dom */ applyRef: (n: HTMLElement) => void; /** * @override * Only re-render if the dimensions of the component have changed. All other * internal render updates are handled internally * * @param {T} nextProps The next properties injected */ shouldComponentUpdate(nextProps: T): boolean; /** * Hook to allow subclasses some control over panning distances * * @param {number} distanceX The distance to pan in the x direction * @param {number} distanceY The distance to pan in the y direction * * @return {Vector3} The vector indicating the direction to pan */ willPan(distanceX: number, distanceY: number): Vector3; /** * This should only attempt rendering when the canvas DOM element needs to be resized. * You will note shouldComponentUpdate helps facilitate this. */ render(): JSX.Element; }