import {
Component, ElementRef, OnInit, AfterViewChecked, OnDestroy, Input, ViewChild, NgZone,
HostListener, Output, EventEmitter, forwardRef, Inject
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {SafeStyle, DomSanitizer} from '@angular/platform-browser';
import {AbstractComponent, ExternalResourceService, ConfigService} from 'gp-admin-abstract';
declare let ymaps: any;
@Component({
selector: 'gp-yandex-map',
template: `
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => YandexMapComponent),
multi: true
}
]
})
export class YandexMapComponent extends AbstractComponent
implements OnInit, ControlValueAccessor,
AfterViewChecked, OnDestroy {
@Input() width: any;
@Input() height: any;
@Input() center: number[] = [];
@Input() zoom = 10;
@Input() value: number[];
@Input() disabled = false;
@Input() placemarkOptions: any;
@Input() isScrolled = false;
@Input() allowChoosePoint = true;
@Output() onLoad = new EventEmitter();
@Output() onInit = new EventEmitter();
@Output() onChangeBounds = new EventEmitter();
@Output() onViewCheck = new EventEmitter();
@Output() onRemoveAll = new EventEmitter();
@Output() onPanToDone = new EventEmitter();
@ViewChild('container') container: ElementRef;
widthSafeStyle: SafeStyle;
heightSafeStyle: SafeStyle;
/**
* YMap instance
*/
private map: any;
private isInitialized: boolean = false;
propagateChange = (_: any) => {
}
constructor(protected el: ElementRef,
private domSanitizer: DomSanitizer,
private zone: NgZone,
private externalResourceService: ExternalResourceService,
private config: ConfigService) {
super(el);
}
ngOnInit() {
this.widthSafeStyle = this.domSanitizer.bypassSecurityTrustStyle(this.width ? this.width : '100%');
this.heightSafeStyle = this.domSanitizer.bypassSecurityTrustStyle(this.height ? this.height + 'px' : 'calc(100vh)');
this.initYmaps();
}
ngOnDestroy(): void {
if (this.map) {
this.map.destroy();
}
}
ngAfterViewChecked(): void {
this.onViewCheck.emit();
}
writeValue(obj: any): void {
this.value = obj;
if (obj && obj.length === 2 && this.map) {
this.setCoordinate(obj);
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
/**
* Инициализация карт Yandex
*/
private initYmaps(): void {
this.externalResourceService.loadScript(this.config.getConfig().externalServices.ymaps).then(() => {
this.zone.runOutsideAngular(() => {
ymaps.ready().then(() => {
this.onLoad.emit(ymaps);
this.map = new ymaps.Map(this.container.nativeElement, {
center: this.value ? this.value : this.center,
zoom: this.zoom,
controls: ['zoomControl']
}, {
suppressMapOpenBlock: true
});
this.isInitialized = true;
this.onInit.emit(this.map);
if (this.allowChoosePoint) {
this.map.events.add('click', (e: any) => {
this.setPoint(e.get('coords'));
});
}
this.map.events.add('boundschange', (e: any) => {
const fields: string[] = [
'oldCenter', 'newCenter', 'oldZoom', 'newZoom', 'oldGlobalPixelCenter', 'newGlobalPixelCenter',
'oldBounds', 'newBounds'
],
bounds: any = {};
if (e) {
for (let i = 0; i < fields.length; i++) {
bounds[fields[i]] = e.get(fields[i]);
}
this.onChangeBounds.emit(bounds);
}
});
if (!this.isScrolled) {
this.disableScrollZoom();
}
if (this.value) {
this.setPoint(this.value);
}
});
});
});
}
public disableScrollZoom() {
if (this.isInitialized) {
this.map.behaviors.disable('scrollZoom');
}
}
public enableScrollZoom() {
if (this.isInitialized) {
this.map.behaviors.enable('scrollZoom');
}
}
public removeAllObjects(): void {
if (this.isInitialized) {
this.zone.runOutsideAngular(() => {
this.map.geoObjects.removeAll();
this.onRemoveAll.emit();
});
}
}
public addPlacemark(placemark: any) {
if (this.isInitialized) {
this.zone.runOutsideAngular(() => {
this.map.geoObjects.add(placemark);
});
}
}
public reDraw(): void {
if (this.map) {
this.zone.runOutsideAngular(() => {
this.map.container.fitToViewport();
});
}
}
/**
* Метод установки точки на карте
*
* @param point
*/
private setPoint(point: any): void {
if (this.isInitialized) {
this.zone.runOutsideAngular(() => {
const placemark = new ymaps.Placemark(point, this.placemarkOptions);
this.removeAllObjects();
this.addPlacemark(placemark);
this.propagateChange(point);
});
}
}
/**
* Метод установки нового центра карты
*
* @param {number[]} coordinate
*/
public setCoordinate(coordinate: number[]): void {
if (this.map) {
ymaps.ready().then(() => {
this.map.panTo(coordinate, {checkZoomRange: true})
.then(() => {
this.onPanToDone.emit();
});
});
}
}
@HostListener('window:resize')
onWindowResize() {
this.reDraw();
}
}