How to use seznam mapy within webpack in typescript?

Viewed 260

Seznam mapy (mapy.cz) are great Czech free alternative to google maps with simple API https://api.mapy.cz/. But how to use them with typescript? Within webpacked aplication?

1 Answers

Seznam mapy (SMap) do not support typesctript and not want to. Seznam maps forum

Maps could not be served from your npm packages, it must be loaded just in time. I prepared a factory, helper and example how to create map.

  • Factory loads map scripts and when all things are ready, it call callback funtion afterInit()
  • Helper can creates map and objects consumed by map object
  • Example of map creation
  • Official documentation link https://api.mapy.cz/
import SeznamMapHelper from "./SeznamMapHelper";

// Declare global Loader and SMap
declare global {
    interface Window { Loader: any; SMap: any}
}

export default class SeznamMapFactory {
    // Helper for simple creating seznam mapy objects
    private _mapHelper?: SeznamMapHelper;

    public init(afterInit?: ()=>void) {
        afterInit = afterInit || (() => void 0);
        if (!window.Loader) {
            $.getScript('https://api.mapy.cz/loader.js', ()=> {
                window.Loader.async = true;
                window.Loader.load(null, null, afterInit?.bind(this));
            });
        } else {
            afterInit();
        }

    }

    public get helper(): SeznamMapHelper {
        if (!window.Loader) {
            throw Error('Seznam maps: Loader is not initialised. Please init() first.');
        }
        if (!this._mapHelper) {
            this._mapHelper = new SeznamMapHelper;
        }
        return this._mapHelper;
    }
}

Helper class creating object consumed by SMap object (map layers, markers, etc.). Helper should be improved to fit your purposes.

// Declare types for Seznam Mapy
declare global {
    interface Window { Loader: any; SMap: any}
}

export type TLayer = {
    setClusterer: (clusterer: TClusterer) => TLayer,
    addMarker: (marker: TMarker|TMarker[]) => TLayer,
    enable: () => void,
    disable: () => void,
    redraw: (full: boolean) => void,
    getId: () => string,
};
export type TClusterer = {};
export type TMarker = {
    click: () => void,
    getId: () => void,
    decorate: (type: any, item: TCard)=>void,
};
export type TCard = {
    setSize: (x:number, y:number)=>TCard,
    getHeader: ()=>Element,
    getFooter: ()=>Element,
    getBody: ()=>Element,
}

export type TMap = {
    addDefaultLayer: ([...any])=>TLayer,
    addLayer: (layer: TLayer)=>TLayer,
    addDefaultControls: ()=>TMap,
    enable: ()=>TMap,
}

export default class SeznamMapHelper {
    public createCoords(gpsLat: number, gpsLng: number): {x:number, y:number} {
        return window.SMap.Coords.fromWGS84(gpsLng, gpsLat); // Seznam map has swapped coords, really.
    }

    public createMap(
        el: Element,
        gpsLat: number,
        gpsLng: number,
        zoom: number = 10
    ): TMap {
        const center = this.createCoords(gpsLat, gpsLng);
        return new window.SMap(el, center, zoom);
    }

    public createDefaultMap(el: Element, gpsLat: number = 50.12655, gpsLng: number = 14.41790): TMap {
        const map = this.createMap(el, gpsLat, gpsLng, 10);
        map.addDefaultLayer(window.SMap.DEF_BASE).enable();
        map.addDefaultControls();
        return map;
    }

    public createMarkerLayer(): TLayer {
        return new window.SMap.Layer.Marker();
    }

    public createClusterer(map: TMap): TClusterer {
        return new window.SMap.Marker.Clusterer(map);
    }

    public createMarker(
        gpsLat: number,
        gpsLng: number,
        id: string|number|undefined = undefined,
        title: string = '',
        url: string|null = null
    ): TMarker {
        const options: any = { title: title };
        if (url) {
             options.url = url;
        }
        return new window.SMap.Marker(this.createCoords(gpsLat, gpsLng), id, options);
    }

    public createCard(marker: TMarker, header: string, body: string, footer:string = '', x: number = 200, y:number = 200): TCard {
        const card: TCard = new window.SMap.Card();
        card.setSize(x, y);
        card.getHeader().innerHTML = header;
        card.getBody().innerHTML = body;
        card.getFooter().innerHTML = footer;
        marker.decorate(window.SMap.Marker.Feature.Card, card);

        return card;
    }
}

Example of creating map:

let map: any; // SMap object
let mapContainter = document.getElementById("map"); // Html element to put a map
const mapFactory = new SeznamMapFactory(); // factory object
this.mapFactory.init( () => { // async load of scripts
    map = mapFactory.helper.createDefaultMap(mapContainter); // after load we can use maps
    // other map stuff - markers, layers, etc.
}
Related