/** * 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 {array}[opts.bounds] - Describes the minimum and maximum coordinates on the map in the form of {[[minLat, minLng],[maxLat, maxLng]]}. * @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. * * @public * @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. * * @public * @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's the clipping of the map data. Clipping describes the * piece of the map that is shown. E.g. if we just show a map of * europe, then we have to set the clipping properly, otherwise * the preojection would produce the wrong results when transforming * from a point to coordinates or the other way around. * * @readonly * @memberof MapData * @returns {object} - Object that contains a min and max value of the clipping in form of: {min: {x,y}, max:{x,y}}. Where x and y are in between 0 and 1. */ get clip() { let unclipped = { min: { x: 0, y: 0 }, max: { x: 1, y: 1 } } return this.opts.clip ? this.opts.clip : unclipped } /** * Returns the biggest viewport the mapdata allows. * This is determined by the projecton or the clipping on the mapapp. * * @readonly * @memberof MapData */ get maxViewport() { return this.opts.clip ? this.opts.clip : this.projection.maxViewport } } /** * Special mapdata for DeepZoomMap objects. * * Note: It just transform the clipping parameter of the tiles config * to the clipping of the mapapp. * * @export * @class DeepZoomMapData * @extends {MapData} */ 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 } }