178 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { DeepZoomMap } from './map.js'
 | 
						|
 | 
						|
/**
 | 
						|
 * The MapViewport class is responsible for a consistent map view.
 | 
						|
 * It is aware of the current viewposition, the scale and viewport.
 | 
						|
 * It ensures, that maps can be changed, without the user noticing it.
 | 
						|
 *
 | 
						|
 */
 | 
						|
export default class MapViewport {
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @param {object} [focus = {x:0, y:0}] - Defines the startup focuspoint of the app.
 | 
						|
     * @param {number} [zoom = 0] - Defines the startup zoom of the app. Note that this is just a request.
 | 
						|
     * The MapViewport will prioritize a full scale app, than displaying the demanded zoom factor
 | 
						|
     */
 | 
						|
    constructor({ focus = null, zoom = null, viewport = { min: { x: -85, y: -180 }, max: { x: 85, y: 180 } } } = {}) {
 | 
						|
        this.viewport = viewport
 | 
						|
        this._focus = focus
 | 
						|
        this._zoom = zoom
 | 
						|
        this.referenceHeight = 256
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     *  The current focus point as map coordinates.
 | 
						|
     *
 | 
						|
     * @member {CoordinatePoint}
 | 
						|
     * @readonly
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    get focus() {
 | 
						|
        return this._focus
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The current zoom distance.
 | 
						|
     * On DeepZoomMaps this is equal to the zoom level.
 | 
						|
     *
 | 
						|
     * @member {number}
 | 
						|
     * @readonly
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    get zoom() {
 | 
						|
        return this._zoom
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Applies the current view to a map.
 | 
						|
     *
 | 
						|
     *
 | 
						|
     * @param {GeoMap} map - Map the viewport should be applied to.
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    apply(map) {
 | 
						|
        map.moveTo(this._focus, this._zoom)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Update the focus point and zoom according to the map.
 | 
						|
     * This is commonly called when the map is transformed.
 | 
						|
     *
 | 
						|
     * @param {GeoMap} map - Map to update.
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    update(map) {
 | 
						|
        this.updateZoom(map)
 | 
						|
        this.updateFocusPoint(map)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Updates the focus point.
 | 
						|
     * This is automatically called when calling update.
 | 
						|
     *
 | 
						|
     * @param {GeoMap} map
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    updateFocusPoint(map) {
 | 
						|
        const frame = map.getFrame()
 | 
						|
        this._focus = this.coordinatesFromWindowPoint(map, frame.localCenter)
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Updates the zoom.
 | 
						|
     * This is automatically called when calling update.
 | 
						|
     *
 | 
						|
     * @param {GeoMap} map
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    updateZoom(map) {
 | 
						|
        /**
 | 
						|
         * TODO: This relies on the fact, that all maps have the same tileSize,
 | 
						|
         * if a set would have a smaller tileSize. Improve that.
 | 
						|
         */
 | 
						|
        if (map instanceof DeepZoomMap) this._zoom = map.floatingLevelForScale(map.image.scatter.scale)
 | 
						|
        else {
 | 
						|
            this._zoom = map.zoom
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Transforms a position on the map to a position in the window.
 | 
						|
     *
 | 
						|
     * Inverse of windowPointToMapPoint.
 | 
						|
     *
 | 
						|
     * @param {GeoMap} map - Map to calculate the position on.
 | 
						|
     * @param {Point} point - Position on the map in pixels.
 | 
						|
     * @returns {Point} - Pixel position in the window.
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    mapPointToWindowPoint(map, point) {
 | 
						|
        let windowPoint = { x: 0, y: 0 }
 | 
						|
 | 
						|
        if (map['image'] && map.image['parent']) {
 | 
						|
            let container = map.image.parent
 | 
						|
 | 
						|
            windowPoint = new PIXI.Point(
 | 
						|
                map.scatter.position.x + map.scatter.scale * point.x,
 | 
						|
                map.scatter.position.y + map.scatter.scale * point.y
 | 
						|
            )
 | 
						|
 | 
						|
            windowPoint = container.toGlobal(windowPoint)
 | 
						|
        } else {
 | 
						|
            console.error(this._noParentError)
 | 
						|
        }
 | 
						|
 | 
						|
        return windowPoint
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Transforms in the window to a position on the map.
 | 
						|
     *
 | 
						|
     * Inverse of     mapPointToWindowPoint(map, point) {.
 | 
						|
     *
 | 
						|
     * @param {GeoMap} map - Map to calculate the position on.
 | 
						|
     * @param {Point} point -Pixel position in the window.
 | 
						|
     * @returns {Point} - Position on the map in pixels.
 | 
						|
     * @memberof MapViewport
 | 
						|
     */
 | 
						|
    windowPointToMapPoint(map, point) {
 | 
						|
        let pointOnMap = { x: 0, y: 0 }
 | 
						|
        if (map['image'] && map.image['parent']) {
 | 
						|
            let offset = map.image.parent.toGlobal({ x: 0, y: 0 })
 | 
						|
            pointOnMap = new PIXI.Point(
 | 
						|
                (point.x - map.scatter.position.x - offset.x) / map.scatter.scale,
 | 
						|
                (point.y - map.scatter.position.y - offset.y) / map.scatter.scale
 | 
						|
            )
 | 
						|
        } else console.error(this._noParentError)
 | 
						|
 | 
						|
        return pointOnMap
 | 
						|
    }
 | 
						|
 | 
						|
    get _noParentError() {
 | 
						|
        return 'Cannot compute map point when map has no parent.'
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets the coordinates of a specific point in the viewport.
 | 
						|
     *
 | 
						|
     * @param {PIXI.Point | {x,y}} point - Pixel position in the viewport.
 | 
						|
     * @returns {{x,y}} Coordinates on the map of the provided position.
 | 
						|
     * @memberof MapView
 | 
						|
     */
 | 
						|
    coordinatesFromWindowPoint(map, point) {
 | 
						|
        let position = {
 | 
						|
            x: point.x - map.scatter.position.x,
 | 
						|
            y: point.y - map.scatter.position.y
 | 
						|
        }
 | 
						|
 | 
						|
        let normalized = {
 | 
						|
            x: position.x / (map.width * map.scatter.scale),
 | 
						|
            y: position.y / (map.height * map.scatter.scale)
 | 
						|
        }
 | 
						|
 | 
						|
        let coordinates = map.mapProjection.toCoordinates(normalized)
 | 
						|
 | 
						|
        return coordinates
 | 
						|
    }
 | 
						|
}
 |