Yrkki/cv-generator-fe

View on GitHub
src/app/services/map/map.service.ts

Summary

Maintainability
A
0 mins
Test Coverage
// 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.
//
import { Injectable } from '@angular/core';
import { Indexable } from '../../interfaces/indexable';

import { ModelModel } from '../../model/model/model.model';

/**
 * A map service.
 */
@Injectable({
  providedIn: 'root'
})
export class MapService {
  /** The layout */
  private get layout() {
    return {
      title: 'Markets',
      geo: {
        scope: 'world',
        resolution: 50,
        projection: { type: 'robinson', scale: 4.5 },
        center: { lon: 35, lat: 52 },
        bgcolor: 'rgba(0,0,0,0)',
        showocean: true, oceancolor: 'rgba(0,255,255,0.2)',
        showland: false, landcolor: 'rgba(0,0,0,0.2)',
        showlakes: true, lakecolor: 'rgba(0,128,255,0.2)',
        showrivers: true, rivercolor: 'rgba(0,0,255,0.2)',
        showcountries: true, countrycolor: 'rgba(128,128,128,0.2)',
        showcoastlines: true, coastlinecolor: 'rgba(0,0,0,0.2)',
        showframe: true, framecolor: 'rgba(0,0,0,0.2)',
      },
      // eslint-disable-next-line camelcase
      paper_bgcolor: 'rgba(0,0,0,0)',
      // eslint-disable-next-line camelcase
      plot_bgcolor: 'rgba(0,0,0,0)',
      margin: { t: 0, l: 0, r: 0, b: 0 }
    };
  }

  /** Get countries visited. */
  public get countriesVisited(): string[] {
    const countries = 'Countries visited';
    return this.model.cv[countries];
  }

  /** Get countries visited. */
  public get entity() {
    const constCountry = 'Country';
    return this.model.entities[constCountry];
  }

  /**
   * Constructs a map.
   * ~constructor
   *
   * @param model The model injected dependency.
   */
  constructor(
    public readonly model: ModelModel,
  ) {
  }

  /**
   * The data.
   *
   * @param locations The locations.
   * @param z The counts.
   * @param colorScaleMinValue The color scale min value.
   */
  private getData(locations: any[], z: number[], colorScaleMinValue: number) {
    return [{
      type: 'choropleth',
      locationmode: 'country names',
      locations, z,
      // text: locations,
      autocolorscale: false,
      colorscale: [
        [0, '#00000020'],  // countries visited background color
        [colorScaleMinValue, 'rgb(65,105,225)'],
        [1, 'rgb(220,166,224)']
        // [0, 'rgba(0, 0, 255, 1)'],
        // [1, 'rgba(255, 0, 0, 1)']
      ],
      colorbar: {
        // title: 'Markets count',
        thickness: 20,
        tick0: 0,
        dtick: 1,
        autotick: false
      },
      marker: { line: { color: 'rgba(0,0,0,0.5)', width: 1 }, opacity: 1 }
    }];
  }

  /**
   * Prepares a map.
   *
   * @param frequencies The frequencies.
   * @param countriesVisited The countries visited.
   */
  public prepareMap(frequencies: Indexable[], countriesVisited: string[]) {
    // prepend other visited countries as map background
    [...countriesVisited].reverse().forEach((country) => {
      // tslint:disable-next-line: variable-name
      if (!frequencies.map((value: Indexable, _index: number, _array: Indexable[]) => value[0]).includes(country)) {
        frequencies.unshift([country, { Count: 0 }]);
      }
    });

    // prepare data settings
    // tslint:disable-next-line: variable-name
    const locations = frequencies.map((value: Indexable, _index: number, _array: Indexable[]) => value[0]);
    // tslint:disable-next-line: variable-name
    const z = frequencies.map((value: Indexable, _index: number, _array: Indexable[]) => Number(value[1].Count));

    // calc color scale min value
    let maxCount = Math.max(...z);
    if (maxCount === 0) { maxCount = 1; }
    const colorScaleMinValue = 1 / maxCount;

    const data = this.getData(locations, z, colorScaleMinValue);
    const layout = this.layout;
    return { data, layout };
  }
}