195 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 *	MapProjection 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 mapprojection.html}
 | 
						|
 */
 | 
						|
export class MapProjection {
 | 
						|
    /**
 | 
						|
     * Creates instance of MapProjection
 | 
						|
     *
 | 
						|
     * @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
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The projection used by the map projection.
 | 
						|
     *
 | 
						|
     * @member {Projection}
 | 
						|
     * @readonly
 | 
						|
     * @memberof MapProjection
 | 
						|
     */
 | 
						|
    get projection() {
 | 
						|
        return this._projection
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Transforms a pixel point on the map to a geographical coordinate.
 | 
						|
     *
 | 
						|
     * @public
 | 
						|
     * @param {Point} point - A pixel position on the map.
 | 
						|
     * @returns {CoordinatePoint} A geographical coordinate.
 | 
						|
     * @memberof MapProjection
 | 
						|
     */
 | 
						|
    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 {CoordinatePoint} coordinates - A point in the form of {x:lat,y:lng}.
 | 
						|
     * @returns {Point} A pixel position on the map.
 | 
						|
     * @memberof MapProjection
 | 
						|
     */
 | 
						|
    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
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     *  Clipping describes the
 | 
						|
     * piece of the map that is shown. The returned object 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.
 | 
						|
     *
 | 
						|
     * 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
 | 
						|
     * @member {object}
 | 
						|
     * @memberof MapProjection
 | 
						|
     */
 | 
						|
    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 map projection allows.
 | 
						|
     * This is determined by the projecton or the clipping on the mapapp.
 | 
						|
     *
 | 
						|
     * @readonly
 | 
						|
     * @memberof MapProjection
 | 
						|
     */
 | 
						|
    get maxViewport() {
 | 
						|
        return this.opts.clip ? this.opts.clip : this.projection.maxViewport
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Special map projection for DeepZoomMap objects.
 | 
						|
 *
 | 
						|
 * Note: It just transform the clipping parameter of the tiles config
 | 
						|
 * to the clipping of the mapapp.
 | 
						|
 *
 | 
						|
 * @export
 | 
						|
 * @class DeepZoomMapProjection
 | 
						|
 * @extends {MapProjection}
 | 
						|
 */
 | 
						|
export class DeepZoomMapProjection extends MapProjection {
 | 
						|
    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
 | 
						|
    }
 | 
						|
}
 |