Search code examples
javascriptmapkit

Zoom and position management in MapKit.js


I've created the following map using MapKit.js, with hundred of custom annotations, clustering (yellow dots) and callout popup on annotation click.

What I want to do, when clicking on the popup link, is simply to zoom in one step and center view on the clicked annotation (in a responsive context).

MapKit.js map

In Google Maps, that I'm used to, you simply position the map by its center and zoom level.

In MapKit.js, you use a center/region combo, and honestly I can't understand how this works.

This center/region thing still doesn't make sense to me, so I've decided to override MapKit.js with a zoom feature.

Thanks to this post, I've manage to implement the zoom calculation, which seems to be ok.

I need now to implement the set zoom action.
No success yet, this math things are so far now ^^

Function:

function MapKitJsZoom(map) {
    var LN2 = 0.6931471805599453; // ???
    var WH = 256; // World Height
    var WW = 256; // World Width
    var MAX = 21; // Max zoom level

    // GET CURRENT ZOOM.

    var latToRad = function (lat) {
        var sin = Math.sin(lat * Math.PI / 180);
        var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
        return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
    };

    var zoom = function (mapPx, worldPx, fraction) {
        return (Math.log(mapPx / worldPx / fraction) / LN2);
    };

    this.get = function () {
        var bounds = map.region.toBoundingRegion();
        var latFraction = (latToRad(bounds.northLatitude) - latToRad(bounds.southLatitude)) / Math.PI;
        var latZoom = zoom(map.element.clientHeight, WH, latFraction);

        var lngDiff = bounds.eastLongitude - bounds.westLongitude;
        var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
        var lngZoom = zoom(map.element.clientWidth, WW, lngFraction);

        return Math.round(Math.min(latZoom, lngZoom, MAX));
    };

    // SET CURRENT ZOOM

    this.set = function (zoom) {
        // TODO
        // I need to calculate latitude and longitude deltas
        // that correspond to required zoom based on viewport size
        // (map.element.clientWidth and map.element.clientHeight)

        map.region.span = new mapkit.CoordinateSpan(latitudeDelta, longitudeDelta);
    };

}

Usage:

    var map = new mapkit.Map("map");

    map.zoom = new MapKitJsZoom(map);

    map.addEventListener('region-change-end', function () {
        console.log(map.zoom.get());
    });

Solution

  • There are two methods of accomplishing this:

    1) set center then change zoom level

    var newCenter = new mapkit.Coordinate(37.792446, -122.399360);
    map._impl.zoomLevel--;
    map.setCenterAnimated(newCenter, true);
    

    2) set region using center and span (delta in degress)

    var newCenter = new mapkit.Coordinate(37.792446, -122.399360);
    var span = new mapkit.CoordinateSpan(.01);
    var region = new mapkit.CoordinateRegion(newCenter, span);
    map.setRegionAnimated(region)