668 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			668 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import PIXIApp from '../app.js'
 | 
						|
import { CoordinateDisplay } from './display.js'
 | 
						|
import { MapLayer } from './geolayer.js'
 | 
						|
import { RigidScatterContainer } from './scatter.js'
 | 
						|
import { EventHandler } from './utils.js'
 | 
						|
import { Points } from '../../utils.js'
 | 
						|
import Logging from '../../logging.js'
 | 
						|
import { MapList } from './maplist.js'
 | 
						|
 | 
						|
/**
 | 
						|
 * A PIXI.Point or object in form {x,y}.
 | 
						|
 * 
 | 
						|
 * @typedef {Object} Point
 | 
						|
 * @property {number} x - Indicates whether the Courage component is present.
 | 
						|
 * @property {number} y - Indicates whether the Power component is present.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * A coordinate point is a PIXI.Point or object in form {x,y} that contains map coordinates
 | 
						|
 * instead of pixel values, where x represents the latitude and y the longitude.
 | 
						|
 * @typedef {Object} CoordinatePoint
 | 
						|
 * @property {number} x - Indicates whether the Courage component is present.
 | 
						|
 * @property {number} y - Indicates whether the Power component is present.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * MapApp is responsible for showing fullscreen
 | 
						|
 * map applications.
 | 
						|
 *
 | 
						|
 * @export
 | 
						|
 * @class MapApp
 | 
						|
 * @extends {PIXIApp}
 | 
						|
 */
 | 
						|
export default class MapApp extends PIXIApp {
 | 
						|
    /**
 | 
						|
     *Creates an instance of MapApp.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    constructor(opts = {}) {
 | 
						|
        super(opts)
 | 
						|
 | 
						|
        // Default values.
 | 
						|
        opts = Object.assign(
 | 
						|
            {
 | 
						|
                debug: false,
 | 
						|
                maps: {}, //required
 | 
						|
                view: null, //required
 | 
						|
                wrapper: null, // Required if you want to use DOM Overlays.
 | 
						|
                startmap: null,
 | 
						|
                coordsLogging: false,
 | 
						|
                overlays: {},
 | 
						|
                keycodes: {},
 | 
						|
                imageMapZoomHeight: 256, //Defines the zoomvalue 1 for all image maps inside the mapapp.
 | 
						|
                focus: null,
 | 
						|
                zoom: 1,
 | 
						|
                onMapChanged: null,
 | 
						|
                onSizeChanged: null,
 | 
						|
                onTransform: null
 | 
						|
            },
 | 
						|
            opts,
 | 
						|
            {
 | 
						|
                alpha: 0.5
 | 
						|
            }
 | 
						|
        )
 | 
						|
        this.submaps = []
 | 
						|
        this.overlayElements = new Map()
 | 
						|
        this.debug = opts.debug
 | 
						|
        this.fpsLogging = opts.fpsLogging
 | 
						|
        this.keycodes = this._extractKeyCodes(opts.keycodes)
 | 
						|
        this.coordsLogging = opts.coordsLogging
 | 
						|
        this.overlays = opts.overlays
 | 
						|
        this.focus = opts.focus
 | 
						|
        this.zoom = opts.zoom
 | 
						|
        this.wrapper = opts.wrapper
 | 
						|
 | 
						|
        this.onMapChanged = new EventHandler('mapChanged', {
 | 
						|
            listeners: opts.onMapChanged
 | 
						|
        })
 | 
						|
        this.onSizeChanged = new EventHandler('sizeChanged', {
 | 
						|
            listeners: opts.onSizeChanged
 | 
						|
        })
 | 
						|
        this.onTransform = new EventHandler('transformed', {
 | 
						|
            listeners: opts.onTransform
 | 
						|
        })
 | 
						|
 | 
						|
        /**
 | 
						|
         * When in debug mode, this allows the user to copy the center coordinates to the clipboard.
 | 
						|
         */
 | 
						|
        if (this.debug) {
 | 
						|
            this.DRAW_MODES = {
 | 
						|
                PIXI_POINT: 0,
 | 
						|
                PATH_MODE: 1,
 | 
						|
                POLYGON_MODE: 2,
 | 
						|
 | 
						|
                getName: function(num) {
 | 
						|
                    let result = null
 | 
						|
                    for (const [key, val] of Object.entries(this)) {
 | 
						|
                        if (val == num) result = key
 | 
						|
                    }
 | 
						|
                    return result
 | 
						|
                }
 | 
						|
            }
 | 
						|
            this.drawMode = this.DRAW_MODES.PIXI_POINT
 | 
						|
            this.drawData = []
 | 
						|
        }
 | 
						|
 | 
						|
        this.mapList = new MapList(opts.startmap ? opts.startmap : null, opts.maps ? opts.maps : {})
 | 
						|
 | 
						|
        this._setupKeyboardUtils()
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Log boundaries for a shown map.
 | 
						|
     * This is for development purposes only, if you want
 | 
						|
     * to find the boundaries of a shown map.
 | 
						|
     *
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    logMapBoundaries() {
 | 
						|
        let map = this.mapLayer.map
 | 
						|
 | 
						|
        let boundaries = {
 | 
						|
            min: this.mapLayer.mapview.coordinatesFromWindowPoint(map, { x: 0, y: 0 }),
 | 
						|
            max: this.mapLayer.mapview.coordinatesFromWindowPoint(map, { x: 0, y: 0 })
 | 
						|
        }
 | 
						|
 | 
						|
        console.log(JSON.stringify(boundaries))
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates the MapLayer.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    _setupMapLayer() {
 | 
						|
        this.mapContainer = new PIXI.Container()
 | 
						|
        this._mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, {
 | 
						|
            name: 'Root Map Layer',
 | 
						|
            focus: this.focus,
 | 
						|
            zoom: this.zoom,
 | 
						|
            onChange: this._mapChanged.bind(this)
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    setup() {
 | 
						|
        super.setup()
 | 
						|
 | 
						|
        // TODO get access to fps display
 | 
						|
        let fpsDisplay = null
 | 
						|
        this.stage.children.forEach(element => {
 | 
						|
            if (element.refreshFps) fpsDisplay = element
 | 
						|
        })
 | 
						|
 | 
						|
        this._setupMapLayer()
 | 
						|
 | 
						|
        this.ui = new PIXI.Container()
 | 
						|
        this.scene.addChild(this.ui)
 | 
						|
        if (this.fpsLogging != null && fpsDisplay != null) this.ui.addChild(fpsDisplay)
 | 
						|
 | 
						|
        if (this.coordsLogging) {
 | 
						|
            this.coordsDisplay = new CoordinateDisplay(this)
 | 
						|
            this.ui.addChild(this.coordsDisplay)
 | 
						|
        }
 | 
						|
 | 
						|
        this.__dragging = false
 | 
						|
        this.__events = new Map()
 | 
						|
 | 
						|
        const scene = this.scene
 | 
						|
        scene.interactive = true
 | 
						|
        scene.on('pointercancel', this.__onEnd.bind(this))
 | 
						|
        scene.on('pointerdown', this.__onStart.bind(this))
 | 
						|
        scene.on('pointermove', this.__onMove.bind(this))
 | 
						|
        scene.on('pointerout', this.__onEnd.bind(this))
 | 
						|
        scene.on('pointerup', this.__onEnd.bind(this))
 | 
						|
        scene.on('pointerupoutside', this.__onEnd.bind(this))
 | 
						|
 | 
						|
        return this
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * You can add Dom elements directly to the app's DomLayer by calling
 | 
						|
     * appendChild(). The elements will be forced to use an absolute positioning.
 | 
						|
     * This shall prevent unwanted sideeffects with the app.
 | 
						|
     *
 | 
						|
     * @param {HTMLElement} element - Element to add to DOMRoot.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    appendChild(element) {
 | 
						|
        if (!this.wrapper)
 | 
						|
            console.error(
 | 
						|
                `When using DOMElements on ${this.constructor.name} you must specify a wrapper in the constructor.`
 | 
						|
            )
 | 
						|
        if (!(element instanceof HTMLElement))
 | 
						|
            console.error(
 | 
						|
                'You can only append HTMLElements to DOM. If you want to add PIXI elements to the scene call app.scene.addChild(element).'
 | 
						|
            )
 | 
						|
        else {
 | 
						|
            Object.assign(element.style, { position: 'absolute' })
 | 
						|
            this.wrapper.appendChild(element)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Relayouts the app. E.g. called when the window is resized.
 | 
						|
     *
 | 
						|
     * @param {number} width - Desired width of the app.
 | 
						|
     * @param {number} height - Desired height of the app.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    layout(width, height) {
 | 
						|
        this.scene.resize(width, height)
 | 
						|
        this.mapLayer.mapview.update()
 | 
						|
        this.onSizeChanged.call(this)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Overrides the sceneFactory of the PIXIApp to create a RigidScatterContainer instead of
 | 
						|
     * a regular PIXI.Container()
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @returns {RigidScatterContainer} - Returns the newly created RigidScatterContainer.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    sceneFactory() {
 | 
						|
        return new RigidScatterContainer(this.width, this.height, this.renderer, {
 | 
						|
            app: this,
 | 
						|
            showBounds: false,
 | 
						|
            showTouches: false,
 | 
						|
            showPolygon: false,
 | 
						|
            container: this,
 | 
						|
            stopEvents: false,
 | 
						|
            claimEvents: false
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Changes the map to the given key.
 | 
						|
     *
 | 
						|
     * @param {string} key - Identifier of the map to change to.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    selectMap(key) {
 | 
						|
        if (this.debug) console.log('Select map', key, result)
 | 
						|
        let result = this.mapList.select(key)
 | 
						|
 | 
						|
        if (result && this.mapLayer) {
 | 
						|
            this.mapLayer.changeMap(this.mapList.map)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds and sets a map to the mapapp.
 | 
						|
     *
 | 
						|
     * @param {string} key - Name of the map.
 | 
						|
     * @param {GeoMap} map - Map to add.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    setMap(key, map) {
 | 
						|
        this.addMap(key, map)
 | 
						|
        this.selectMap(key)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds a map to the maplist.
 | 
						|
     * If no map is set, the added map will be set as default.
 | 
						|
     *
 | 
						|
     * @param {string} key - Identifier for the map.
 | 
						|
     * @param {GeoMap} map - Map object to add.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    addMap(key, map) {
 | 
						|
        if (this.mapList) this.mapList.add(key, map)
 | 
						|
        else console.error('Cannot access mapLayer. It was not initialized yet.')
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds multiple maps at once.
 | 
						|
     *
 | 
						|
     * @param {object} mapObject
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    addMaps(mapObject) {
 | 
						|
        for (let [key, val] of Object.entries(mapObject)) {
 | 
						|
            if (val instanceof GeoMap) {
 | 
						|
                this.addMap(key, val)
 | 
						|
            } else console.warn('Tried adding maps that are not og Type GeoMap.')
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    transformed(event) {
 | 
						|
        this.onTransform.call(this, event)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * Called when the mapLayer changed the map.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @param {*} lastMap
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    _mapChanged(lastMap) {
 | 
						|
        if (lastMap) {
 | 
						|
            lastMap.flushHandlers()
 | 
						|
        }
 | 
						|
 | 
						|
        this.transformed()
 | 
						|
        this.onMapChanged.call(this, this.map)
 | 
						|
 | 
						|
        this.map.onTransform.add(this.transformed.bind(this))
 | 
						|
 | 
						|
        if (this.ui && this.ui.parent) {
 | 
						|
            const parent = this.ui.parent
 | 
						|
            parent.removeChild(this.ui)
 | 
						|
            parent.addChild(this.ui)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the mapLayer of the map.
 | 
						|
     *
 | 
						|
     * @member {MapLayer}
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    get mapLayer() {
 | 
						|
        return this._mapLayer
 | 
						|
    }
 | 
						|
 | 
						|
    _doesOverlayElementExist(layer, type, name) {
 | 
						|
        let layerElements = this.overlayElements.get(layer)
 | 
						|
        return layerElements != undefined && layerElements[type] != null && layerElements[type][name] != null
 | 
						|
    }
 | 
						|
 | 
						|
    _getOverlayElement(layer, type, name) {
 | 
						|
        let layerElements = this.overlayElements.get(layer)
 | 
						|
        return layerElements[type][name]
 | 
						|
    }
 | 
						|
 | 
						|
    _setOverlayElement(layer, type, name, value) {
 | 
						|
        let obj = this.overlayElements.get(layer)
 | 
						|
        if (obj == undefined) obj = {}
 | 
						|
 | 
						|
        if (obj[type] == null) obj[type] = {}
 | 
						|
 | 
						|
        obj[type][name] = value
 | 
						|
 | 
						|
        this.overlayElements.set(layer, obj)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Copies the current location to the clipboard.
 | 
						|
     *
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    locationToClipboard() {
 | 
						|
        let hidden = document.createElement('input')
 | 
						|
        document.body.appendChild(hidden)
 | 
						|
        hidden.value = '"location":' + JSON.stringify(app.mapLayer.mapview.focus)
 | 
						|
        hidden.readOnly = true
 | 
						|
        hidden.select()
 | 
						|
        document.execCommand('Copy')
 | 
						|
        this.showNotification('Copied location to clipboard.')
 | 
						|
        document.body.removeChild(hidden)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Can be used to copy polygons to the clipboard.
 | 
						|
     *
 | 
						|
     * Useful for debugging or to roughly trace a shape in the map.
 | 
						|
     * The generated pointarray can be used as geometry of a geographic
 | 
						|
     * or inside an overlay to draw that shape onto the map.
 | 
						|
     *
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    pathToClipboard() {
 | 
						|
        let hidden = document.createElement('input')
 | 
						|
        document.body.appendChild(hidden)
 | 
						|
 | 
						|
        this.drawData.push(this.mapLayer.mapview.focus)
 | 
						|
 | 
						|
        if (this.drawMode == this.DRAW_MODES.POLYGON_MODE) {
 | 
						|
            let data = {
 | 
						|
                type: 'Polygon',
 | 
						|
                coordinates: [this.drawData]
 | 
						|
            }
 | 
						|
 | 
						|
            hidden.value = '"geometry":' + JSON.stringify(data)
 | 
						|
        } else {
 | 
						|
            // PATH_MODE is default.
 | 
						|
            hidden.value = JSON.stringify(this.drawData)
 | 
						|
        }
 | 
						|
        hidden.select()
 | 
						|
        document.execCommand('Copy')
 | 
						|
        this.showNotification('Location appended in clipboard.')
 | 
						|
        document.body.removeChild(hidden)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the active map.
 | 
						|
     *
 | 
						|
     * @readonly
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    get map() {
 | 
						|
        return this.mapList.map
 | 
						|
    }
 | 
						|
 | 
						|
    clearDrawData() {
 | 
						|
        this.drawData = []
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Logs a text field on the map.
 | 
						|
     * The text element is a DOMElement.
 | 
						|
     *
 | 
						|
     * @param {string} msg - Message to log.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    showNotification(msg) {
 | 
						|
        let notification = document.createElement('div')
 | 
						|
        notification.classList.add('notification')
 | 
						|
 | 
						|
        let text = document.createElement('p')
 | 
						|
        text.innerHTML = msg
 | 
						|
        notification.appendChild(text)
 | 
						|
 | 
						|
        /**
 | 
						|
         * TODO: move styling (except opacity) to css.
 | 
						|
         */
 | 
						|
        Object.assign(notification.style, {
 | 
						|
            opacity: 0,
 | 
						|
            top: 0,
 | 
						|
            left: 0,
 | 
						|
            position: 'fixed',
 | 
						|
            display: 'flex',
 | 
						|
            width: '100%',
 | 
						|
            height: '100%',
 | 
						|
            justifyContent: 'center',
 | 
						|
            alignItems: 'center',
 | 
						|
            pointerEvents: 'none'
 | 
						|
        })
 | 
						|
 | 
						|
        document.body.appendChild(notification)
 | 
						|
 | 
						|
        let popAnimation = new TimelineLite({
 | 
						|
            onComplete: () => {
 | 
						|
                notification.parentNode.removeChild(notification)
 | 
						|
            }
 | 
						|
        })
 | 
						|
        let animationSpeed = 0.5
 | 
						|
 | 
						|
        popAnimation
 | 
						|
            .to(notification, animationSpeed, {
 | 
						|
                opacity: 1
 | 
						|
            })
 | 
						|
            .to(notification, animationSpeed, {
 | 
						|
                opacity: 0
 | 
						|
            })
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @typedef KeyCode
 | 
						|
     * @type {object}
 | 
						|
     * @property {string} key - an ID.
 | 
						|
     * @property {boolean} altKey - Defines if KeyCode requires the alt key to be pressed.
 | 
						|
     * @property {boolean} shiftKey - Defines if KeyCode requires the shift key to be pressed.
 | 
						|
     * @property {boolean} ctrlKey - Defines if KeyCode requires the ctrl key to be pressed.
 | 
						|
     *
 | 
						|
     */
 | 
						|
 | 
						|
    /**
 | 
						|
     * Check's if a key event matches a defined KeyCode.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @param {KeyboardEvent} event - Event that is fired on keydown, -pressed or -up.
 | 
						|
     * @param {KeyCode} keyCode - KeyCode is an object in the form of : {key:number, altKey:boolean,shiftKey:boolean,ctrlKey:boolean }
 | 
						|
     * @returns {boolean} - True, when the event matches the keycode, false otherwise.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    _matchKeyCode(event, keyCode) {
 | 
						|
        // If keycode does not exist or is invalid - return.
 | 
						|
        if (!keyCode || keyCode.key == null) return false
 | 
						|
 | 
						|
        let code = keyCode.key
 | 
						|
        if (event.shiftKey) code -= 32
 | 
						|
        const key = event.which == code || event.keyCode == code || event.charCode == code
 | 
						|
 | 
						|
        const ctrl = keyCode.ctrlKey == event.ctrlKey
 | 
						|
        const shift = keyCode.shiftKey == event.shiftKey
 | 
						|
        const alt = keyCode.altKey == event.altKey
 | 
						|
 | 
						|
        return key && ctrl && shift && alt
 | 
						|
    }
 | 
						|
 | 
						|
    _setupKeyboardUtils() {
 | 
						|
        document.body.addEventListener('keypress', event => {
 | 
						|
            this._checkForKeyCode(event)
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Checks on every key down if it matches a keycode.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @param {KeyboardEvent} event
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    _checkForKeyCode(event) {
 | 
						|
        if (this._matchKeyCode(event, this.keycodes.copyCoordinate)) {
 | 
						|
            event.preventDefault()
 | 
						|
 | 
						|
            switch (this.drawMode) {
 | 
						|
                case this.DRAW_MODES.PIXI_POINT:
 | 
						|
                    this.locationToClipboard()
 | 
						|
                    break
 | 
						|
                case this.DRAW_MODES.PATH_MODE:
 | 
						|
                case this.DRAW_MODES.POLYGON_MODE:
 | 
						|
                    this.pathToClipboard()
 | 
						|
                    break
 | 
						|
                default:
 | 
						|
                    console.error(
 | 
						|
                        `Draw mode is not implemented yet: ${this.DRAW_MODES.getName(this.drawMode)}(${this.drawMode}).`
 | 
						|
                    )
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (this._matchKeyCode(event, this.keycodes.togglePathMode)) {
 | 
						|
            if (this.drawMode == this.DRAW_MODES.PATH_MODE) {
 | 
						|
                this.showNotification('Path Mode disabled.')
 | 
						|
                this._resetDrawMode()
 | 
						|
            } else {
 | 
						|
                this.drawMode = this.DRAW_MODES.PATH_MODE
 | 
						|
                this.showNotification('Path Mode enabled.')
 | 
						|
                this.clearDrawData()
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        //When SHIFT+P is pressed POLYGON-MODE is toggled:
 | 
						|
        if (this._matchKeyCode(event, this.keycodes.togglePolygonMode)) {
 | 
						|
            if (this.drawMode == this.DRAW_MODES.POLYGON_MODE) {
 | 
						|
                this.showNotification('Polygon Mode disabled.')
 | 
						|
                this._resetDrawMode()
 | 
						|
            } else {
 | 
						|
                this.drawMode = this.DRAW_MODES.POLYGON_MODE
 | 
						|
                this.showNotification('Polygon Mode enabled.')
 | 
						|
                this.clearDrawData()
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // When SHIFT+X is pressed toggle crosshair
 | 
						|
        if (this.keycodes.toggleUi && this._matchKeyCode(event, this.keycodes.toggleUi)) {
 | 
						|
            if (this.pixiUiLayer.visible) {
 | 
						|
                this.pixiUiLayer.hide()
 | 
						|
                this.domUiLayer.hide()
 | 
						|
            } else {
 | 
						|
                this.pixiUiLayer.show()
 | 
						|
                this.domUiLayer.show()
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    _resetDrawMode() {
 | 
						|
        this.drawMode = this.DRAW_MODES.PIXI_POINT
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @typedef KeyCodePairs
 | 
						|
     * @type {object}
 | 
						|
     * @property {string} name - Name of the KeyCode.
 | 
						|
     * @property {KeyCode} keyCode - KeyCode
 | 
						|
     *
 | 
						|
     */
 | 
						|
 | 
						|
    /**
 | 
						|
     * Extracts keycodes from a string.
 | 
						|
     *
 | 
						|
     * KeycodeStrings may look like this 'ctrl+shift+b'
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @param {KeyCodePairs} nameKeyCodePairs
 | 
						|
     * @returns {array} - Returns an array of KeyCode objects.
 | 
						|
     * @memberof MapApp
 | 
						|
     */
 | 
						|
    _extractKeyCodes(nameKeyCodePairs) {
 | 
						|
        let out = {}
 | 
						|
 | 
						|
        for (let [name, combinationString] of Object.entries(nameKeyCodePairs)) {
 | 
						|
            let keys = combinationString.split('+')
 | 
						|
            out[name] = {
 | 
						|
                key: null,
 | 
						|
                ctrlKey: false,
 | 
						|
                shiftKey: false,
 | 
						|
                altKey: false
 | 
						|
            }
 | 
						|
            let errors = []
 | 
						|
 | 
						|
            const special = ['shift', 'ctrl', 'alt']
 | 
						|
            keys.forEach(key => {
 | 
						|
                if (key.length == 1) {
 | 
						|
                    if (out[name].key) {
 | 
						|
                        const error = 'Tried to set multiple keys as keycode. This is currently not supported.'
 | 
						|
                        errors.push(error)
 | 
						|
                    } else out[name].key = key.charCodeAt(0)
 | 
						|
                } else {
 | 
						|
                    key = key.toLowerCase()
 | 
						|
                    if (special.indexOf(key) != -1) {
 | 
						|
                        out[name][key + 'Key'] = true
 | 
						|
                    } else {
 | 
						|
                        const error = 'Wrong / non-implemented special character OR typo in key: ' + key
 | 
						|
                        errors.push(error)
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            })
 | 
						|
 | 
						|
            // Disable hotkey if an error occured.
 | 
						|
            if (errors.length > 0)
 | 
						|
                out[name] = {
 | 
						|
                    key: null,
 | 
						|
                    ctrlKey: false,
 | 
						|
                    shiftKey: false,
 | 
						|
                    altKey: false
 | 
						|
                }
 | 
						|
        }
 | 
						|
 | 
						|
        return out
 | 
						|
    }
 | 
						|
 | 
						|
    __onStart(event) {
 | 
						|
        this.__dragging = true
 | 
						|
 | 
						|
        let hittedSubmap = null
 | 
						|
        let center = null
 | 
						|
        for (const submap of this.submaps) {
 | 
						|
            const radius = submap.container.width / 2
 | 
						|
            const distance = Points.distance(submap.center, event.data.global)
 | 
						|
            if (distance < radius) {
 | 
						|
                hittedSubmap = submap
 | 
						|
                center = submap.center
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        this.__events.set(event.data.identifier, {
 | 
						|
            event,
 | 
						|
            submap: hittedSubmap,
 | 
						|
            center
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    __onMove(event) {
 | 
						|
        if (this.__dragging) {
 | 
						|
            const myevent = this.__events.get(event.data.identifier)
 | 
						|
 | 
						|
            if (myevent && myevent.submap) {
 | 
						|
                const submap = myevent.submap
 | 
						|
                const center = submap.center
 | 
						|
                const radius = submap.container.width / 2
 | 
						|
                const distance = Points.distance(center, event.data.global) / submap.scatter.scale
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    __onEnd(event) {
 | 
						|
        this.__dragging = false
 | 
						|
        this.__events.delete(event.data.identifier)
 | 
						|
    }
 | 
						|
}
 |