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(); } }