<commit_before>import { Component, ChangeDetectorRef, OnInit, AfterViewInit, ViewChild, Inject, HostListener } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { PageScrollConfig, PageScrollService, PageScrollInstance } from 'ng2-page-scroll';
import 'rxjs/add/operator/take';
import {scaleLinear} from 'd3-scale';
import { TranslateService, TranslatePipe, TranslateDirective } from '@ngx-translate/core';

import { MapFeature } from './map/map-feature';
import { MapComponent } from './map/map/map.component';
import { UiToastComponent } from '../ui/ui-toast/ui-toast.component';
import { DataService } from '../data/data.service';

// Temporarily adding debounce function here to avoid compilation errors
// caused by the `debounce-decorator`.  See the following issues for more:
// https://github.com/angular/angular-cli/issues/8434
// https://github.com/Microsoft/TypeScript/issues/17384
function debounce(func, wait, immediate) {
	var timeout;
	return function() {
		var context = this, args = arguments;
		var later = function() {
			timeout = null;
			if (!immediate) func.apply(context, args);
		};
		var callNow = immediate && !timeout;
		clearTimeout(timeout);
		timeout = setTimeout(later, wait);
		if (callNow) func.apply(context, args);
	};
};

@Component({
  selector: 'app-map-tool',
  templateUrl: './map-tool.component.html',
  styleUrls: ['./map-tool.component.scss']
})
export class MapToolComponent implements OnInit, AfterViewInit {
  title = 'Eviction Lab';
  // autoSwitchLayers = true;
  enableZoom = true; // controls if map scroll zoom is enabled
  wheelEvent = false; // tracks if there is an active wheel event
  currentRoute = [];
  verticalOffset; // stores the amount the page has scrolled
  panelOffset: number; // tracks the vertical offset to the data panel
  offsetToTranslate; // function that maps vertical offset to the
  activeMenuItem; // tracks the active menu item on mobile
  /** gets if the page has scrolled enough to fix the "back to map" button */
  get isDataButtonFixed() {
    if (!this.panelOffset || !this.verticalOffset) { return false; }
    return (this.verticalOffset - this.panelOffset) > 0;
  }
  get isLoading() {
    return this.map.mapLoading || this.dataService.isLoading;
  }
  @ViewChild(MapComponent) map;
  @ViewChild(UiToastComponent) toast;
  @ViewChild('divider') dividerEl;
  urlParts;

  constructor(
    private cdRef: ChangeDetectorRef,
    private route: ActivatedRoute,
    private router: Router,
    private pageScrollService: PageScrollService,
    private translate: TranslateService,
    public dataService: DataService,
    @Inject(DOCUMENT) private document: any
  ) {}

  ngOnInit() {
    this.configurePageScroll();
    this.route.url.subscribe((url) => { this.urlParts = url; });
    this.route.data.take(1).subscribe(this.setMapToolData.bind(this));
    this.route.paramMap.take(1).subscribe(this.setRouteParams.bind(this));
  }

  /**
   * Set the panel offset when the divider element is present
   */
  ngAfterViewInit() {
    this.panelOffset = this.dividerEl.nativeElement.getBoundingClientRect().bottom;
    this.setOffsetToTranslate();
  }

  /**
   * Update the position of the data panel on window resize
   * @param e resize event
   */
  @HostListener('window:resize', [ '$event' ])
  onresize(e) {
    this.panelOffset =
      this.verticalOffset + this.dividerEl.nativeElement.getBoundingClientRect().bottom;
    this.setOffsetToTranslate();
  }


  /**
   * Configures the data service based on any route parameters
   */
  setRouteParams(params: ParamMap) {
    if (params.has('year')) {
      this.dataService.activeYear = params.get('year');
    }
    if (params.has('choropleth')) {
      this.dataService.setChoroplethHighlight(params.get('choropleth'));
    }
    if (params.has('type')) {
      this.dataService.setBubbleHighlight(params.get('type'));
    }
    if (params.has('geography')) {
      const geo = params.get('geography');
      if (geo !== 'auto') {
        this.dataService.setGeographyLevel(geo);
        // this.autoSwitchLayers = false;
      }
    }
    if (params.has('locations')) {
      const locations = this.getLocationsFromString(params.get('locations'));
      this.dataService.setLocations(locations);
    }
    if (params.has('bounds')) {
      const b = params.get('bounds').split(',');
      if (b.length === 4) {
        this.dataService.setMapBounds(b);
      }
    }
    this.cdRef.detectChanges();
  }

  /**
   * Configures the data service with any static data passed through the route
   */
  setMapToolData(data) {
    this.dataService.mapConfig = data.mapConfig;
    if (data.hasOwnProperty('year')) {
      this.dataService.activeYear = data.year;
    }
  }

  /** Update route if it has changed */
  updateRoute() {
    if (this.urlParts && this.urlParts.length && this.urlParts[0].path !== 'editor') {
      this.router.navigate(this.dataService.getRouteArray(), { replaceUrl: true });
    }
  }

  /**
   * Accepts a clicked feature, queries tile data to get data across all years
   * @param feature returned from featureClick event
   */
  onFeatureSelect(feature: MapFeature) {
    const featureLonLat = this.dataService.getFeatureLonLat(feature);
    this.dataService.isLoading = true;
    this.dataService.getTileData(feature['layer']['id'], featureLonLat, null, true)
      .subscribe(data => {
        if (this.dataService.activeFeatures.length < 3) {
          const locationAdded = this.dataService.addLocation(data);
          if (!locationAdded) {
            this.toast.display('You have already selected this location.');
          }
        } else {
          this.toast.display(
            'You have selected the maximum allowed locations. ' +
            'Dismiss one of the locations and try again.'
          );
        }
        this.updateRoute();
        this.dataService.isLoading = false;
      });
  }<commit_msg>Update max location text<commit_after>import { Component, ChangeDetectorRef, OnInit, AfterViewInit, ViewChild, Inject, HostListener } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { PageScrollConfig, PageScrollService, PageScrollInstance } from 'ng2-page-scroll';
import 'rxjs/add/operator/take';
import {scaleLinear} from 'd3-scale';
import { TranslateService, TranslatePipe, TranslateDirective } from '@ngx-translate/core';

import { MapFeature } from './map/map-feature';
import { MapComponent } from './map/map/map.component';
import { UiToastComponent } from '../ui/ui-toast/ui-toast.component';
import { DataService } from '../data/data.service';

// Temporarily adding debounce function here to avoid compilation errors
// caused by the `debounce-decorator`.  See the following issues for more:
// https://github.com/angular/angular-cli/issues/8434
// https://github.com/Microsoft/TypeScript/issues/17384
function debounce(func, wait, immediate) {
	var timeout;
	return function() {
		var context = this, args = arguments;
		var later = function() {
			timeout = null;
			if (!immediate) func.apply(context, args);
		};
		var callNow = immediate && !timeout;
		clearTimeout(timeout);
		timeout = setTimeout(later, wait);
		if (callNow) func.apply(context, args);
	};
};

@Component({
  selector: 'app-map-tool',
  templateUrl: './map-tool.component.html',
  styleUrls: ['./map-tool.component.scss']
})
export class MapToolComponent implements OnInit, AfterViewInit {
  title = 'Eviction Lab';
  // autoSwitchLayers = true;
  enableZoom = true; // controls if map scroll zoom is enabled
  wheelEvent = false; // tracks if there is an active wheel event
  currentRoute = [];
  verticalOffset; // stores the amount the page has scrolled
  panelOffset: number; // tracks the vertical offset to the data panel
  offsetToTranslate; // function that maps vertical offset to the
  activeMenuItem; // tracks the active menu item on mobile
  /** gets if the page has scrolled enough to fix the "back to map" button */
  get isDataButtonFixed() {
    if (!this.panelOffset || !this.verticalOffset) { return false; }
    return (this.verticalOffset - this.panelOffset) > 0;
  }
  get isLoading() {
    return this.map.mapLoading || this.dataService.isLoading;
  }
  @ViewChild(MapComponent) map;
  @ViewChild(UiToastComponent) toast;
  @ViewChild('divider') dividerEl;
  urlParts;

  constructor(
    private cdRef: ChangeDetectorRef,
    private route: ActivatedRoute,
    private router: Router,
    private pageScrollService: PageScrollService,
    private translate: TranslateService,
    public dataService: DataService,
    @Inject(DOCUMENT) private document: any
  ) {}

  ngOnInit() {
    this.configurePageScroll();
    this.route.url.subscribe((url) => { this.urlParts = url; });
    this.route.data.take(1).subscribe(this.setMapToolData.bind(this));
    this.route.paramMap.take(1).subscribe(this.setRouteParams.bind(this));
  }

  /**
   * Set the panel offset when the divider element is present
   */
  ngAfterViewInit() {
    this.panelOffset = this.dividerEl.nativeElement.getBoundingClientRect().bottom;
    this.setOffsetToTranslate();
  }

  /**
   * Update the position of the data panel on window resize
   * @param e resize event
   */
  @HostListener('window:resize', [ '$event' ])
  onresize(e) {
    this.panelOffset =
      this.verticalOffset + this.dividerEl.nativeElement.getBoundingClientRect().bottom;
    this.setOffsetToTranslate();
  }


  /**
   * Configures the data service based on any route parameters
   */
  setRouteParams(params: ParamMap) {
    if (params.has('year')) {
      this.dataService.activeYear = params.get('year');
    }
    if (params.has('choropleth')) {
      this.dataService.setChoroplethHighlight(params.get('choropleth'));
    }
    if (params.has('type')) {
      this.dataService.setBubbleHighlight(params.get('type'));
    }
    if (params.has('geography')) {
      const geo = params.get('geography');
      if (geo !== 'auto') {
        this.dataService.setGeographyLevel(geo);
        // this.autoSwitchLayers = false;
      }
    }
    if (params.has('locations')) {
      const locations = this.getLocationsFromString(params.get('locations'));
      this.dataService.setLocations(locations);
    }
    if (params.has('bounds')) {
      const b = params.get('bounds').split(',');
      if (b.length === 4) {
        this.dataService.setMapBounds(b);
      }
    }
    this.cdRef.detectChanges();
  }

  /**
   * Configures the data service with any static data passed through the route
   */
  setMapToolData(data) {
    this.dataService.mapConfig = data.mapConfig;
    if (data.hasOwnProperty('year')) {
      this.dataService.activeYear = data.year;
    }
  }

  /** Update route if it has changed */
  updateRoute() {
    if (this.urlParts && this.urlParts.length && this.urlParts[0].path !== 'editor') {
      this.router.navigate(this.dataService.getRouteArray(), { replaceUrl: true });
    }
  }

  /**
   * Accepts a clicked feature, queries tile data to get data across all years
   * @param feature returned from featureClick event
   */
  onFeatureSelect(feature: MapFeature) {
    const featureLonLat = this.dataService.getFeatureLonLat(feature);
    this.dataService.isLoading = true;
    this.dataService.getTileData(feature['layer']['id'], featureLonLat, null, true)
      .subscribe(data => {
        if (this.dataService.activeFeatures.length < 3) {
          const locationAdded = this.dataService.addLocation(data);
          if (!locationAdded) {
            this.toast.display('You have already selected this location.');
          }
        } else {
          this.toast.display(
            'Maximum limit reached. Please remove a location to add another.'
          );
        }
        this.updateRoute();
        this.dataService.isLoading = false;
      });
  }
{'fraction_non_alphanumeric': 0.12920264945082585, 'fraction_numerical': 0.002850674939213549, 'mean_word_length': 3.416142169566827, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4924169', 'n_tokens_mistral': 3586, 'n_tokens_neox': 3509, 'n_words': 858}