diff --git a/js/layout/HeightSizable.ts b/js/layout/HeightSizable.ts index 44676951f..9531d17cb 100644 --- a/js/layout/HeightSizable.ts +++ b/js/layout/HeightSizable.ts @@ -71,9 +71,8 @@ const HeightSizable = memoize( ( type: SuperType public readonly isHeightResizableProperty: TinyProperty = new TinyProperty( true ); // Flags so that we can change one (parent/local) value and not enter an infinite loop changing the other - // (scenery-internal) - would be private, but can't be with mixin constraints - public _preferredHeightChanging = false; - public _minimumHeightChanging = false; + private _preferredHeightChanging = false; + private _minimumHeightChanging = false; // IMPORTANT: If you're mixing this in, typically don't pass options that HeightSizable would take through the // constructor. It will hit Node's mutate() likely, and then will fail because we haven't been able to set the diff --git a/js/layout/WidthSizable.ts b/js/layout/WidthSizable.ts index d43337416..51ff0d2b7 100644 --- a/js/layout/WidthSizable.ts +++ b/js/layout/WidthSizable.ts @@ -71,9 +71,8 @@ const WidthSizable = memoize( ( type: SuperType ) public readonly isWidthResizableProperty: TinyProperty = new TinyProperty( true ); // Flags so that we can change one (parent/local) value and not enter an infinite loop changing the other - // (scenery-internal) - would be private, but can't be with mixin constraints - public _preferredWidthChanging = false; - public _minimumWidthChanging = false; + private _preferredWidthChanging = false; + private _minimumWidthChanging = false; // IMPORTANT: If you're mixing this in, typically don't pass options that WidthSizable would take through the // constructor. It will hit Node's mutate() likely, and then will fail because we haven't been able to set the diff --git a/js/layout/constraints/FlowConfigurable.ts b/js/layout/constraints/FlowConfigurable.ts index c194b0ecb..75b000ced 100644 --- a/js/layout/constraints/FlowConfigurable.ts +++ b/js/layout/constraints/FlowConfigurable.ts @@ -88,12 +88,11 @@ export type FlowConfigurableOptions = { export type ExternalFlowConfigurableOptions = WithoutNull>; const FlowConfigurable = memoize( ( type: SuperType ) => { - return class extends type { + return class FlowConfirableMixin extends type { - // (scenery-internal) - considered private, but TypeScript mixins won't support private - public _orientation: Orientation = Orientation.HORIZONTAL; + protected _orientation: Orientation = Orientation.HORIZONTAL; - // (scenery-internal) - considered private, but TypeScript mixins won't support private + // (scenery-internal) public _align: LayoutAlign | null = null; public _stretch: boolean | null = null; public _leftMargin: number | null = null; diff --git a/js/layout/constraints/GridConfigurable.ts b/js/layout/constraints/GridConfigurable.ts index 5b3bd1176..083218aa9 100644 --- a/js/layout/constraints/GridConfigurable.ts +++ b/js/layout/constraints/GridConfigurable.ts @@ -83,9 +83,9 @@ export type GridConfigurableOptions = { export type ExternalGridConfigurableOptions = WithoutNull>; const GridConfigurable = memoize( ( type: SuperType ) => { - return class extends type { + return class GridConfigurableMixin extends type { - // (scenery-internal) - considered private, but TypeScript mixins won't support private + // (scenery-internal) public _xAlign: LayoutAlign | null = null; public _yAlign: LayoutAlign | null = null; public _xStretch: boolean | null = null; diff --git a/js/nodes/Imageable.ts b/js/nodes/Imageable.ts index 8677e6949..cdfd03c13 100644 --- a/js/nodes/Imageable.ts +++ b/js/nodes/Imageable.ts @@ -71,62 +71,61 @@ export type ImageableOptions = { }; const Imageable = ( type: SuperType ) => { - return class extends type { + return class ImageableMixin extends type { - // Internal stateful value, see setImage() - _image: HTMLImageElement | HTMLCanvasElement | null; + // (scenery-internal) Internal stateful value, see setImage() + public _image: HTMLImageElement | HTMLCanvasElement | null; // Internal stateful value, see setInitialWidth() for documentation. - _initialWidth: number; + private _initialWidth: number; // Internal stateful value, see setInitialHeight() for documentation. - _initialHeight: number; + private _initialHeight: number; - // Internal stateful value, see setImageOpacity() for documentation. - _imageOpacity: number; + // (scenery-internal) Internal stateful value, see setImageOpacity() for documentation. + public _imageOpacity: number; - // Internal stateful value, see setMipmap() for documentation. - _mipmap: boolean; + // (scenery-internal) Internal stateful value, see setMipmap() for documentation. + public _mipmap: boolean; - // Internal stateful value, see setMipmapBias() for documentation. - _mipmapBias: number; + // (scenery-internal) Internal stateful value, see setMipmapBias() for documentation. + public _mipmapBias: number; - // Internal stateful value, see setMipmapInitialLevel() for documentation. - _mipmapInitialLevel: number; + // (scenery-internal) Internal stateful value, see setMipmapInitialLevel() for documentation. + public _mipmapInitialLevel: number; - // Internal stateful value, see setMipmapMaxLevel() for documentation - _mipmapMaxLevel: number; + // (scenery-internal) Internal stateful value, see setMipmapMaxLevel() for documentation + public _mipmapMaxLevel: number; // Internal stateful value, see setHitTestPixels() for documentation - _hitTestPixels: boolean; + protected _hitTestPixels: boolean; // Array of Canvases for each level, constructed internally so that Canvas-based drawables (Canvas, WebGL) can quickly draw mipmaps. - _mipmapCanvases: HTMLCanvasElement[]; + private _mipmapCanvases: HTMLCanvasElement[]; // Array of URLs for each level, where each URL will display an image (and is typically a data URI or blob URI), so // that we can handle mipmaps in SVG where URLs are required. - _mipmapURLs: string[]; + private _mipmapURLs: string[]; - // Mipmap data if it is passed into our image. Will be stored here for processing - _mipmapData: Mipmap | null; + // (scenery-internal) Mipmap data if it is passed into our image. Will be stored here for processing + public _mipmapData: Mipmap | null; // Listener for invalidating our bounds whenever an image is invalidated. - _imageLoadListener: () => void; + private _imageLoadListener: () => void; // Whether our _imageLoadListener has been attached as a listener to the current image. - _imageLoadListenerAttached: boolean; + private _imageLoadListenerAttached: boolean; // Used for pixel hit testing. - _hitTestImageData: ImageData | null; + protected _hitTestImageData: ImageData | null; // Emits when mipmaps are (re)generated - mipmapEmitter: TinyEmitter<[]>; - + public mipmapEmitter: TinyEmitter<[]>; // For compatibility - isDisposed?: boolean; + public isDisposed?: boolean; - constructor( ...args: any[] ) { + public constructor( ...args: any[] ) { super( ...args ); @@ -204,7 +203,7 @@ const Imageable = ( type: SuperType ) => { * Also note that if the underlying image (like Canvas data) has changed, it is recommended to call * invalidateImage() instead of changing the image reference (calling setImage() multiple times) */ - setImage( image: ImageableImage ): this { + public setImage( image: ImageableImage ): this { assert && assert( image, 'image should be available' ); assert && assert( typeof image === 'string' || image instanceof HTMLImageElement || @@ -270,9 +269,9 @@ const Imageable = ( type: SuperType ) => { return this; } - set image( value: ImageableImage ) { this.setImage( value ); } + public set image( value: ImageableImage ) { this.setImage( value ); } - get image(): HTMLImageElement | HTMLCanvasElement { return this.getImage(); } + public get image(): HTMLImageElement | HTMLCanvasElement { return this.getImage(); } /** * Returns the current image's representation as either a Canvas or img element. @@ -281,7 +280,7 @@ const Imageable = ( type: SuperType ) => { * instead provides the mapped result (or first mipmap level's image). * TODO: return the original result instead. */ - getImage(): HTMLImageElement | HTMLCanvasElement { + public getImage(): HTMLImageElement | HTMLCanvasElement { assert && assert( this._image !== null ); return this._image!; @@ -296,7 +295,7 @@ const Imageable = ( type: SuperType ) => { * This should be done when the underlying image has changed appearance (usually the case with a Canvas changing, * but this is also triggered by our actual image reference changing). */ - invalidateImage(): void { + public invalidateImage(): void { this.invalidateMipmaps(); this._invalidateHitTestData(); } @@ -315,7 +314,7 @@ const Imageable = ( type: SuperType ) => { * @param width - Initial width of the image. See setInitialWidth() for more documentation * @param height - Initial height of the image. See setInitialHeight() for more documentation */ - setImageWithSize( image: string | HTMLImageElement | HTMLCanvasElement | Mipmap, width: number, height: number ): this { + public setImageWithSize( image: string | HTMLImageElement | HTMLCanvasElement | Mipmap, width: number, height: number ): this { // First, setImage(), as it will reset the initial width and height this.setImage( image ); @@ -335,7 +334,7 @@ const Imageable = ( type: SuperType ) => { * @param imageOpacity - Should be a number between 0 (transparent) and 1 (opaque), just like normal * opacity. */ - setImageOpacity( imageOpacity: number ): void { + public setImageOpacity( imageOpacity: number ): void { assert && assert( typeof imageOpacity === 'number', 'imageOpacity was not a number' ); assert && assert( isFinite( imageOpacity ) && imageOpacity >= 0 && imageOpacity <= 1, `imageOpacity out of range: ${imageOpacity}` ); @@ -345,16 +344,16 @@ const Imageable = ( type: SuperType ) => { } } - set imageOpacity( value: number ) { this.setImageOpacity( value ); } + public set imageOpacity( value: number ) { this.setImageOpacity( value ); } - get imageOpacity(): number { return this.getImageOpacity(); } + public get imageOpacity(): number { return this.getImageOpacity(); } /** * Returns the opacity applied only to this image (not including children). * * See setImageOpacity() documentation for more information. */ - getImageOpacity(): number { + public getImageOpacity(): number { return this._imageOpacity; } @@ -376,7 +375,7 @@ const Imageable = ( type: SuperType ) => { * * @param width - Expected width of the image's unloaded content */ - setInitialWidth( width: number ): this { + public setInitialWidth( width: number ): this { assert && assert( typeof width === 'number' && width >= 0 && ( width % 1 === 0 ), 'initialWidth should be a non-negative integer' ); if ( width !== this._initialWidth ) { @@ -388,16 +387,16 @@ const Imageable = ( type: SuperType ) => { return this; } - set initialWidth( value: number ) { this.setInitialWidth( value ); } + public set initialWidth( value: number ) { this.setInitialWidth( value ); } - get initialWidth(): number { return this.getInitialWidth(); } + public get initialWidth(): number { return this.getInitialWidth(); } /** * Returns the initialWidth value set from setInitialWidth(). * * See setInitialWidth() for more documentation. A value of 0 is ignored. */ - getInitialWidth(): number { + public getInitialWidth(): number { return this._initialWidth; } @@ -419,7 +418,7 @@ const Imageable = ( type: SuperType ) => { * * @param height - Expected height of the image's unloaded content */ - setInitialHeight( height: number ): this { + public setInitialHeight( height: number ): this { assert && assert( typeof height === 'number' && height >= 0 && ( height % 1 === 0 ), 'initialHeight should be a non-negative integer' ); if ( height !== this._initialHeight ) { @@ -431,16 +430,16 @@ const Imageable = ( type: SuperType ) => { return this; } - set initialHeight( value: number ) { this.setInitialHeight( value ); } + public set initialHeight( value: number ) { this.setInitialHeight( value ); } - get initialHeight(): number { return this.getInitialHeight(); } + public get initialHeight(): number { return this.getInitialHeight(); } /** * Returns the initialHeight value set from setInitialHeight(). * * See setInitialHeight() for more documentation. A value of 0 is ignored. */ - getInitialHeight(): number { + public getInitialHeight(): number { return this._initialHeight; } @@ -455,7 +454,7 @@ const Imageable = ( type: SuperType ) => { * * @param mipmap - Whether mipmapping is supported */ - setMipmap( mipmap: boolean ): this { + public setMipmap( mipmap: boolean ): this { assert && assert( typeof mipmap === 'boolean' ); if ( this._mipmap !== mipmap ) { @@ -467,16 +466,16 @@ const Imageable = ( type: SuperType ) => { return this; } - set mipmap( value: boolean ) { this.setMipmap( value ); } + public set mipmap( value: boolean ) { this.setMipmap( value ); } - get mipmap(): boolean { return this.isMipmap(); } + public get mipmap(): boolean { return this.isMipmap(); } /** * Returns whether mipmapping is supported. * * See setMipmap() for more documentation. */ - isMipmap(): boolean { + public isMipmap(): boolean { return this._mipmap; } @@ -494,7 +493,7 @@ const Imageable = ( type: SuperType ) => { * This is done approximately like the following formula: * mipmapLevel = Utils.roundSymmetric( computedMipmapLevel + mipmapBias ) */ - setMipmapBias( bias: number ): this { + public setMipmapBias( bias: number ): this { assert && assert( typeof bias === 'number' ); if ( this._mipmapBias !== bias ) { @@ -506,16 +505,16 @@ const Imageable = ( type: SuperType ) => { return this; } - set mipmapBias( value: number ) { this.setMipmapBias( value ); } + public set mipmapBias( value: number ) { this.setMipmapBias( value ); } - get mipmapBias(): number { return this.getMipmapBias(); } + public get mipmapBias(): number { return this.getMipmapBias(); } /** * Returns the current mipmap bias. * * See setMipmapBias() for more documentation. */ - getMipmapBias(): number { + public getMipmapBias(): number { return this._mipmapBias; } @@ -525,7 +524,7 @@ const Imageable = ( type: SuperType ) => { * * @param level - A non-negative integer representing the number of mipmap levels to precompute. */ - setMipmapInitialLevel( level: number ): this { + public setMipmapInitialLevel( level: number ): this { assert && assert( typeof level === 'number' && level % 1 === 0 && level >= 0, 'mipmapInitialLevel should be a non-negative integer' ); @@ -538,16 +537,16 @@ const Imageable = ( type: SuperType ) => { return this; } - set mipmapInitialLevel( value: number ) { this.setMipmapInitialLevel( value ); } + public set mipmapInitialLevel( value: number ) { this.setMipmapInitialLevel( value ); } - get mipmapInitialLevel(): number { return this.getMipmapInitialLevel(); } + public get mipmapInitialLevel(): number { return this.getMipmapInitialLevel(); } /** * Returns the current initial mipmap level. * * See setMipmapInitialLevel() for more documentation. */ - getMipmapInitialLevel(): number { + public getMipmapInitialLevel(): number { return this._mipmapInitialLevel; } @@ -560,7 +559,7 @@ const Imageable = ( type: SuperType ) => { * * @param level - A non-negative integer representing the maximum mipmap level to compute. */ - setMipmapMaxLevel( level: number ): this { + public setMipmapMaxLevel( level: number ): this { assert && assert( typeof level === 'number' && level % 1 === 0 && level >= 0, 'mipmapMaxLevel should be a non-negative integer' ); @@ -573,16 +572,16 @@ const Imageable = ( type: SuperType ) => { return this; } - set mipmapMaxLevel( value: number ) { this.setMipmapMaxLevel( value ); } + public set mipmapMaxLevel( value: number ) { this.setMipmapMaxLevel( value ); } - get mipmapMaxLevel(): number { return this.getMipmapMaxLevel(); } + public get mipmapMaxLevel(): number { return this.getMipmapMaxLevel(); } /** * Returns the current maximum mipmap level. * * See setMipmapMaxLevel() for more documentation. */ - getMipmapMaxLevel(): number { + public getMipmapMaxLevel(): number { return this._mipmapMaxLevel; } @@ -592,7 +591,7 @@ const Imageable = ( type: SuperType ) => { * * See https://github.com/phetsims/scenery/issues/1049 for more information. */ - setHitTestPixels( hitTestPixels: boolean ): this { + public setHitTestPixels( hitTestPixels: boolean ): this { assert && assert( typeof hitTestPixels === 'boolean', 'hitTestPixels should be a boolean' ); if ( this._hitTestPixels !== hitTestPixels ) { @@ -604,23 +603,23 @@ const Imageable = ( type: SuperType ) => { return this; } - set hitTestPixels( value: boolean ) { this.setHitTestPixels( value ); } + public set hitTestPixels( value: boolean ) { this.setHitTestPixels( value ); } - get hitTestPixels(): boolean { return this.getHitTestPixels(); } + public get hitTestPixels(): boolean { return this.getHitTestPixels(); } /** * Returns whether pixels are checked for hit testing. * * See setHitTestPixels() for more documentation. */ - getHitTestPixels(): boolean { + public getHitTestPixels(): boolean { return this._hitTestPixels; } /** * Constructs the next available (uncomputed) mipmap level, as long as the previous level was larger than 1x1. */ - _constructNextMipmap(): void { + private _constructNextMipmap(): void { const level = this._mipmapCanvases.length; const biggerCanvas = this._mipmapCanvases[ level - 1 ]; @@ -646,7 +645,7 @@ const Imageable = ( type: SuperType ) => { /** * Triggers recomputation of mipmaps (as long as mipmapping is enabled) */ - invalidateMipmaps(): void { + public invalidateMipmaps(): void { // Clean output arrays cleanArray( this._mipmapCanvases ); cleanArray( this._mipmapURLs ); @@ -693,7 +692,7 @@ const Imageable = ( type: SuperType ) => { * @param matrix - The relative transformation matrix of the node. * @param [additionalBias] - Can be provided to get per-call bias (we want some of this for Canvas output) */ - getMipmapLevel( matrix: Matrix3, additionalBias = 0 ): number { + public getMipmapLevel( matrix: Matrix3, additionalBias = 0 ): number { assert && assert( this._mipmap, 'Assumes mipmaps can be used' ); // Handle high-dpi devices like retina with correct mipmap levels. @@ -705,7 +704,7 @@ const Imageable = ( type: SuperType ) => { /** * Returns the desired mipmap level (0-indexed) that should be used for the particular scale */ - getMipmapLevelFromScale( scale: number, additionalBias = 0 ): number { + public getMipmapLevelFromScale( scale: number, additionalBias = 0 ): number { assert && assert( typeof scale === 'number' && scale > 0, 'scale should be a positive number' ); // If we are shown larger than scale, ALWAYS choose the highest resolution @@ -747,7 +746,7 @@ const Imageable = ( type: SuperType ) => { * @param level - Non-negative integer representing the mipmap level * @returns - Matching for the level of detail */ - getMipmapCanvas( level: number ): HTMLCanvasElement { + public getMipmapCanvas( level: number ): HTMLCanvasElement { assert && assert( typeof level === 'number' && level >= 0 && level < this._mipmapCanvases.length && @@ -768,7 +767,7 @@ const Imageable = ( type: SuperType ) => { * @param level - Non-negative integer representing the mipmap level * @returns - Matching data URL for the level of detail */ - getMipmapURL( level: number ): string { + public getMipmapURL( level: number ): string { assert && assert( typeof level === 'number' && level >= 0 && level < this._mipmapCanvases.length && @@ -780,14 +779,14 @@ const Imageable = ( type: SuperType ) => { /** * Returns whether there are mipmap levels that have been computed. (scenery-internal) */ - hasMipmaps(): boolean { + public hasMipmaps(): boolean { return this._mipmapCanvases.length > 0; } /** * Triggers recomputation of hit test data */ - _invalidateHitTestData(): void { + private _invalidateHitTestData(): void { // Only compute this if we are hit-testing pixels if ( !this._hitTestPixels ) { return; @@ -803,7 +802,7 @@ const Imageable = ( type: SuperType ) => { * * NOTE: If the image is not loaded and an initialWidth was provided, that width will be used. */ - getImageWidth(): number { + public getImageWidth(): number { if ( this._image === null ) { return 0; } @@ -819,14 +818,14 @@ const Imageable = ( type: SuperType ) => { } } - get imageWidth(): number { return this.getImageWidth(); } + public get imageWidth(): number { return this.getImageWidth(); } /** * Returns the height of the displayed image (not related to how this node is transformed). * * NOTE: If the image is not loaded and an initialHeight was provided, that height will be used. */ - getImageHeight(): number { + public getImageHeight(): number { if ( this._image === null ) { return 0; } @@ -842,12 +841,12 @@ const Imageable = ( type: SuperType ) => { } } - get imageHeight(): number { return this.getImageHeight(); } + public get imageHeight(): number { return this.getImageHeight(); } /** * If our provided image is an HTMLImageElement, returns its URL (src). (scenery-internal) */ - getImageURL(): string { + public getImageURL(): string { assert && assert( this._image instanceof HTMLImageElement, 'Only supported for HTML image elements' ); return ( this._image as HTMLImageElement ).src; @@ -856,7 +855,7 @@ const Imageable = ( type: SuperType ) => { /** * Attaches our on-load listener to our current image. */ - _attachImageLoadListener(): void { + private _attachImageLoadListener(): void { assert && assert( !this._imageLoadListenerAttached, 'Should only be attached to one thing at a time' ); if ( !this.isDisposed ) { @@ -868,7 +867,7 @@ const Imageable = ( type: SuperType ) => { /** * Detaches our on-load listener from our current image. */ - _detachImageLoadListener(): void { + private _detachImageLoadListener(): void { assert && assert( this._imageLoadListenerAttached, 'Needs to be attached first to be detached.' ); ( this._image as HTMLImageElement ).removeEventListener( 'load', this._imageLoadListener ); @@ -878,7 +877,7 @@ const Imageable = ( type: SuperType ) => { /** * Called when our image has loaded (it was not yet loaded with then listener was added) */ - _onImageLoad(): void { + private _onImageLoad(): void { assert && assert( this._imageLoadListenerAttached, 'If _onImageLoad is firing, it should be attached' ); this.invalidateImage(); @@ -888,7 +887,7 @@ const Imageable = ( type: SuperType ) => { /** * Disposes the path, releasing image listeners if needed (and preventing new listeners from being added). */ - dispose(): void { + public dispose(): void { if ( this._image && this._imageLoadListenerAttached ) { this._detachImageLoadListener(); } diff --git a/js/nodes/Leaf.ts b/js/nodes/Leaf.ts index dad9508e7..3f515ab55 100644 --- a/js/nodes/Leaf.ts +++ b/js/nodes/Leaf.ts @@ -14,16 +14,16 @@ import Constructor from '../../../phet-core/js/types/Constructor.js'; const Leaf = memoize( ( type: SuperType ) => { assert && assert( _.includes( inheritance( type ), Node ), 'Only Node subtypes should mix Leaf' ); - return class extends type { - constructor( ...args: any[] ) { + return class LeafMixin extends type { + public constructor( ...args: any[] ) { super( ...args ); } - insertChild( index: number, node: Node ): void { + public insertChild( index: number, node: Node ): void { throw new Error( 'Attempt to insert child into Leaf' ); } - removeChildWithIndex( node: Node, indexOfChild: number ): void { + public removeChildWithIndex( node: Node, indexOfChild: number ): void { throw new Error( 'Attempt to remove child from Leaf' ); } }; diff --git a/js/nodes/Paintable.ts b/js/nodes/Paintable.ts index 5ec2af28e..3f98b1543 100644 --- a/js/nodes/Paintable.ts +++ b/js/nodes/Paintable.ts @@ -68,18 +68,21 @@ const PAINTABLE_DRAWABLE_MARK_FLAGS = [ 'fill', 'stroke', 'lineWidth', 'lineOpti const Paintable = memoize( ( type: SuperType ) => { assert && assert( _.includes( inheritance( type ), Node ), 'Only Node subtypes should mix Paintable' ); - return class extends type { + return class PaintableMixin extends type { - _fill: IPaint; - _fillPickable: boolean; + // (scenery-internal) + public _fill: IPaint; + public _fillPickable: boolean; - _stroke: IPaint; - _strokePickable: boolean; + // (scenery-internal) + public _stroke: IPaint; + public _strokePickable: boolean; - _cachedPaints: Paint[]; - _lineDrawingStyles: LineStyles; + // (scenery-internal) + public _cachedPaints: Paint[]; + public _lineDrawingStyles: LineStyles; - constructor( ...args: any[] ) { + public constructor( ...args: any[] ) { super( ...args ); assertHasProperties( this, [ '_drawables' ] ); @@ -103,7 +106,7 @@ const Paintable = memoize( ( type: SuperType ) => * provided for a single-color flat appearance, and can be wrapped with an Axon Property. Gradients and patterns * can also be provided. */ - setFill( fill: IPaint ): this { + public setFill( fill: IPaint ): this { assert && assert( PaintDef.isPaintDef( fill ), 'Invalid fill type' ); if ( assert && typeof fill === 'string' ) { @@ -121,34 +124,34 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set fill( value: IPaint ) { this.setFill( value ); } + public set fill( value: IPaint ) { this.setFill( value ); } - get fill(): IPaint { return this.getFill(); } + public get fill(): IPaint { return this.getFill(); } /** * Returns the fill (if any) for this Node. */ - getFill(): IPaint { + public getFill(): IPaint { return this._fill; } /** * Returns whether there is a fill applied to this Node. */ - hasFill(): boolean { + public hasFill(): boolean { return this.getFillValue() !== null; } /** * Returns a property-unwrapped fill if applicable. */ - getFillValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { + public getFillValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { const fill = this.getFill(); return fill instanceof ReadOnlyProperty ? fill.get() : fill; } - get fillValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { return this.getFillValue(); } + public get fillValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { return this.getFillValue(); } /** * Sets the stroke color for the Node. @@ -162,7 +165,7 @@ const Paintable = memoize( ( type: SuperType ) => * provided for a single-color flat appearance, and can be wrapped with an Axon Property. Gradients and patterns * can also be provided. */ - setStroke( stroke: IPaint ): this { + public setStroke( stroke: IPaint ): this { assert && assert( PaintDef.isPaintDef( stroke ), 'Invalid stroke type' ); if ( assert && typeof stroke === 'string' ) { @@ -180,28 +183,28 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set stroke( value: IPaint ) { this.setStroke( value ); } + public set stroke( value: IPaint ) { this.setStroke( value ); } - get stroke(): IPaint { return this.getStroke(); } + public get stroke(): IPaint { return this.getStroke(); } /** * Returns the stroke (if any) for this Node. */ - getStroke(): IPaint { + public getStroke(): IPaint { return this._stroke; } /** * Returns whether there is a stroke applied to this Node. */ - hasStroke(): boolean { + public hasStroke(): boolean { return this.getStrokeValue() !== null; } /** * Returns whether there will appear to be a stroke for this Node. Properly handles the lineWidth:0 case. */ - hasPaintableStroke(): boolean { + public hasPaintableStroke(): boolean { // Should not be stroked if the lineWidth is 0, see https://github.com/phetsims/scenery/issues/658 // and https://github.com/phetsims/scenery/issues/523 return this.hasStroke() && this.getLineWidth() > 0; @@ -210,18 +213,18 @@ const Paintable = memoize( ( type: SuperType ) => /** * Returns a property-unwrapped stroke if applicable. */ - getStrokeValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { + public getStrokeValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { const stroke = this.getStroke(); return stroke instanceof ReadOnlyProperty ? stroke.get() : stroke; } - get strokeValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { return this.getStrokeValue(); } + public get strokeValue(): null | string | Color | LinearGradient | RadialGradient | Pattern { return this.getStrokeValue(); } /** * Sets whether the fill is marked as pickable. */ - setFillPickable( pickable: boolean ): this { + public setFillPickable( pickable: boolean ): this { assert && assert( typeof pickable === 'boolean' ); if ( this._fillPickable !== pickable ) { @@ -233,21 +236,21 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set fillPickable( value: boolean ) { this.setFillPickable( value ); } + public set fillPickable( value: boolean ) { this.setFillPickable( value ); } - get fillPickable(): boolean { return this.isFillPickable(); } + public get fillPickable(): boolean { return this.isFillPickable(); } /** * Returns whether the fill is marked as pickable. */ - isFillPickable(): boolean { + public isFillPickable(): boolean { return this._fillPickable; } /** * Sets whether the stroke is marked as pickable. */ - setStrokePickable( pickable: boolean ): this { + public setStrokePickable( pickable: boolean ): this { assert && assert( typeof pickable === 'boolean', `strokePickable should be a boolean, not ${pickable}` ); if ( this._strokePickable !== pickable ) { @@ -259,21 +262,21 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set strokePickable( value: boolean ) { this.setStrokePickable( value ); } + public set strokePickable( value: boolean ) { this.setStrokePickable( value ); } - get strokePickable(): boolean { return this.isStrokePickable(); } + public get strokePickable(): boolean { return this.isStrokePickable(); } /** * Returns whether the stroke is marked as pickable. */ - isStrokePickable(): boolean { + public isStrokePickable(): boolean { return this._strokePickable; } /** * Sets the line width that will be applied to strokes on this Node. */ - setLineWidth( lineWidth: number ): this { + public setLineWidth( lineWidth: number ): this { assert && assert( typeof lineWidth === 'number', `lineWidth should be a number, not ${lineWidth}` ); assert && assert( lineWidth >= 0, `lineWidth should be non-negative instead of ${lineWidth}` ); @@ -289,14 +292,14 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set lineWidth( value: number ) { this.setLineWidth( value ); } + public set lineWidth( value: number ) { this.setLineWidth( value ); } - get lineWidth(): number { return this.getLineWidth(); } + public get lineWidth(): number { return this.getLineWidth(); } /** * Returns the line width that would be applied to strokes. */ - getLineWidth(): number { + public getLineWidth(): number { return this._lineDrawingStyles.lineWidth; } @@ -306,7 +309,7 @@ const Paintable = memoize( ( type: SuperType ) => * - 'round' draws a semicircular arc around the end point * - 'square' draws a square outline around the end point (like butt, but extended by 1/2 line width out) */ - setLineCap( lineCap: LineCap ): this { + public setLineCap( lineCap: LineCap ): this { assert && assert( lineCap === 'butt' || lineCap === 'round' || lineCap === 'square', `lineCap should be one of "butt", "round" or "square", not ${lineCap}` ); @@ -322,14 +325,14 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set lineCap( value: LineCap ) { this.setLineCap( value ); } + public set lineCap( value: LineCap ) { this.setLineCap( value ); } - get lineCap(): LineCap { return this.getLineCap(); } + public get lineCap(): LineCap { return this.getLineCap(); } /** * Returns the line cap style (controls appearance at the start/end of paths) */ - getLineCap(): LineCap { + public getLineCap(): LineCap { return this._lineDrawingStyles.lineCap; } @@ -340,7 +343,7 @@ const Paintable = memoize( ( type: SuperType ) => * - 'round' draws a circular arc to connect the two stroked areas. * - 'bevel' connects with a single line segment. */ - setLineJoin( lineJoin: LineJoin ): this { + public setLineJoin( lineJoin: LineJoin ): this { assert && assert( lineJoin === 'miter' || lineJoin === 'round' || lineJoin === 'bevel', `lineJoin should be one of "miter", "round" or "bevel", not ${lineJoin}` ); @@ -356,14 +359,14 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set lineJoin( value: LineJoin ) { this.setLineJoin( value ); } + public set lineJoin( value: LineJoin ) { this.setLineJoin( value ); } - get lineJoin(): LineJoin { return this.getLineJoin(); } + public get lineJoin(): LineJoin { return this.getLineJoin(); } /** * Returns the current line join style (controls join appearance between drawn segments). */ - getLineJoin(): LineJoin { + public getLineJoin(): LineJoin { return this._lineDrawingStyles.lineJoin; } @@ -371,7 +374,7 @@ const Paintable = memoize( ( type: SuperType ) => * Sets the miterLimit value. This determines how sharp a corner with lineJoin: 'miter' will need to be before * it gets cut off to the 'bevel' behavior. */ - setMiterLimit( miterLimit: number ): this { + public setMiterLimit( miterLimit: number ): this { assert && assert( typeof miterLimit === 'number' && isFinite( miterLimit ), 'miterLimit should be a finite number' ); if ( this._lineDrawingStyles.miterLimit !== miterLimit ) { @@ -386,14 +389,14 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set miterLimit( value: number ) { this.setMiterLimit( value ); } + public set miterLimit( value: number ) { this.setMiterLimit( value ); } - get miterLimit(): number { return this.getMiterLimit(); } + public get miterLimit(): number { return this.getMiterLimit(); } /** * Returns the miterLimit value. */ - getMiterLimit(): number { + public getMiterLimit(): number { return this._lineDrawingStyles.miterLimit; } @@ -401,7 +404,7 @@ const Paintable = memoize( ( type: SuperType ) => * Sets the line dash pattern. Should be an array of numbers "on" and "off" alternating. An empty array * indicates no dashing. */ - setLineDash( lineDash: number[] ): this { + public setLineDash( lineDash: number[] ): this { assert && assert( Array.isArray( lineDash ) && lineDash.every( n => typeof n === 'number' && isFinite( n ) && n >= 0 ), 'lineDash should be an array of finite non-negative numbers' ); @@ -417,28 +420,28 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set lineDash( value: number[] ) { this.setLineDash( value ); } + public set lineDash( value: number[] ) { this.setLineDash( value ); } - get lineDash(): number[] { return this.getLineDash(); } + public get lineDash(): number[] { return this.getLineDash(); } /** * Gets the line dash pattern. An empty array is the default, indicating no dashing. */ - getLineDash(): number[] { + public getLineDash(): number[] { return this._lineDrawingStyles.lineDash; } /** * Returns whether the stroke will be dashed. */ - hasLineDash(): boolean { + public hasLineDash(): boolean { return !!this._lineDrawingStyles.lineDash.length; } /** * Sets the offset of the line dash pattern from the start of the stroke. Defaults to 0. */ - setLineDashOffset( lineDashOffset: number ): this { + public setLineDashOffset( lineDashOffset: number ): this { assert && assert( typeof lineDashOffset === 'number' && isFinite( lineDashOffset ), `lineDashOffset should be a number, not ${lineDashOffset}` ); @@ -454,21 +457,21 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set lineDashOffset( value: number ) { this.setLineDashOffset( value ); } + public set lineDashOffset( value: number ) { this.setLineDashOffset( value ); } - get lineDashOffset(): number { return this.getLineDashOffset(); } + public get lineDashOffset(): number { return this.getLineDashOffset(); } /** * Returns the offset of the line dash pattern from the start of the stroke. */ - getLineDashOffset(): number { + public getLineDashOffset(): number { return this._lineDrawingStyles.lineDashOffset; } /** * Sets the LineStyles object (it determines stroke appearance). The passed-in object will be mutated as needed. */ - setLineStyles( lineStyles: LineStyles ): this { + public setLineStyles( lineStyles: LineStyles ): this { assert && assert( lineStyles instanceof LineStyles ); this._lineDrawingStyles = lineStyles; @@ -476,14 +479,14 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set lineStyles( value: LineStyles ) { this.setLineStyles( value ); } + public set lineStyles( value: LineStyles ) { this.setLineStyles( value ); } - get lineStyles(): LineStyles { return this.getLineStyles(); } + public get lineStyles(): LineStyles { return this.getLineStyles(); } /** * Returns the composite {LineStyles} object, that determines stroke appearance. */ - getLineStyles(): LineStyles { + public getLineStyles(): LineStyles { return this._lineDrawingStyles; } @@ -497,7 +500,7 @@ const Paintable = memoize( ( type: SuperType ) => * * Also note that duplicate paints are acceptable, and don't need to be filtered out before-hand. */ - setCachedPaints( paints: IPaint[] ): this { + public setCachedPaints( paints: IPaint[] ): this { this._cachedPaints = paints.filter( ( paint: IPaint ): paint is Paint => paint instanceof Paint ); const stateLen = ( this as unknown as Node )._drawables.length; @@ -508,14 +511,14 @@ const Paintable = memoize( ( type: SuperType ) => return this; } - set cachedPaints( value: IPaint[] ) { this.setCachedPaints( value ); } + public set cachedPaints( value: IPaint[] ) { this.setCachedPaints( value ); } - get cachedPaints(): IPaint[] { return this.getCachedPaints(); } + public get cachedPaints(): IPaint[] { return this.getCachedPaints(); } /** * Returns the cached paints. */ - getCachedPaints(): IPaint[] { + public getCachedPaints(): IPaint[] { return this._cachedPaints; } @@ -529,7 +532,7 @@ const Paintable = memoize( ( type: SuperType ) => * * Also note that duplicate paints are acceptable, and don't need to be filtered out before-hand. */ - addCachedPaint( paint: IPaint ): void { + public addCachedPaint( paint: IPaint ): void { if ( paint instanceof Paint ) { this._cachedPaints.push( paint ); @@ -549,7 +552,7 @@ const Paintable = memoize( ( type: SuperType ) => * element, so that we can switch quickly to use the given paint (instead of having to create it on the * SVG-side whenever the switch is made). */ - removeCachedPaint( paint: IPaint ): void { + public removeCachedPaint( paint: IPaint ): void { if ( paint instanceof Paint ) { assert && assert( _.includes( this._cachedPaints, paint ) ); @@ -565,7 +568,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * Applies the fill to a Canvas context wrapper, before filling. (scenery-internal) */ - beforeCanvasFill( wrapper: CanvasContextWrapper ): void { + public beforeCanvasFill( wrapper: CanvasContextWrapper ): void { assert && assert( this.getFillValue() !== null ); const fillValue = this.getFillValue()!; @@ -582,7 +585,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * Un-applies the fill to a Canvas context wrapper, after filling. (scenery-internal) */ - afterCanvasFill( wrapper: CanvasContextWrapper ): void { + public afterCanvasFill( wrapper: CanvasContextWrapper ): void { const fillValue = this.getFillValue(); // @ts-ignore @@ -594,7 +597,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * Applies the stroke to a Canvas context wrapper, before stroking. (scenery-internal) */ - beforeCanvasStroke( wrapper: CanvasContextWrapper ): void { + public beforeCanvasStroke( wrapper: CanvasContextWrapper ): void { const strokeValue = this.getStrokeValue(); // TODO: is there a better way of not calling so many things on each stroke? @@ -617,7 +620,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * Un-applies the stroke to a Canvas context wrapper, after stroking. (scenery-internal) */ - afterCanvasStroke( wrapper: CanvasContextWrapper ): void { + public afterCanvasStroke( wrapper: CanvasContextWrapper ): void { const strokeValue = this.getStrokeValue(); // @ts-ignore - for performance @@ -629,7 +632,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * If applicable, returns the CSS color for the fill. */ - getCSSFill(): string { + public getCSSFill(): string { const fillValue = this.getFillValue(); // if it's a Color object, get the corresponding CSS // 'transparent' will make us invisible if the fill is null @@ -640,7 +643,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * If applicable, returns the CSS color for the stroke. */ - getSimpleCSSStroke(): string { + public getSimpleCSSStroke(): string { const strokeValue = this.getStrokeValue(); // if it's a Color object, get the corresponding CSS // 'transparent' will make us invisible if the fill is null @@ -654,7 +657,7 @@ const Paintable = memoize( ( type: SuperType ) => * @param spaces - Whitespace to add * @param result */ - appendFillablePropString( spaces: string, result: string ): string { + public appendFillablePropString( spaces: string, result: string ): string { if ( this._fill ) { if ( result ) { result += ',\n'; @@ -676,7 +679,7 @@ const Paintable = memoize( ( type: SuperType ) => * @param spaces - Whitespace to add * @param result */ - appendStrokablePropString( spaces: string, result: string ): string { + public appendStrokablePropString( spaces: string, result: string ): string { function addProp( key: string, value: any, nowrap?: boolean ) { if ( result ) { result += ',\n'; @@ -724,7 +727,7 @@ const Paintable = memoize( ( type: SuperType ) => * * @returns - Renderer bitmask, see Renderer for details */ - getFillRendererBitmask(): number { + public getFillRendererBitmask(): number { let bitmask = 0; // Safari 5 has buggy issues with SVG gradients @@ -764,7 +767,7 @@ const Paintable = memoize( ( type: SuperType ) => * * @returns - Renderer bitmask, see Renderer for details */ - getStrokeRendererBitmask(): number { + public getStrokeRendererBitmask(): number { let bitmask = 0; bitmask |= Renderer.bitmaskCanvas; @@ -784,7 +787,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * Invalidates our current fill, triggering recomputation of anything that depended on the old fill's value */ - invalidateFill(): void { + public invalidateFill(): void { const thisNode = this as unknown as Node; thisNode.invalidateSupportedRenderers(); @@ -798,7 +801,7 @@ const Paintable = memoize( ( type: SuperType ) => /** * Invalidates our current stroke, triggering recomputation of anything that depended on the old stroke's value */ - invalidateStroke(): void { + public invalidateStroke(): void { const thisNode = this as unknown as Node; thisNode.invalidateSupportedRenderers(); diff --git a/js/nodes/RichText.ts b/js/nodes/RichText.ts index 3ce03c9af..97b3836fa 100644 --- a/js/nodes/RichText.ts +++ b/js/nodes/RichText.ts @@ -1560,15 +1560,15 @@ scenery.register( 'RichText', RichText ); const RichTextCleanable = memoize( ( type: SuperType ) => { assert && assert( _.includes( inheritance( type ), Node ), 'Only Node subtypes should mix Paintable' ); - return class extends type { - get isCleanable(): boolean { + return class RichTextCleanableMixin extends type { + public get isCleanable(): boolean { return true; } /** * Releases references */ - clean(): void { + public clean(): void { const thisNode = this as unknown as RichTextCleanableNode; // Remove all children (and recursively clean) diff --git a/js/util/DelayedMutate.ts b/js/util/DelayedMutate.ts index d7b7e0a56..17bd88903 100644 --- a/js/util/DelayedMutate.ts +++ b/js/util/DelayedMutate.ts @@ -43,13 +43,13 @@ const DelayedMutate = ( name: string, keys: strin const pendingOptionsKey = `_${name}PendingOptions` as '_fakePendingOptionsType'; const isConstructedKey = `_${name}IsConstructed` as '_fakeIsConstructedType'; - return class DelayedMutate extends type { + return class DelayedMutateMixin extends type { // We need to store different fields in each class, so we use computed properties private [ isConstructedKey ]: boolean; private [ pendingOptionsKey ]: NodeOptions | undefined; - constructor( ...args: any[] ) { + public constructor( ...args: any[] ) { super( ...args ); // Mark ourself as constructed, so further mutates will use all of the options @@ -63,7 +63,7 @@ const DelayedMutate = ( name: string, keys: strin } // Typescript doesn't want an override here, but we're overriding it - mutate( options?: NodeOptions ): this { + public mutate( options?: NodeOptions ): this { // If we're not constructed, we need to save the options for later // NOTE: If we haven't SET the constructed field yet, then it will be undefined (and falsy), so we do a check