src/components/display/text_display.js
import _ from "lodash"
import Phaser from "phaser"
import Button from "../input/button"
import Element from "../element"
/**
* Draws an interactive button in the display
*/
class TextDisplay extends Element {
/**
* @param {object} scene - The container Phaser.Scene
* @param {number} x - The x position of the TextDisplay in the game world
* @param {number} y - The y position of the TextDisplay in the game world
* @param {number} [width=200] - Display width in pixels
* @param {number} [height=400] - Display height in pixels
* @param {string} [content=""] - The text displayed
*/
constructor(
scene,
{
x, y,
width=400, height=200,
initialText="",
hasOutline=true,
styles={
fontSize: 24,
fontFamily: "Helvetica",
align: "left",
padding: {top: 10, left: 10, right: 10, bottom: 10},
wordWrap: {width: width - 10}
}
}
) {
// set up basic attributes
super(
scene,
{
x: x,
y: y,
width: width,
height: height,
hasOutline: hasOutline
}
)
scene.sys.displayList.add(this)
this.width = width
this.height = height
this.initialText = initialText
this.styles = styles
this.maskGraphics = this.scene.add.graphics()
if (!this.scene.domlessGraphics) {
this.scene.domlessGraphics = this.scene.add.graphics()
}
// calc height of one text row
let testlineHeight = this.scene.add.text(0, 0, "foobar", this.styles)
this.lineHeight = testlineHeight.height
testlineHeight.destroy()
this.initialized = true
this.updateOn = _.union(
this.updateOn,
[
"x", "y", "width", "height",
"styles", "localTransform.tx", "localTransform.ty"
]
)
this.updateCallback = this.initTextDisplayComponents
this.initTextDisplayComponents()
}
/**
* Initialize all the stuff that makes this object work
* If you change anything about the parent object: position, size, styles etc
* You should re-run this method
*/
initTextDisplayComponents(diffObject, diffOld) {
// don't do anything if I'm not yet initialized
if (!this.initialized) {
return
}
super.initElementComponents(diffObject, diffOld)
// reset the wordWrap width
this.styles.wordWrap.width = this.width
// add or reinit the content Text object
if (this.content) {
this.content.setStyle(this.styles)
this.content.setPosition(-this.width / 2, -this.height / 2)
} else {
this.content = this.scene.add.text(-this.width / 2, -this.height / 2, "", this.styles)
this.content.setOrigin(0, 0)
this.content.setText(this.initialText)
this.add(this.content)
}
// set up a mask on the content
// this will hide overflow text when we scroll
if (!this.contentMask) {
this.maskGraphics
.clear()
.fillStyle(0x000000, 0.25)
.fillRect(0, 0, this.width, this.height)
this.contentMask = this.content.createGeometryMask(this.maskGraphics)
this.content.setMask(this.contentMask)
}
// if my y or height changed, move the form row below me
if (diffObject && (diffObject.height || diffObject.y) && this.formRow) {
let nextRow = this.form.nextRow(this.formRow)
if (nextRow) {
let tallestField = _.maxBy(this.formRow.list, "height")
nextRow.y = this.formRow.y + tallestField.height + this.form.rowPadding
}
}
// if my shape changed, redraw the mask
if (diffObject && (diffObject.height || diffObject.width)) {
this.maskGraphics
.clear()
.fillStyle(0x000000, 0.25)
.fillRect(0, 0, this.width, this.height)
}
// add pagination buttons
let pageUpPosition = [this.width / 2 - 15, -this.height / 2 + 15]
let pageUpLabel = "\u2BC5"
let pageDownPosition = [this.width / 2 - 15, this.height / 2 - 15]
let pageDownLabel = "\u2BC6"
// add pageUp button if it doesn't exist
if (this.pageUpButton) {
this.pageUpButton.setPosition(pageUpPosition[0], pageUpPosition[1])
} else {
this.pageUpButton = new Button(
this.scene,
{
x: pageUpPosition[0], y: pageUpPosition[1],
width: 30, height: 30,
label: pageUpLabel, value: null,
hasFill: false, hasOutline: false,
callback: this.pageUp, callbackScope: this,
eventName: "domlessTextDisplayPageUp", eventArgs: []
}
)
this.add(this.pageUpButton)
this.pageUpButton.setAlpha(0)
}
// add pageDown button if it doesn't exist
if (this.pageDownButton) {
this.pageDownButton.setPosition(pageDownPosition[0], pageDownPosition[1])
} else {
this.pageDownButton = new Button(
this.scene,
{
x: pageDownPosition[0], y: pageDownPosition[1],
width: 30, height: 30,
label: pageDownLabel, value: null,
hasFill: false, hasOutline: false,
callback: this.pageDown, callbackScope: this,
eventName: "domlessTextDisplayPageDown", eventArgs: []
}
)
this.add(this.pageDownButton)
this.pageDownButton.setAlpha(0)
}
// reposition the mask
let
maskX = this.localTransform.tx - this.width / 2,
maskY = this.localTransform.ty - this.height / 2
this.maskGraphics.setPosition(maskX, maskY)
}
pageUp(scrollY, scrollTweenCallback=null, disablePageUp=false) {
// tween the page up
if (
this.active && this.content.y < this.y &&
!this.scrollTween || (this.scrollTween && this.scrollTween.progress === 1)
) {
this.scrollTween = this.scene.add.tween({
targets: [this.content, this.cursor],
ease: Phaser.Math.Easing.Cubic.InOut,
duration: 500,
y: `+=${scrollY}`
})
this.scrollTween.setCallback(
"onComplete", function() {
// possibly disable the pageUp button
// and call the custom callback if one was supplied
if (disablePageUp) {
this.pageUpButton.deactivate(true)
}
// enable the pageDown button if it is disabled
if (!this.pageDownButton.alpha) {
this.pageDownButton.activate(true)
}
if (scrollTweenCallback) {
scrollTweenCallback.call(this)
}
},
[], this
)
}
}
pageDown(scrollY, scrollTweenCallback=null, disablePageDown=false) {
// tween the page down
if (
this.active && this.content.y + this.content.height > this.y + this.height &&
!this.scrollTween || (this.scrollTween && this.scrollTween.progress === 1)
) {
this.scrollTween = this.scene.add.tween({
targets: [this.content, this.cursor],
ease: Phaser.Math.Easing.Cubic.InOut,
duration: 500,
y: `-=${scrollY}`
})
this.scrollTween.setCallback(
"onComplete", function() {
// possibly disable the pageDown button
// and call the custom callback if one was supplied
if (disablePageDown) {
this.pageDownButton.deactivate(true)
}
// enable the pageUp button if it is disabled
if (!this.pageUpButton.alpha) {
this.pageUpButton.activate(true)
}
if (scrollTweenCallback) {
scrollTweenCallback.call(this)
}
}, [], this
)
}
}
}
export default TextDisplay