iwmlib/pixi/tooltip.js
2019-03-21 09:57:27 +01:00

156 lines
4.2 KiB
JavaScript

import Theme from './theme.js'
import AbstractPopup from './abstractpopup.js'
/**
* Class that represents a PixiJS Tooltip.
*
* @example
* // Create the app
* const app = new PIXIApp({
* view: canvas,
* width: 900,
* height: 250
* }).setup().run()
*
* // Add an DisplayObject to the app
* const circle = new PIXI.Graphics()
* circle.beginFill(0x5251a3)
* circle.drawCircle(50, 50, 40)
* app.scene.addChild(circle)
*
* const tooltip = new Tooltip({
* object: circle,
* container: app.scene,
* content: 'Das Gesetz ist der Freund des Schwachen.'
* })
*
* @class
* @extends AbstractPopup
* @see {@link https://www.iwm-tuebingen.de/iwmbrowser/lib/pixi/tooltip.html|DocTest}
*/
export default class Tooltip extends AbstractPopup {
/**
* Creates an instance of a Tooltip.
*
* @constructor
* @param {object} [opts] - An options object to specify to style and behaviour of the tooltip.
* @param {number} [opts.minWidth=0] - The minimum width of the tooltip.
* @param {number} [opts.minHeight=0] - The minimum height of the tooltip.
* @param {number} [opts.padding=Theme.padding / 2] - The inner spacing of the tooltip.
* @param {PIXI.DisplayObject} opts.object - The object, where the tooltip should be displayed.
* @param {PIXI.DisplayObject} [opts.container=object] - The container where the tooltip should be attached to.
* @param {number} [opts.offsetLeft=8] - The horizontal shift of the tooltip.
* @param {number} [opts.offsetTop=-8] - The vertical shift of the tooltip.
* @param {number} [opts.delay=0] - A delay, after which the tooltip should be opened.
*/
constructor(opts = {}) {
const theme = Theme.fromString(opts.theme)
opts = Object.assign({}, {
minWidth: 0,
minHeight: 0,
padding: theme.padding / 2,
object: null,
container: null,
offsetLeft: 8,
offsetTop: -8,
delay: 0
}, opts)
opts.container = opts.container || opts.object
super(opts)
// setup
//-----------------
this.setup()
// layout
//-----------------
this.layout()
}
/**
* Creates children and instantiates everything.
*
* @private
* @return {Tooltip} A reference to the tooltip for chaining.
*/
setup() {
super.setup()
// bind events this
//-----------------
this.interactive = true
let mouseoverTooltip = false
this.on('mouseover', e => {
mouseoverTooltip = true
})
this.on('mouseout', e => {
mouseoverTooltip = false
if (!mouseoverObject) {
this.hide(() => {
this.opts.container.removeChild(this)
})
}
})
// bind events object
//-----------------
const object = this.opts.object
object.interactive = true
let mouseoverObject = false
object.on('mouseover', e => {
this.timeout = window.setTimeout(() => {
mouseoverObject = true
this.visible = true
this.opts.container.addChild(this)
this.setPosition(e)
}, this.opts.delay * 1000)
})
object.on('mousemove', e => {
if (mouseoverObject) {
this.setPosition(e)
}
})
object.on('mouseout', e => {
mouseoverObject = false
window.clearTimeout(this.timeout)
if (!mouseoverTooltip) {
this.hide(() => {
this.opts.container.removeChild(this)
})
}
})
return this
}
/**
* Calculates and sets the position of the tooltip.
*
* @private
* @return {Tooltip} A reference to the tooltip for chaining.
*/
setPosition(e) {
const position = e.data.getLocalPosition(this.opts.container)
this.x = position.x + this.opts.offsetLeft
this.y = position.y + this.opts.offsetTop - this.height
return this
}
}