在谷歌地图墨卡托投影的顶部将纬度值转换为y

时间:2014-03-07 22:57:42

标签: javascript google-maps google-maps-api-3

关于这个主题有很多问题,还有很多答案,但似乎没有一个对我的代码起作用,不确定它的转换公式或整体代码是否有问题。经度值似乎按预期工作,但我无法将纬度转换为地图上的y值。我将添加一个jsfiddle以及代码,以及我尝试过的公式的一些链接。 对于我所读到的,谷歌地图是一种墨卡托投影,它使用投影的双版本(椭球和球面),在这种情况下通用公式将不会那么准确,但我没有相差20公里,而不是他们想要的地图点。 我会感谢任何有关这个特殊情况的帮助,请尝试提供一些代码,而不是指出我的链接,除非你测试它与我正在做什么,因为我可能已经测试,没有工作或我'我不确定如何实现它,提前谢谢。

http://jsfiddle.net/ve94P/

这是代码

var mapReach = {
    init: function(mapId, canvasId) {
        // Some Google map configurations here....

        this.map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

        this.nodes = [];
        this.$mapCanvas = $('#'+ mapId);
        this.canvas = document.getElementById(canvasId);

    },

    /**
     * Gets the current boundaries of the google map view-port in latitude and longitude
     * @return {} top-rigth & bottom-left lat,lon values.
     */

    getCurrentBounds: function(){
        var lng0 = this.map.getBounds().getNorthEast().lng(); // top-right x
        var lat0 = this.map.getBounds().getNorthEast().lat(); // top-right y
        var lng1 = this.map.getBounds().getSouthWest().lng(); // bottom-left x
        var lat1 = this.map.getBounds().getSouthWest().lat(); // bottom-left y

        return {topRight: {lat: lat0, lon: lng0}, bottomLeft: {lat: lat1, lon: lng1}};
    },

    /**
     * Adds nodes to be drawn on the canvas that overlays the map
     * @param {number} lat the latitude (y) geoposition of the node
     * @param {number} lon the longitude (x) geoposition of the node
     * @return {} top-rigth & bottom-left lat,lon values.
     */

    add: function(lat, lon){ // lat y , lon x
        this.nodes.push({lat:lat, lon:lon});
    },

    canvasSetUp: function(){
        if(!this.isCanvasSetted){
            this.width = this.canvas.width =  this.$mapCanvas.width();
            this.height = this.canvas.height = this.$mapCanvas.height();
            this.isCanvasSetted = true;
                    if(LOGGING){
                console.log('width:' + this.width );
                console.log('height:' + this.height );
                    }
        }
    },

    /**
     * Draws the nodes in place
     * @return void
     */

    draw: function() {
        var ctx  = this.canvas.getContext('2d');
        var currentBounds = this.getCurrentBounds();
        var yMin = currentBounds.bottomLeft.lat;
        var yMax = currentBounds.topRight.lat;
        var tempMinY = (yMin < 0) ?  Math.abs(yMin) : -yMin;
        yMax = (yMax > 0) ?  Math.abs(yMax) : yMax;
        var yRange = yMax + tempMinY;

        var xMin = currentBounds.bottomLeft.lon;
        var xMax = currentBounds.topRight.lon;
        var tempMinX = (xMin < 0) ?  Math.abs(xMin) : xMin;
        xMax = (xMax > 0) ?  Math.abs(xMax) : xMax;
        var xRange  = xMax + tempMinX;

        var mapLatBottomDegree = yMin * Math.PI / 180;

        if(LOGGING){
            console.log(currentBounds);
            console.log('x-range:' + xRange + ', y-range:' + yRange);
        }

        ctx.clearRect(0, 0, this.width, this.height);

        for (var i in this.nodes) {
            ctx.save();

            ctx.fillStyle = '#ffff00';

            // Translates lon to x value
            var x = (this.nodes[i].lon - xMin) * (this.width / xRange);

            var latRad = this.nodes[i].lat * Math.PI / 180;
            var mercN = Math.log( Math.tan( (Math.PI/4) + (latRad / 2) ) );
            var y = (this.height/2) - ( this.width * mercN / (2*Math.PI) );

            if(LOGGING){
                //console.log('x-delta:' + xDelta );
                console.log('lat:' + this.nodes[i].lat + ', lon:' + this.nodes[i].lon);
                console.log('y:' + y + ', x:' + x);
            }

            ctx.beginPath();
            ctx.arc(x, y, 4, 0, Math.PI*2, true);
            ctx.fill();
            ctx.closePath();

            ctx.restore();

        }


    },

    placeNodes: function() {
        // Lat, Lon Values for the following cities
        this.add(5, -74.226523);          // Bogota/Colombia
        this.add(48.944151, 2.263183);    // Paris/France
        this.add(-33.907758, 18.391732);  // Cape Town/South Africa
        this.add(49.254814, -123.087512); // Vancouver/Canada
        this.add(25.792680, -80.232110);  // Miami/Florida
        this.add(35.693089, 139.704742);  // Tokyo/Japan
        this.add(30.034134, 31.218933);   // Cairo/Egypt
        this.draw();
    }

};

var LOGGING = false;

$(document).ready(function(){
    mapReach.init('map-canvas', 'activity-reach');
    google.maps.event.addListener(mapReach.map, 'bounds_changed',
            function() {
                mapReach.canvasSetUp();
                mapReach.placeNodes();
            });
});

这些是我在不成功的情况下研究的一些公式,可能是我以错误的方式实施了这些公式,或者它们实际上不适用于此。

Covert latitude/longitude point to a pixels (x,y) on mercator projection

http://alastaira.wordpress.com/2011/01/23/the-google-maps-bing-maps-spherical-mercator-projection/

Converting longitude/latitude to X/Y coordinate

Mercator longitude and latitude calculations to x and y on a cropped map (of the UK)

感谢您花时间阅读并帮助我。

2 个答案:

答案 0 :(得分:1)

你还需要来自的mercator投影  地图的顶部和底部也是一个因素。然后你可以做一个线性变换:Convert lat/lon to pixel coordinate?

答案 1 :(得分:0)

我无法找到将经度转换为x位置的正确公式,即使对边界使用相同的公式并获得缩放系数也是如此。所以我最终使用谷歌api方法和自定义修复程序找到偏移量,当屏幕可以适应比整个地图强制平铺它。

我的代码基于我在网上找到的代码

http://krasimirtsonev.com/blog/article/google-maps-api-v3-convert-latlng-object-to-actual-pixels-point-object

我将此方法添加到mapReach对象:

fromLatLngToPoint: function (lat, lng) {

        var bounds,
            maxX, minX, minXDefault, maxXDefault, xOffset,
            maxY, minY, northEast, southWest, topRight, bottomLeft,
            point, scale, worldPoint;

        bounds = this.getCurrentBounds();

        minXDefault = -180; // Minumun longitude value in google maps
        maxXDefault =  180; // Maximum '                             '

        maxX = bounds.topRight.lng;
        minX = bounds.bottomLeft.lng;
        /*
        When the map is shown on a hi-res screen at zoom lvl 3 (this won't work if lvl is zoom lvl is below 3 )
        it might have to tile up on the x axis and since the google map API returns the bounds from the top-right and
        bottom-left it might return the longitude of the tiled copy and not the real starting point, so we take that
        into account by setting the minX to the minXDefault in case that is greater that the maxX value, and we need to
        the difference between our maxDefault (180) and this "minX" when this one is actually greater than the maxX.
        After finding the offset we now can change the value of minX like i said before and take that offset and add it
        to the lng of the point we are trying to get the x,y position.
        */
        xOffset = (maxX < minX) ? maxXDefault - minX : 0;
        minX = (maxX > minX) ? minX : minXDefault;

        maxY = bounds.topRight.lat;
        minY = bounds.bottomLeft.lat;

        northEast = new google.maps.LatLng(maxY, maxX);
        southWest = new google.maps.LatLng(minY, minX);

        point = new google.maps.LatLng(lat, lng + xOffset);

        topRight = this.map.getProjection().fromLatLngToPoint(northEast);
        bottomLeft = this.map.getProjection().fromLatLngToPoint(southWest);
        scale = Math.pow(2, this.map.getZoom());
        worldPoint = this.map.getProjection().fromLatLngToPoint(point);
        return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
    }

然后绘制方法是这样的:

draw: function () {
        var ctx  = this.canvas.getContext('2d');

        ctx.clearRect(0, 0, this.width, this.height);

        for (var i in this.nodes) {
            ctx.save();

            ctx.fillStyle = '#ffff00';

            var pos = this.fromLatLngToPoint(this.nodes[i].lat, this.nodes[i].lng);

            ctx.beginPath();
            ctx.arc(pos.x, pos.y, 4, 0, Math.PI*2, true);
            ctx.fill();
            ctx.closePath();
        }
    }

这是jsfiddle http://jsfiddle.net/ve94P/1/

注意:此代码应该重构以考虑性能,但主要行为是存在的。