Yandex tiles in Google Maps v3

Switch between google road map and Yandex and note that the tiles for Moscow (and other places) don't line up.

HTML

<script src="https://maps.googleapis.com/maps/api/js?sensor=false&amp;libraries=visualization&amp;dummy=.js"></script>
<div id="map" style="width:500px;height:500px;"></div>

JavaScript

var center = new google.maps.LatLng(55.75, 37.62);
var mapOptions = {
    zoom: 10,
    center: center,
    mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map'), mapOptions);

new google.maps.Marker({map: map, position: center});

map.mapTypes.set("Yandex",
                 new google.maps.ImageMapType(
                     {getTileUrl: function(coord, zoom) {
                         return "http://vec0"+((coord.x+coord.y)%5)+".maps.yandex.net/tiles?l=map&v=2.16.0&x=" + 
                             coord.x + "&y=" + coord.y + "&z=" + zoom + "";
                     },
                      tileSize: new google.maps.Size(256, 256),
                      isPng: true,
                      alt: "Yandex",
                      name: "Yandex",
                      projection: new YandexProjection(),
                      maxZoom: 17}));

map.setOptions({mapTypeControlOptions: {mapTypeIds: [google.maps.MapTypeId.ROADMAP, "Yandex"]} });

function YandexProjection() {
    this.pixelOrigin_ = new google.maps.Point(128,128);
    var MERCATOR_RANGE = 256;
    this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
    this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
    
    this.fromLatLngToPoint = function(latLng) {
        function atanh(x) {
            return 0.5*Math.log((1+x)/(1-x));
        }
        function degreesToRadians(deg) {
            return deg * (Math.PI / 180);
        }
        function bound(value, opt_min, opt_max) {
            if (opt_min != null) value = Math.max(value, opt_min);
            if (opt_max != null) value = Math.min(value, opt_max);
            return value;
        }
    
        var origin = this.pixelOrigin_;
        var exct = 0.0818197;
        var z = Math.sin(latLng.lat()/180*Math.PI);
        return new google.maps.Point(origin.x + latLng.lng() *this.pixelsPerLonDegree_,
                                     Math.abs(origin.y -...