iwmlib/lib/pixi/maps/mapviewport.js

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
}
}