ultimap
Version:
Universal map api
230 lines (196 loc) • 7.11 kB
text/typescript
import * as L from 'leaflet';
import { LatLng, Map, Bounds as LBounds } from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { ICreateMapStrategyOptions, IMapStrategy } from '../interface/map';
import { Coords } from '../../coords';
import { Bounds } from '../../bounds';
import { EventHandlerFn, IEventHandlerFnMap } from '../../events';
import './style/map.less';
export interface ILeafletMapStrategyProps {
tileLayerProviderLink?: string;
copyrights?: string[];
}
export class LeafletMapStrategy implements IMapStrategy {
protected props: ILeafletMapStrategyProps;
constructor(props?: ILeafletMapStrategyProps) {
this.initProps(props);
}
/**
* Произвести загрузку карты в элемент
* @param {HTMLElement} element
* @param {ICreateMapStrategyOptions} options
* @return {Promise<any>}
*/
public load(element: HTMLElement, options: ICreateMapStrategyOptions): Promise<any> {
return new Promise((resolve: (result: any) => void) => {
const instance = L.map(element, { editable: true } as any).on('load', () => {
resolve(instance);
});
L.tileLayer(this.props.tileLayerProviderLink, {
attribution: this.props.copyrights.join(' | '),
maxZoom: 18,
}).addTo(instance);
const center = options.center
? options.center.toArray()
: null;
const boundsCoords = options.bounds
? (new LBounds(options.bounds.toArray() as any)).getCenter()
: null;
const boundsCenter = boundsCoords
? [boundsCoords.x, boundsCoords.y] as [number, number]
: null;
instance.setView(center || boundsCenter, options.zoom);
(instance as any)._controlCorners['custom'] = L.DomUtil
.create('div', 'leaflet-custom', (instance as any)._controlContainer);
});
}
/**
* Уничтожить карту
*
* @param {Map} map
*
* @return {Promise<IMapStrategy>}
*/
public destroy(map: Map): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
map.remove();
resolve(this);
});
}
/**
* Установить центр для карты
*
* @param {Map} map
* @param {Coords} coords
*
* @return {IMapStrategy}
*/
public setCenter(map: Map, coords: Coords): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
// @TODO Проверка на то что можно остановить анимацию (при еще не загруженной карте все ломается)
// map.stop();
// @TODO listen event for complete
map.panTo(coords.toArray());
resolve(this);
});
}
/**
* Получить значение центра для карты
*
* @param {Map} map
*
* @return {Coords}
*/
public getCenter(map: Map): Coords {
const center: LatLng = map.getCenter();
return new Coords(center.lat, center.lng);
}
/**
* Установить текущее занчение зума
* @param {Map} map
* @param {number} value
* @return {IMapStrategy}
*/
public setZoom(map: Map, value: number): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
// @TODO listen event for complete
map.setZoom(value);
resolve(this);
});
}
/**
* Получить текущее значение зума
* @param {Map} map
* @return {number}
*/
public getZoom(map: Map): number {
return map.getZoom();
}
/**
* Установить область отображения карты
* @param map
* @param {Bounds} value
* @return {IMapStrategy}
*/
public setBounds(map: Map, value: Bounds): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
// @TODO Проверка на то что можно остановить анимацию (при еще не загруженной карте все ломается)
// map.stop();
// @TODO listen event for complete change bounds
map.fitBounds(value.toArray() as any);
resolve(this);
});
}
/**
* Получить область отображения карты
* @return {Bounds}
*/
public getBounds(map: Map): Bounds {
const bounds = map.getBounds();
const northEast = bounds.getNorthEast();
const southWest = bounds.getSouthWest();
return new Bounds({
lat: northEast.lat,
lng: northEast.lng,
}, {
lat: southWest.lat,
lng: southWest.lng,
});
}
public on(geoObject: Map, type: string | IEventHandlerFnMap, fn?: EventHandlerFn, context?: any): IMapStrategy {
geoObject.on(type as string, fn, context);
return this;
}
public off(geoObject: Map, type: string, fn?: EventHandlerFn, context?: any): IMapStrategy {
geoObject.off(type as string, fn, context);
return this;
}
/**
* Обновить отображаемую область
* @param {Map} map
* @return {Promise<IMapStrategy>}
*/
public fitToViewport(map: Map): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
map.invalidateSize(false);
resolve(this);
});
}
/**
* Добавить элемент управления на карту
*
* @param map
* @param control
*
* @return {Promise<IMapStrategy>}
*/
public addControl(map: L.Map, control: L.Control): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
control.addTo(map);
resolve(this);
});
}
/**
* Remove control from map
* @param map
* @param control
* @return {Promise<IMapStrategy>}
*/
public removeControl(map: L.Map, control: L.Control): Promise<IMapStrategy> {
return new Promise((resolve: (result: IMapStrategy) => void) => {
(control as any).remove();
resolve(this);
});
}
protected initProps(props?: ILeafletMapStrategyProps) {
if (this.props) {
throw new Error('Properties already exist');
}
this.props = Object.assign({
tileLayerProviderLink: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
copyrights: [
'© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors',
],
}, props || { });
}
}