358 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import Theme from './theme.js'
 | |
| 
 | |
| /**
 | |
|  * Class that represents a PixiJS AbstractPopup.
 | |
|  * The class is used for various other Popup-like classes
 | |
|  * like Popup, Message, Tooltip...
 | |
|  *
 | |
|  * @class
 | |
|  * @abstract
 | |
|  * @extends PIXI.Graphics
 | |
|  * @see {@link http://pixijs.download/dev/docs/PIXI.Graphics.html|PIXI.Graphics}
 | |
|  */
 | |
| export default class AbstractPopup extends PIXI.Graphics {
 | |
|     
 | |
|     /**
 | |
|      * Creates an instance of an AbstractPopup (only for internal use).
 | |
|      * 
 | |
|      * @constructor
 | |
|      * @param {object} [opts] - An options object to specify to style and behaviour of the popup.
 | |
|      * @param {number} [opts.id=auto generated] - The id of the popup.
 | |
|      * @param {number} [opts.x=0] - The x position of the popup. Can be also set after creation with popup.x = 0.
 | |
|      * @param {number} [opts.y=0] - The y position of the popup. Can be also set after creation with popup.y = 0.
 | |
|      * @param {string|Theme} [opts.theme=dark] - The theme to use for this popup. Possible values are dark, light, red
 | |
|      *     or a Theme object.
 | |
|      * @param {string|number|PIXI.Text} [opts.header] - The heading inside the popup as a string, a number (will be
 | |
|      *     converted to a text) or as a PIXI.Text object.
 | |
|      * @param {string|number|PIXI.DisplayObject} [opts.content] - A text, a number (will be converted to a text) or
 | |
|      *     an PIXI.DisplayObject as the content of the popup.
 | |
|      * @param {number} [opts.minWidth=320] - The minimum width of the popup.
 | |
|      * @param {number} [opts.minHeight=130] - The minimum height of the popup.
 | |
|      * @param {number} [opts.padding=Theme.padding] - The inner spacing (distance from header and content) the the border.
 | |
|      * @param {number} [opts.fill=Theme.fill] - The color of the button background as a hex value.
 | |
|      * @param {number} [opts.fillAlpha=Theme.fillAlpha] - The alpha value of the background.
 | |
|      * @param {number} [opts.stroke=Theme.stroke] - The color of the border as a hex value.
 | |
|      * @param {number} [opts.strokeWidth=Theme.strokeWidth] - The width of the border in pixel.
 | |
|      * @param {number} [opts.strokeAlpha=Theme.strokeAlpha] - The alpha value of the border.
 | |
|      * @param {object} [opts.headerStyle=Theme.textStyleLarge] - A textstyle object for the styling of the header. See PIXI.TextStyle
 | |
|      *     for possible options.
 | |
|      * @param {object} [opts.textStyle=Theme.textStyleSmall] - A textstyle object for the styling of the text. See PIXI.TextStyle
 | |
|      *     for possible options.
 | |
|      * @param {number} [opts.radius=Theme.radius] - The radius of the four corners of the popup (which is a rounded rectangle).
 | |
|      * @param {hiddenCallback} [opts.onHidden] - Executed when the popup gets hidden.
 | |
|      * @param {boolean} [opts.visible=true] - Is the popup initially visible (property visible)?
 | |
|      * @param {string} [opts.orientation] - When set to portrait, the popup cannot be displayed in landscape mode. When set
 | |
|      *     to landscape, the popup cannot be displayed in portrait mode.
 | |
|      */
 | |
|     constructor(opts = {}) {
 | |
| 
 | |
|         super()
 | |
|         
 | |
|         const theme = Theme.fromString(opts.theme)
 | |
|         this.theme = theme
 | |
| 
 | |
|         this.opts = Object.assign({}, {
 | |
|             id: PIXI.utils.uid(),
 | |
|             x: 0,
 | |
|             y: 0,
 | |
|             header: null,                       // null or null
 | |
|             content: null,                      // null or String or PIXI.DisplayObject
 | |
|             minWidth: 320,
 | |
|             minHeight: 130,
 | |
|             maxWidth: null,
 | |
|             padding: theme.padding,
 | |
|             fill: theme.fill,
 | |
|             fillAlpha: theme.fillAlpha,
 | |
|             stroke: theme.stroke,
 | |
|             strokeWidth: theme.strokeWidth,
 | |
|             strokeAlpha: theme.strokeAlpha,
 | |
|             headerStyle: theme.textStyleLarge,
 | |
|             textStyle: theme.textStyleSmall,
 | |
|             radius: theme.radius,
 | |
|             onHidden: null,
 | |
|             visible: true,
 | |
|             orientation: null
 | |
|         }, opts)
 | |
| 
 | |
|         this.id = this.opts.id
 | |
| 
 | |
|         this.headerStyle = new PIXI.TextStyle(this.opts.headerStyle)
 | |
|         this.textStyle = new PIXI.TextStyle(this.opts.textStyle)
 | |
| 
 | |
|         if (this.opts.maxWidth) {
 | |
|             this.headerStyle.wordWrap = true
 | |
|             this.headerStyle.wordWrapWidth = this.opts.maxWidth - (2 * this.opts.padding)
 | |
| 
 | |
|             this.textStyle.wordWrap = true
 | |
|             this.textStyle.wordWrapWidth = this.opts.maxWidth - (2 * this.opts.padding)
 | |
|         }
 | |
| 
 | |
|         this.alpha = 0
 | |
|         this.visible = this.opts.visible
 | |
| 
 | |
|         this._header = null
 | |
|         this._content = null
 | |
| 
 | |
|         // position
 | |
|         this.x = this.opts.x
 | |
|         this.y = this.opts.y
 | |
| 
 | |
|         // padding
 | |
|         this.innerPadding = this.opts.padding * 1.5
 | |
|         
 | |
|         // interaction
 | |
|         //-----------------
 | |
|         this.interactive = true
 | |
|         this.on('added', e => {
 | |
|             this.show()
 | |
|         })
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Creates the framework and instantiates everything.
 | |
|      * 
 | |
|      * @private
 | |
|      * @return {AbstractPopup} A reference to the popup for chaining.
 | |
|      */
 | |
|     setup() {
 | |
| 
 | |
|         // position
 | |
|         //-----------------
 | |
|         this.sy = this.opts.padding
 | |
| 
 | |
|         // header
 | |
|         //-----------------
 | |
|         if (this.opts.header != null) {
 | |
| 
 | |
|             let header = null
 | |
| 
 | |
|             if (this.opts.header instanceof PIXI.Text) {
 | |
|                 header = this.opts.header
 | |
|             } else if (typeof this.opts.header === 'number') {
 | |
|                 header =  new PIXI.Text(this.opts.header.toString(), this.headerStyle)
 | |
|             } else {
 | |
|                 header =  new PIXI.Text(this.opts.header, this.headerStyle)
 | |
|             }
 | |
| 
 | |
|             header.x = this.opts.padding
 | |
|             header.y = this.sy
 | |
| 
 | |
|             this.addChild(header)
 | |
| 
 | |
|             this.sy += header.height
 | |
| 
 | |
|             this._header = header
 | |
|         }
 | |
| 
 | |
|         if (this.opts.header && this.opts.content) {
 | |
|             this.sy += this.innerPadding
 | |
|         }
 | |
| 
 | |
|         // content
 | |
|         //-----------------
 | |
|         if (this.opts.content != null) {
 | |
| 
 | |
|             let content = null
 | |
| 
 | |
|             if (typeof this.opts.content === 'string') {
 | |
|                 content = new PIXI.Text(this.opts.content, this.textStyle)
 | |
|             } else if (typeof this.opts.content === 'number') {
 | |
|                 content = new PIXI.Text(this.opts.content.toString(), this.textStyle)
 | |
|             } else {
 | |
|                 content = this.opts.content
 | |
|             }
 | |
| 
 | |
|             content.x = this.opts.padding
 | |
|             content.y = this.sy
 | |
| 
 | |
|             this.sy += content.height
 | |
| 
 | |
|             this.addChild(content)
 | |
| 
 | |
|             this._content = content
 | |
|         }
 | |
| 
 | |
|         return this
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Should be called to refresh the layout of the popup. Can be used after resizing.
 | |
|      * 
 | |
|      * @return {AbstractPopup} A reference to the popup for chaining.
 | |
|      */
 | |
|     layout() {
 | |
|         
 | |
|         // wanted width & wanted height
 | |
|         //-----------------
 | |
|         const padding = this.opts.padding
 | |
|         const size = this.getInnerSize()
 | |
|         const width = size.width + (2 * padding)
 | |
|         const height = size.height + (2 * padding)
 | |
| 
 | |
|         this.wantedWidth = Math.max(width, this.opts.minWidth)
 | |
|         this.wantedHeight = Math.max(height, this.opts.minHeight)
 | |
|         
 | |
|         if (this.opts.maxWidth) {
 | |
|             this.wantedWidth = Math.min(this.wantedWidth, this.opts.maxWidth)
 | |
|         }
 | |
| 
 | |
|         if (this.opts.radius * 2 > this.wantedWidth) {
 | |
|             this.wantedWidth = this.opts.radius * 2
 | |
|         }
 | |
| 
 | |
|         if (this.opts.radius * 2 > this.wantedHeight) {
 | |
|             this.wantedHeight = this.opts.radius * 2
 | |
|         }
 | |
| 
 | |
|         switch (this.opts.orientation) {
 | |
|             case 'portrait':
 | |
|                 if (this.wantedWidth > this.wantedHeight) {
 | |
|                     this.wantedHeight = this.wantedWidth
 | |
|                 }
 | |
|                 break
 | |
|             case 'landscape':
 | |
|                 if (this.wantedHeight > this.wantedWidth) {
 | |
|                     this.wantedWidth = this.wantedHeight
 | |
|                 }
 | |
|                 break
 | |
|         }
 | |
| 
 | |
|         this.draw()
 | |
| 
 | |
|         return this
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Draws the canvas.
 | |
|      * 
 | |
|      * @private
 | |
|      * @return {AbstractPopup} A reference to the popup for chaining.
 | |
|      */
 | |
|     draw() {
 | |
| 
 | |
|         const square = Math.round(this.wantedWidth) === Math.round(this.wantedHeight)
 | |
|         const diameter = Math.round(this.opts.radius * 2)
 | |
| 
 | |
|         this.clear()
 | |
|         this.lineStyle(this.opts.strokeWidth, this.opts.stroke, this.opts.strokeAlpha)
 | |
|         this.beginFill(this.opts.fill, this.opts.fillAlpha)
 | |
|         if (square && diameter === this.wantedWidth) {
 | |
|             this.drawCircle(this.wantedWidth / 2, this.wantedHeight / 2, this.opts.radius)
 | |
|         } else {
 | |
|             this.drawRoundedRect(0, 0, this.wantedWidth, this.wantedHeight, this.opts.radius)
 | |
|         }
 | |
|         this.endFill()
 | |
| 
 | |
|         return this
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Calculates the size of the children of the AbstractPopup.
 | |
|      * Cannot use getBounds() because it is not updated when children
 | |
|      * are removed.
 | |
|      * 
 | |
|      * @private
 | |
|      * @returns {object} An JavaScript object width the keys width and height.
 | |
|      */
 | |
|     getInnerSize() {
 | |
| 
 | |
|         let width = 0
 | |
|         let height = 0
 | |
| 
 | |
|         if (this._header) {
 | |
|             width = this._header.width
 | |
|             height = this._header.height
 | |
|         }
 | |
| 
 | |
|         if (this._header && this._content) {
 | |
|             height += this.innerPadding
 | |
|         }
 | |
| 
 | |
|         if (this._content) {
 | |
|             width = Math.max(width, this._content.width)
 | |
|             height += this._content.height
 | |
|         }
 | |
| 
 | |
|         return {width, height}
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Shows the popup (sets his alpha values to 1).
 | |
|      * 
 | |
|      * @param {callback} [cb] - Executed when show animation was completed.
 | |
|      * @return {AbstractPopup} A reference to the popup for chaining.
 | |
|      */
 | |
|     show(cb) {
 | |
| 
 | |
|         TweenLite.to(this, this.theme.fast, {
 | |
|             alpha: 1,
 | |
|             onComplete: () => {
 | |
|                 if (cb) {
 | |
|                     cb.call(this)
 | |
|                 }
 | |
|             }
 | |
|         })
 | |
| 
 | |
|         return this
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Hides the popup (sets his alpha values to 0).
 | |
|      * 
 | |
|      * @param {callback} [cb] - Executed when hide animation was completed.
 | |
|      * @return {AbstractPopup} A reference to the popup for chaining.
 | |
|      */
 | |
|     hide(cb) {
 | |
| 
 | |
|         TweenLite.to(this, this.theme.fast, {
 | |
|             alpha: 0,
 | |
|             onComplete: () => {
 | |
|                 this.visible = false
 | |
|                 if (cb) {
 | |
|                     cb.call(this)
 | |
|                 }
 | |
|             }
 | |
|         })
 | |
| 
 | |
|         if (this.opts.onHidden) {
 | |
|             this.opts.onHidden.call(this, this)
 | |
|         }
 | |
| 
 | |
|         return this
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets or gets the header. The getter always returns a PIXI.Text object. The setter can receive
 | |
|      * a string, a number or a PIXI.Text object.
 | |
|      * 
 | |
|      * @member {string|number|PIXI.Text}
 | |
|      */
 | |
|     get header() {
 | |
|         return this._header
 | |
|     }
 | |
|     set header(value) {
 | |
|         if (this._header) {
 | |
|             this._header.destroy()
 | |
|         }
 | |
|         this.opts.header = value
 | |
|         this.setup().layout()
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Sets or gets the content. The getter always returns an PIXI.DisplayObject. The setter can receive
 | |
|      * a string, a number or a PIXI.DisplayObject.
 | |
|      * 
 | |
|      * @member {string|number|PIXI.DisplayObject}
 | |
|      */
 | |
|     get content() {
 | |
|         return this._content
 | |
|     }
 | |
|     set content(value) {
 | |
|         if (this._content) {
 | |
|             this._content.destroy()
 | |
|         }
 | |
|         this.opts.content = value
 | |
|         this.setup().layout()
 | |
|     }
 | |
| }
 |