iwmlib/lib/pixi/maps/mapdata.js

171 lines
4.8 KiB
JavaScript

/**
* MapData contains the informations about how
* a Map has to be interpreted. What are the bounds of the
* map and how to translate coordinates into
* image positions.
*
* @class
* @see {@link mapdata.html}
*/
export class MapData {
/**
* Creates instance of MapData
*
* @constructor
* @param {Projection}[projection] - Specifies the projection of the map (e.g. Mercator Projection).
* @param {object}[opts] - Addiditonal options.
* @param {[[minLat, minLng],[maxLat, maxLng]]}[opts.bounds] - Describes the minimum and maximum coordinates on the map
* @param {Point}[opts.translate] - Defines a translation, when clipping is not an option (e.g. when the whole world is shown, but translated.)
*/
constructor(projection, opts = {}) {
this.opts = Object.assign(
{
translate: { x: 0, y: 0 }
},
opts
)
this.projection = projection
if (this.opts.clip) {
let _cmin = this.projection.forward(this.opts.clip.min)
let _cmax = this.projection.forward(this.opts.clip.max)
// Swaps the y values, Mercator has it's origin bottom right,
// browser coordinates start top right.
let cmin = { x: _cmin.x, y: _cmax.y }
let cmax = { x: _cmax.x, y: _cmin.y }
this.clipExt = {
coords: {
min: this.opts.clip.min,
max: this.opts.clip.max
},
point: {
min: cmin,
max: cmax
}
}
}
}
/**
* Transforms a pixel point on the map to a geographical coordinate.
*
* @param {{x,y} | PIXI.Point} point - A pixel position on the map.
* @returns {{x,y} | PIXI.Point} - A geographical coordinate.
* @memberof MapData
*/
toCoordinates(point) {
if (this.opts.clip) {
let min = this.clipExt.point.min
let max = this.clipExt.point.max
let width = max.x - min.x
let height = max.y - min.y
point.x *= width
point.y *= height
point.x += min.x
point.y += min.y
}
let coordinates = this.projection.backward(point)
if (this.opts.translate) {
coordinates.x -= this.opts.translate.x
coordinates.y -= this.opts.translate.y
}
return coordinates
}
/**
* Transform a geographical coordinate to a pixel point on the map.
*
* @param {{x,y} | PIXI.Point} coordinates - A point in the form of {x:lat,y:lng}.
* @returns {{x,y} | PIXI.Point} point - A pixel position on the map.
* @memberof MapData
*/
toPixel(coordinates) {
let coords = { x: coordinates.x, y: coordinates.y }
if (this.opts.translate) {
coords.x += this.opts.translate.x
coords.y += this.opts.translate.y
}
let point = this.projection.forward(coords)
if (this.opts.clip) {
let min = this.clipExt.point.min
let max = this.clipExt.point.max
let clippedPoint = {
x: point.x - min.x,
y: point.y - min.y
}
let width = max.x - min.x
let height = max.y - min.y
point.x = clippedPoint.x / width
point.y = clippedPoint.y / height
}
return point
}
get clip() {
let unclipped = {
min: { x: 0, y: 0 },
max: { x: 1, y: 1 }
}
return this.opts.clip ? this.opts.clip : unclipped
}
/**
* Bounds to pixel transforms some bounds in form of {min:{x:minLat, y:minLng},max:{x:maxLat, y:maxLng}}
* to pixel coordinates.
*
*/
getBoundaries() {
// let min = this.toPixel(bounds.min)
// let max = this.toPixel(bounds.max)
// Y values needs to be swapped, as PIXI has it's origin
// in the top-left corner and a regular map in the bottom-left corner.
let boundaries = {
min: { x: 0, y: 0 },
max: { x: 1, y: 1 }
}
return boundaries
}
get maxViewport() {
return this.opts.clip ? this.opts.clip : this.projection.maxViewport
}
}
export class DeepZoomMapData extends MapData {
constructor(projection, tilesConfig, opts = {}) {
if (tilesConfig.clip) {
opts.clip = {
min: {
x: tilesConfig.clip.bounds.min[0],
y: tilesConfig.clip.bounds.min[1]
},
max: {
x: tilesConfig.clip.bounds.max[0],
y: tilesConfig.clip.bounds.max[1]
}
}
}
super(projection, opts)
this.app = opts.app
}
}