Source: js/plugins/Clamp.js

js/plugins/Clamp.js

import { Plugin } from './Plugin';
const DEFAULT_CLAMP_OPTIONS = {
    left: false,
    right: false,
    top: false,
    bottom: false,
    direction: null,
    underflow: 'center'
};
/**
 * Plugin to clamp the viewport to a specific world bounding box.
 *
 * @public
 */
export class Clamp extends Plugin {
    /**
     * This is called by {@link Viewport.clamp}.
     */
    constructor(parent, options = {}) {
        super(parent);
        this.options = Object.assign({}, DEFAULT_CLAMP_OPTIONS, options);
        if (this.options.direction) {
            this.options.left = this.options.direction === 'x' || this.options.direction === 'all' ? true : null;
            this.options.right = this.options.direction === 'x' || this.options.direction === 'all' ? true : null;
            this.options.top = this.options.direction === 'y' || this.options.direction === 'all' ? true : null;
            this.options.bottom = this.options.direction === 'y' || this.options.direction === 'all' ? true : null;
        }
        this.parseUnderflow();
        this.last = { x: null, y: null, scaleX: null, scaleY: null };
        this.update();
    }
    parseUnderflow() {
        const clamp = this.options.underflow.toLowerCase();
        if (clamp === 'none') {
            this.noUnderflow = true;
        }
        else if (clamp === 'center') {
            this.underflowX = this.underflowY = 0;
            this.noUnderflow = false;
        }
        else {
            // eslint-disable-next-line no-nested-ternary
            this.underflowX = (clamp.indexOf('left') !== -1) ? -1 : (clamp.indexOf('right') !== -1) ? 1 : 0;
            // eslint-disable-next-line no-nested-ternary
            this.underflowY = (clamp.indexOf('top') !== -1) ? -1 : (clamp.indexOf('bottom') !== -1) ? 1 : 0;
            this.noUnderflow = false;
        }
    }
    move() {
        this.update();
        return false;
    }
    update() {
        if (this.paused) {
            return;
        }
        // only clamp on change
        if (this.parent.x === this.last.x
            && this.parent.y === this.last.y
            && this.parent.scale.x === this.last.scaleX
            && this.parent.scale.y === this.last.scaleY) {
            return;
        }
        const original = { x: this.parent.x, y: this.parent.y };
        // TODO: Fix
        const decelerate = this.parent.plugins.decelerate || {};
        if (this.options.left !== null || this.options.right !== null) {
            let moved = false;
            if (!this.noUnderflow && this.parent.screenWorldWidth < this.parent.screenWidth) {
                switch (this.underflowX) {
                    case -1:
                        if (this.parent.x !== 0) {
                            this.parent.x = 0;
                            moved = true;
                        }
                        break;
                    case 1:
                        if (this.parent.x !== this.parent.screenWidth - this.parent.screenWorldWidth) {
                            this.parent.x = this.parent.screenWidth - this.parent.screenWorldWidth;
                            moved = true;
                        }
                        break;
                    default:
                        if (this.parent.x !== (this.parent.screenWidth - this.parent.screenWorldWidth) / 2) {
                            this.parent.x = (this.parent.screenWidth - this.parent.screenWorldWidth) / 2;
                            moved = true;
                        }
                }
            }
            else {
                if (this.options.left !== null) {
                    if (this.parent.left < (this.options.left === true ? 0 : this.options.left)) {
                        this.parent.x = -(this.options.left === true ? 0 : this.options.left) * this.parent.scale.x;
                        decelerate.x = 0;
                        moved = true;
                    }
                }
                if (this.options.right !== null) {
                    if (this.parent.right > (this.options.right === true ? this.parent.worldWidth : this.options.right)) {
                        this.parent.x = (-(this.options.right === true ? this.parent.worldWidth : this.options.right)
                            * this.parent.scale.x) + this.parent.screenWidth;
                        decelerate.x = 0;
                        moved = true;
                    }
                }
            }
            if (moved) {
                this.parent.emit('moved', { viewport: this.parent, original, type: 'clamp-x' });
            }
        }
        if (this.options.top !== null || this.options.bottom !== null) {
            let moved = false;
            if (!this.noUnderflow && this.parent.screenWorldHeight < this.parent.screenHeight) {
                switch (this.underflowY) {
                    case -1:
                        if (this.parent.y !== 0) {
                            this.parent.y = 0;
                            moved = true;
                        }
                        break;
                    case 1:
                        if (this.parent.y !== this.parent.screenHeight - this.parent.screenWorldHeight) {
                            this.parent.y = (this.parent.screenHeight - this.parent.screenWorldHeight);
                            moved = true;
                        }
                        break;
                    default:
                        if (this.parent.y !== (this.parent.screenHeight - this.parent.screenWorldHeight) / 2) {
                            this.parent.y = (this.parent.screenHeight - this.parent.screenWorldHeight) / 2;
                            moved = true;
                        }
                }
            }
            else {
                if (this.options.top !== null) {
                    if (this.parent.top < (this.options.top === true ? 0 : this.options.top)) {
                        this.parent.y = -(this.options.top === true ? 0 : this.options.top)
                            * this.parent.scale.y;
                        decelerate.y = 0;
                        moved = true;
                    }
                }
                if (this.options.bottom !== null) {
                    if (this.parent.bottom > (this.options.bottom === true ? this.parent.worldHeight : this.options.bottom)) {
                        this.parent.y = (-(this.options.bottom === true ? this.parent.worldHeight : this.options.bottom)
                            * this.parent.scale.y) + this.parent.screenHeight;
                        decelerate.y = 0;
                        moved = true;
                    }
                }
            }
            if (moved) {
                this.parent.emit('moved', { viewport: this.parent, original, type: 'clamp-y' });
            }
        }
        this.last.x = this.parent.x;
        this.last.y = this.parent.y;
        this.last.scaleX = this.parent.scale.x;
        this.last.scaleY = this.parent.scale.y;
    }
    reset() {
        this.update();
    }
}