src/app/components/map/map.component.ts
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2018 Georgi Marinov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// eslint-disable-next-line no-redeclare
/*global globalThis*/
import { Component, Input, OnInit, OnDestroy, AfterViewInit, ViewChild, ElementRef, HostListener } from '@angular/core';
import { Subscription } from 'rxjs';
import { PortfolioService } from '../../services/portfolio/portfolio.service';
import { MapService } from '../../services/map/map.service';
import { EngineService } from '../../services/engine/engine.service';
import { Indexable } from '../../interfaces/indexable';
/** The global this object */
const global = globalThis as Indexable;
/** The global Plotly object */
const plotly = global.Plotly;
/**
* Map component
* ~implements {@link OnInit}
* ~implements {@link OnDestroy}
* ~implements {@link AfterViewInit}
*/
@Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit, OnDestroy, AfterViewInit {
/** Entity key. */
@Input() key: any;
/** The map element. */
@ViewChild('map') map?: ElementRef;
/** The map html element. */
mapHTMLElement?: HTMLDivElement;
/** Search token subscription. */
private searchTokenSubscription: Subscription | undefined;
/** The resize host listener */
@HostListener('window:resize') onResize() { this.resize(); }
/** The beforeprint host listener */
// tslint:disable-next-line: variable-name
@HostListener('window:beforeprint', ['$event']) onBeforePrint(_event: Event) { this.resize(); }
/**
* Constructs the Map component.
*
* @param portfolioService The portfolio service injected dependency.
* @param mapService The map service injected dependency.
* @param engine The engine service injected dependency.
*/
constructor(
protected readonly portfolioService: PortfolioService,
protected readonly mapService: MapService,
protected readonly engine: EngineService,
) {
}
/** Subscription */
ngOnInit() { this.searchTokenSubscription = this.portfolioService.subscribe('ST', (m: string) => this.onSearchTokenChanged(m)); }
/** Cleanup */
ngOnDestroy() { this.searchTokenSubscription?.unsubscribe(); }
/** Initialization */
ngAfterViewInit() {
this.drawMap();
}
/** Search token changed event handler. */
// tslint:disable-next-line: variable-name
private onSearchTokenChanged(_value: string) {
this.drawMap();
}
/** The resize event handler */
private resize() {
if (this.mapHTMLElement) {
plotly?.Plots.resize(this.mapHTMLElement);
}
}
/**
* Draws a map.
*
* @param entity The entity. Optional.
* @param frequencies The frequencies. Optional.
* @param countriesVisited The countries visited. Optional.
*/
public async drawMap() {
// get map container
const mapContainer = this.map?.nativeElement;
if (!mapContainer) { return; }
// ensure entity
const entity = this.mapService.entity;
if (!entity) { return; }
// ensure frequencies
const frequencies = this.portfolioService.getFrequenciesCache(entity.key);
const frequenciesClone = frequencies.slice(0);
// ensure countriesVisited
const countriesVisited = this.mapService.countriesVisited;
if (!countriesVisited) { return; }
// plot map
const { data, layout } = this.mapService.prepareMap(frequenciesClone, countriesVisited);
this.purgeOldMap();
plotly?.plot(this.mapHTMLElement, data, layout, { showLink: false });
}
/** Purge old map. */
private purgeOldMap() {
// get map container
const mapContainer = this.map?.nativeElement;
if (!mapContainer) { return; }
mapContainer.innerHTML = '';
// crate new map dom node
const map = document.createElement('div');
map.style.cssText = 'width: 100%; height: 250px';
this.mapHTMLElement = mapContainer.appendChild(map);
// console.log('Debug: Map width: ', this.mapHTMLElement.clientWidth);
}
}