Skip to content

Display

Overview

A persistent display of a specific Node and its descendants, which is updated at discrete points in time.

Use display.getDOMElement or display.domElement to retrieve the Display's DOM representation. Use display.updateDisplay() to trigger the visual update in the Display's DOM element.

A standard way of using a Display with Scenery is to: 1. Create a Node that will be the root 2. Create a Display, referencing that node 3. Make changes to the scene graph 4. Call display.updateDisplay() to draw the scene graph into the Display 5. Go to (3)

Common ways to simplify the change/update loop would be to: - Use Node-based events. Initialize it with Display.initializeEvents(), then add input listeners to parts of the scene graph (see Node.addInputListener). - Execute code (and update the display afterwards) by using Display.updateOnRequestAnimationFrame.

Internal documentation:

Lifecycle information: Instance (create,dispose) - out of update: Stateless stub is created synchronously when a Node's children are added where we have no relevant Instance. - start of update: Creates first (root) instance if it doesn't exist (stateless stub). - synctree: Create descendant instances under stubs, fills in state, and marks removed subtree roots for disposal. - update instance disposal: Disposes root instances that were marked. This also disposes all descendant instances, and for every instance, it disposes the currently-attached drawables. Drawable (create,dispose) - synctree: Creates all drawables where necessary. If it replaces a self/group/shared drawable on the instance, that old drawable is marked for disposal. - update instance disposal: Any drawables attached to disposed instances are disposed themselves (see Instance lifecycle). - update drawable disposal: Any marked drawables that were replaced or removed from an instance (it didn't maintain a reference) are disposed.

add/remove drawables from blocks: - stitching changes pending "parents", marks for block update - backbones marked for disposal (e.g. instance is still there, just changed to not have a backbone) will mark drawables for block updates - add/remove drawables phase updates drawables that were marked - disposed backbone instances will only remove drawables if they weren't marked for removal previously (e.g. in case we are from a removed instance)

@author Jonathan Olson <jonathan.olson@colorado.edu>

Class Display

import { Display } from 'scenerystack/scenery';

Constructor

new Display( rootNode : Node, providedOptions? : DisplayOptions )

Instance Methods

getDOMElement() : HTMLElement

updateDisplay()

Updates the display's DOM element with the current visual state of the attached root node and its descendants

getPhetioElementAt( point : Vector2 ) : PhetioObject | null

Used for Studio Autoselect to determine the leafiest PhET-iO Element under the mouse

isWebGLAllowed() : boolean

Whether WebGL is allowed to be used in drawables for this Display

getRootNode() : Node

getRootBackbone() : BackboneDrawable

getSize() : Dimension2

The dimensions of the Display's DOM element

getBounds() : Bounds2

setSize( size : Dimension2 )

Changes the size that the Display's DOM element will be after the next updateDisplay()

setWidthHeight( width : number, height : number )

Changes the size that the Display's DOM element will be after the next updateDisplay()

getWidth() : number

The width of the Display's DOM element

setWidth( width : number ) : this

Sets the width that the Display's DOM element will be after the next updateDisplay(). Should be an integral value.

getHeight() : number

The height of the Display's DOM element

setHeight( height : number ) : this

Sets the height that the Display's DOM element will be after the next updateDisplay(). Should be an integral value.

setBackgroundColor( color : Color | string | null ) : this

Will be applied to the root DOM element on updateDisplay(), and no sooner.

getBackgroundColor() : Color | string | null

addOverlay( overlay : TOverlay )

Adds an overlay to the Display. Each overlay should have a .domElement (the DOM element that will be used for display) and an .update() method.

removeOverlay( overlay : TOverlay )

Removes an overlay from the display.

getPDOMRootElement() : HTMLElement | null

Get the root accessible DOM element which represents this display and provides semantics for assistive technology. If this Display is not accessible, returns null.

isAccessible() : boolean

Has this Display enabled accessibility features like PDOM creation and support.

isElementUnderPDOM( element : Element, allowRoot : boolean ) : boolean

Returns true if the element is in the PDOM. That is only possible if the display is accessible. @param element @param allowRoot - If true, the root of the PDOM is also considered to be "under" the PDOM.

getUsedRenderersBitmask() : number

Returns the bitmask union of all renderers (canvas/svg/dom/webgl) that are used for display, excluding BackboneDrawables (which would be DOM).

canvasDataURL( callback : ( str: string ) => void )

canvasSnapshot( callback : ( canvas: HTMLCanvasElement, imageData: ImageData ) => void )

Renders what it can into a Canvas (so far, Canvas and SVG layers work fine)

setPointerDisplayVisible( visibility : boolean )

TODO: reduce code duplication for handling overlays https://github.com/phetsims/scenery/issues/1581

setPointerAreaDisplayVisible( visibility : boolean )

TODO: reduce code duplication for handling overlays https://github.com/phetsims/scenery/issues/1581

setHitAreaDisplayVisible( visibility : boolean )

TODO: reduce code duplication for handling overlays https://github.com/phetsims/scenery/issues/1581

setCanvasNodeBoundsVisible( visibility : boolean )

TODO: reduce code duplication for handling overlays https://github.com/phetsims/scenery/issues/1581

setFittedBlockBoundsVisible( visibility : boolean )

TODO: reduce code duplication for handling overlays https://github.com/phetsims/scenery/issues/1581

resizeOnWindowResize()

Sets up the Display to resize to whatever the self inner dimensions will be.

updateOnRequestAnimationFrame( stepCallback? : ( dt: number ) => void )

Updates on every request animation frame. If stepCallback is passed in, it is called before updateDisplay() with stepCallback( timeElapsedInSeconds )

cancelUpdateOnRequestAnimationFrame()

initializeEvents( options? : InputOptions )

Initializes event handling, and connects the browser's input event handlers to notify this Display of events.

NOTE: This can be reversed with detachEvents().

detachEvents()

Detach already-attached input event handling (from initializeEvents()).

addInputListener( listener : TInputListener ) : this

Adds an input listener.

removeInputListener( listener : TInputListener ) : this

Removes an input listener that was previously added with addInputListener.

hasInputListener( listener : TInputListener ) : boolean

Returns whether this input listener is currently listening to this Display.

More efficient than checking display.inputListeners, as that includes a defensive copy.

getInputListeners() : TInputListener[]

Returns a copy of all of our input listeners.

interruptInput() : this

Interrupts all input listeners that are attached to this Display.

interruptPointers() : this

Interrupts all pointers associated with this Display, see https://github.com/phetsims/scenery/issues/1582.

interruptOtherPointers( excludePointer : Pointer | null ) : this

Interrupts all pointers associated with this Display that are NOT currently having events executed. see https://github.com/phetsims/scenery/issues/1582.

If excludePointer is provided and is non-null, it's used as the "current" pointer that should be excluded from interruption.

loseWebGLContexts()

Triggers a loss of context for all WebGL blocks.

NOTE: Should generally only be used for debugging.

inspect()

Makes this Display available for inspection.

getDebugHTML() : string

Returns an HTML fragment that includes a large amount of debugging information, including a view of the instance tree and drawable tree.

getDebugURI() : string

Returns the getDebugHTML() information, but wrapped into a full HTML page included in a data URI.

popupDebug()

Attempts to open a popup with the getDebugHTML() information.

iframeDebug()

Attempts to open an iframe popup with the getDebugHTML() information in the same self. This is similar to popupDebug(), but should work in browsers that block popups, or prevent that type of data URI being opened.

getPDOMDebugHTML() : string

foreignObjectRasterization( callback : ( url: string | null ) => void )

Will attempt to call callback( {string} dataURI ) with the rasterization of the entire Display's DOM structure, used for internal testing. Will call-back null if there was an error

Only tested on recent Chrome and Firefox, not recommended for general use. Guaranteed not to work for IE <= 10.

See https://github.com/phetsims/scenery/issues/394 for some details.

popupRasterization()

getTrailFromPDOMIndicesString( indicesString : string ) : Trail | null

Will return null if the string of indices isn't part of the PDOMInstance tree

refreshSVG()

Forces SVG elements to have their visual contents refreshed, by changing state in a non-visually-apparent way. It should trick browsers into re-rendering the SVG elements.

See https://github.com/phetsims/scenery/issues/1507

refreshSVGOnNextFrame()

Similar to refreshSVG (see docs above), but will do so on the next frame.

dispose()

Releases references.

TODO: this dispose function is not complete. https://github.com/phetsims/scenery/issues/1581

Instance Properties

sizeProperty : TProperty<Dimension2>

(readonly)

The (integral, > 0) dimensions of the Display's DOM element (only updates the DOM element on updateDisplay())

descriptionUtteranceQueue : UtteranceQueue

data structure for managing aria-live alerts the this Display instance

focusManager : FocusManager

Manages the various types of Focus that can go through the Display, as well as Properties controlling which forms of focus should be displayed in the HighlightOverlay.

Static Methods

elementToSVGDataURL( domElement : HTMLElement, width : number, height : number, callback : ( url: string | null ) => void )

Takes a given DOM element, and asynchronously renders it to a string that is a data URL representing an SVG file.

@param domElement @param width - The width of the output SVG @param height - The height of the output SVG @param callback - Called as callback( url: {string} ), where the URL will be the encoded SVG file.

addInputListener( listener : TInputListener )

Adds an input listener to be fired for ANY Display

removeInputListener( listener : TInputListener )

Removes an input listener that was previously added with Display.addInputListener.

interruptInput()

Interrupts all input listeners that are attached to all Displays.

Static Properties

INTERRUPT_OTHER_POINTERS

(readonly)

userGestureEmitter : TEmitter

Fires when we detect an input event that would be considered a "user gesture" by Chrome, so that we can trigger browser actions that are only allowed as a result. See https://github.com/phetsims/scenery/issues/802 and https://github.com/phetsims/vibe/issues/32 for more information.

inputListeners : TInputListener[]

Listeners that will be called for every event on ANY Display, see https://github.com/phetsims/scenery/issues/1149. Do not directly modify this!

Type DisplayOptions

import type { DisplayOptions } from 'scenerystack/scenery';
  • width?: number
    Initial (or override) display width
  • height?: number
    Initial (or override) display height
  • allowCSSHacks?: boolean
    Applies CSS styles to the root DOM element that make it amenable to interactive content
  • allowSafariRedrawWorkaround?: boolean
    Whether we allow the display to put a rectangle in front of everything that subtly shifts every frame, in order to force repaints for https://github.com/phetsims/geometric-optics-basics/issues/31.
  • allowSceneOverflow?: boolean
    Usually anything displayed outside our dom element is hidden with CSS overflow.
  • allowLayerFitting?: boolean
    If false, this will disable layer fitting (like putting preventFit: true on Nodes, but for the entire Display). Layer fitting has caused some unsightly jittering (https://github.com/phetsims/scenery/issues/1289), so this allows it to be turned on in a case-by-case manner.
  • defaultCursor?: string
    What cursor is used when no other cursor is specified
  • forceSVGRefresh?: boolean
    Forces SVG elements to be refreshed every frame, which can force repainting and detect (or potentially in some cases work around) SVG rendering browser bugs. See https://github.com/phetsims/scenery/issues/1507
  • backgroundColor?: Color | string | null
    Initial background color
  • preserveDrawingBuffer?: boolean
    Whether WebGL will preserve the drawing buffer WARNING!: This can significantly reduce performance if set to true.
  • allowWebGL?: boolean
    Whether WebGL is enabled at all for drawables in this Display Makes it possible to disable WebGL for ease of testing on non-WebGL platforms, see #289
  • accessibility?: boolean
    Enables accessibility features
  • supportsInteractiveHighlights?: boolean
    {boolean} - Enables Interactive Highlights in the HighlightOverlay. These are highlights that surround interactive components when using mouse or touch which improves low vision access.
  • interactive?: boolean
    Whether mouse/touch/keyboard inputs are enabled (if input has been added).
  • listenToOnlyElement?: boolean
    If true, input event listeners will be attached to the Display's DOM element instead of the self. Normally, attaching listeners to the self is preferred (it will see mouse moves/ups outside of the browser self, allowing correct button tracking), however there may be instances where a global listener is not preferred.
  • batchDOMEvents?: boolean
    Forwarded to Input: If true, most event types will be batched until otherwise triggered.
  • assumeFullWindow?: boolean
    If true, the input event location (based on the top-left of the browser tab's viewport, with no scaling applied) will be used. Usually, this is not a safe assumption, so when false the location of the display's DOM element will be used to get the correct event location. There is a slight performance hit to doing so, thus this option is provided if the top-left location can be guaranteed. NOTE: Rotation of the Display's DOM element (e.g. with a CSS transform) will result in an incorrect event mapping, as getBoundingClientRect() can't work with this. getBoxQuads() should fix this when browser support is available.
  • aggressiveContextRecreation?: boolean
    Whether Scenery will try to aggressively re-create WebGL Canvas/context instead of waiting for a context restored event. Sometimes context losses can occur without a restoration afterwards, but this can jump-start the process. See https://github.com/phetsims/scenery/issues/347.
  • passiveEvents?: boolean | null
    Whether the passive flag should be set when adding and removing DOM event listeners. See https://github.com/phetsims/scenery/issues/770 for more details. If it is true or false, that is the value of the passive flag that will be used. If it is null, the default behavior of the browser will be used.

Safari doesn't support touch-action: none, so we NEED to not use passive events (which would not allow preventDefault to do anything, so drags actually can scroll the sim). Chrome also did the same "passive by default", but because we have touch-action: none in place, it doesn't affect us, and we can potentially get performance improvements by allowing passive events. See https://github.com/phetsims/scenery/issues/770 for more information. - allowBackingScaleAntialiasing?: boolean
Whether, if no WebGL antialiasing is detected, the backing scale can be increased to provide some antialiasing benefit. See https://github.com/phetsims/scenery/issues/859. - container?: HTMLElement
An HTMLElement used to contain the contents of the Display - & Pick<PhetioObjectOptions, "tandem">

Source Code

See the source for Display.ts in the scenery repository.