<!DOCTYPE html>
<html>
  <head>
    <title>Angular Quickstart</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body {color:#369;font-family: Arial,Helvetica,sans-serif;}
    </style>

    <!-- Polyfills -->
    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>

    <script src="https://unpkg.com/zone.js@0.8.4?main=browser"></script>
    <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
    <script src="systemjs.config.js"></script>
    <script>
      System.import('main.js').catch(function(err){ console.error(err); });
    </script>
  </head>
  

  <body>
    <my-app>Loading AppComponent content here ...</my-app>
  </body>

</html>


import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule);


var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;

module.exports.translate = function(load){
  if (load.source.indexOf('moduleId') != -1) return load;

  var url = document.createElement('a');
  url.href = load.address;

  var basePathParts = url.pathname.split('/');

  basePathParts.pop();
  var basePath = basePathParts.join('/');

  var baseHref = document.createElement('a');
  baseHref.href = this.baseURL;
  baseHref = baseHref.pathname;

  if (!baseHref.startsWith('/base/')) { // it is not karma
    basePath = basePath.replace(baseHref, '');
  }

  load.source = load.source
    .replace(templateUrlRegex, function(match, quote, url){
      let resolvedUrl = url;

      if (url.startsWith('.')) {
        resolvedUrl = basePath + url.substr(1);
      }

      return 'templateUrl: "' + resolvedUrl + '"';
    })
    .replace(stylesRegex, function(match, relativeUrls) {
      var urls = [];

      while ((match = stringRegex.exec(relativeUrls)) !== null) {
        if (match[2].startsWith('.')) {
          urls.push('"' + basePath + match[2].substr(1) + '"');
        } else {
          urls.push('"' + match[2] + '"');
        }
      }

      return "styleUrls: [" + urls.join(', ') + "]";
    });

  return load;
};
/**
 * WEB ANGULAR VERSION
 * (based on systemjs.config.js in angular.io)
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
    transpiler: 'ts',
    typescriptOptions: {
      // Copy of compiler options in standard tsconfig.json
      "target": "es5",
      "module": "commonjs",
      "moduleResolution": "node",
      "sourceMap": true,
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "lib": ["es2015", "dom"],
      "noImplicitAny": true,
      "suppressImplicitAnyIndexErrors": true
    },
    meta: {
      'typescript': {
        "exports": "ts"
      }
    },
    paths: {
      // paths serve as alias
      'npm:': 'https://unpkg.com/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      'app': 'app',

      // angular bundles
      '@angular/animations': 'npm:@angular/animations@4.1.2/bundles/animations.umd.js',
      '@angular/animations/browser': 'npm:@angular/animations@4.1.2/bundles/animations-browser.umd.js',
      '@angular/core': 'npm:@angular/core@4.1.2/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common@4.1.2/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler@4.1.2/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser@4.1.2/bundles/platform-browser.umd.js',
      '@angular/platform-browser/animations': 'npm:@angular/platform-browser@4.1.2/bundles/platform-browser-animations.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@4.1.2/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http@4.1.2/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router@4.1.2/bundles/router.umd.js',
      '@angular/router/upgrade': 'npm:@angular/router@4.1.2/bundles/router-upgrade.umd.js',
      '@angular/forms': 'npm:@angular/forms@4.1.2/bundles/forms.umd.js',
      '@angular/upgrade': 'npm:@angular/upgrade@4.1.2/bundles/upgrade.umd.js',
      '@angular/upgrade/static': 'npm:@angular/upgrade@4.1.2/bundles/upgrade-static.umd.js',

      // other libraries
      'rxjs':                      'npm:rxjs@5.0.1',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api@0.2.4/bundles/in-memory-web-api.umd.js',
      'ts':                        'npm:plugin-typescript@5.2.7/lib/plugin.js',
      'typescript':                'npm:typescript@2.2.1/lib/typescript.js',
      
      '@agm/core': 'npm:@agm/core@1.0.0-beta.0/core.umd.js',

    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.ts',
        defaultExtension: 'ts',
        meta: {
          './*.ts': {
            loader: 'systemjs-angular-loader.js'
          }
        }
      },
      rxjs: {
        defaultExtension: 'js'
      }
    }
  });

})(this);

import {Component, ChangeDetectorRef} from '@angular/core';
import {MapsAPILoader} from "@agm/core";
import {NgForm} from "@angular/forms";

declare let google: any;

@Component({
  selector: 'my-app',
  styles: [`
    .custom-map {
      height: 300px;
      width: 100%;
    }
    .control-ui {
      /* background-color: #eef; */
      background-color: white;
      cursor: pointer;
      min-width: 20em;
    }
    .control-ui:hover {
      background-color: deepskyblue;
    }
    .control-ui.selected {
      background-color: lightblue;
    }
  `],
  template: `
    <div>
      <form #inputForm="ngForm" (ngSubmit)="geocoding(inputForm, searchInput)"  novalidate>
        <input #searchInput type="text" name="address" placeholder="場所を入力してください。" ngModel>
      </form>
    </div>
    
    <div style="position:absolute; z-index: 50; background-color: white;">
       <div id="" *ngFor="let geoCodeResult of geoCodeResults; let i = index" 
        [class]="'control-ui'" [class.selected]="selectedResult===i" (click)="toggleSelectedResult(i, geoCodeResult)" >
          <span>{{geoCodeResult.formattedAddress}}</span>
       </div>
    </div>
    
    <agm-map #agmMap class="custom-map" [latitude]="mapLat" [longitude]="mapLng" [zoom]="mapZoom" 
      (mapClick)="onMapClick()" (mapReady)="onMapReady($event)">
    
      <agm-marker [latitude]="mapLat" [longitude]="mapLng"></agm-marker>
      
      <agm-circle [latitude]="mapLat" [longitude]="mapLng" 
          [radius]="mapRadius"
          [fillColor]="'red'"
          [circleDraggable]="true"
          [editable]="true"
          (centerChange)="onCenterChanged($event)"
          (radiusChange)="onRadiusChanged($event)">
      </agm-circle>
      
      <agm-circle #agmCircle [latitude]="mapLat+0.1" [longitude]="mapLng+0.1" 
          [radius]="mapRadius"
          [fillColor]="'blue'"
          [circleDraggable]="true"
          [editable]="true">
      </agm-circle>
      
    </agm-map>

    <div>current position lat:{{mapLat}} lng:{{mapLng}} radius:{{mapRadius}}m</div>
    <div>clickCount: {{clickCount}}</div>
  `
})
export class AppComponent {
  private readonly MAX_RESULT_NUM:number = 10;

  public mapLat: number = 35.695367;
  public mapLng: number = 139.770797;
  public mapRadius:number = 5000;
  public mapZoom:number = 10;

  public geoCodeResults:GeoCodeResult[] = [];

  public selectedResult:number = -1;

  private geocoder: any = null;
  
  // オーバーレイ用
  public overlay = null;

  constructor(
    private changeDetectorRef: ChangeDetectorRef,
    private mapsAPILoader: MapsAPILoader
  ) {

  }
  
  public onMapReady(nativeMap:GoogleMap):void {

    class USGSOverlay extends google.maps.OverlayView  { // user inner class to avoid error of 'google is not defined'
      //export class USGSOverlay extends google.maps.OverlayView { // exportするとここのgoogleがgoogle is not definedにつかまる
      image_;
      map_;
      div_;

      constructor(map) {
        super(); //  we need to call super

        this.image_  = 'https://developers.google.com/maps/documentation/' +
          'javascript/examples/full/images/talkeetna.png';
        this.map_ = map;

        // Define a property to hold the image's div. We'll
        // actually create this div upon receipt of the onAdd()
        // method so we'll leave it null for now.
        this.div_ = null;

        // Explicitly call setMap on this overlay.
        this.setMap(map);
      }
      /**
       * onAdd is called when the map's panes are ready and the overlay has been
       * added to the map.
       */
      onAdd(){
        const div = document.createElement('div');
        div.style.borderStyle = 'none';
        div.style.borderWidth = '0px';
        div.style.position = 'absolute';

        // Create the img element and attach it to the div.
        const img = document.createElement('img');
        img.src = this.image_;
        img.style.width = '100%';
        img.style.height = '100%';
        img.style.position = 'absolute';
        div.appendChild(img);

        this.div_ = div;

        // Add the element to the "overlayLayer" pane.
        const panes = this.getPanes();
        panes.overlayLayer.appendChild(div);
      };

      draw(){ // 今回は緯度経度を位置に変換することはせずいったん直接指定で地図を表示する
        // We use the south-west and north-east
        // coordinates of the overlay to peg it to the correct position and size.
        // To do this, we need to retrieve the projection from the overlay.
        const overlayProjection = this.getProjection();

        // Retrieve the south-west and north-east coordinates of this overlay
        // in LatLngs and convert them to pixel coordinates.
        // We'll use these coordinates to resize the div.
        //  const sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
        //  const ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
        const sw = {x:100, y:200};
        const ne = {x:200, y:100};


        // Resize the image's div to fit the indicated dimensions.
        const div = this.div_;
        div.style.left = sw.x + 'px';
        div.style.top = ne.y + 'px';
        div.style.width = (ne.x - sw.x) + 'px';
        div.style.height = (sw.y - ne.y) + 'px';
      };

      // The onRemove() method will be called automatically from the API if
      // we ever set the overlay's map property to 'null'.
      onRemove(){
        this.div_.parentNode.removeChild(this.div_);
        this.div_ = null;
      };
    }
    this.overlay = new USGSOverlay(nativeMap);
  }

  private onCenterChanged(center:Center):void {

  }

  private onRadiusChanged(radius:number):void {

  }

  private clickCount:number = 0;
  private onMapClick():void {
    this.clickCount++; // 地図の移動のドラッグの際はカウントされない模様
  }

  private geocoding(form:NgForm, searchInput:HTMLInputElement):void {
    let address:string = form.value.address;
    searchInput.blur();

    this.mapsAPILoader.load().then(() => {
      this.geocoder = new google.maps.Geocoder();
      this.geocoder.geocode(
        {'address': address},
        (result: any, status: any) => {
          if (status === google.maps.GeocoderStatus.OK) {
            this.geoCodeResults = this.translateResultToGeoCodeResultArray(result, this.MAX_RESULT_NUM);
          } else {
            this.geoCodeResults = [];
            console.log("ng:" + status)
          }
          searchInput.focus();
          this.changeDetectorRef.detectChanges();
        });
    });
  }

  private translateResultToGeoCodeResultArray(result:Object, maxResultNum:number):GeoCodeResult[] {
    let retArray:GeoCodeResult[] = [];
    const retLen:number = Math.min(result["length"], maxResultNum);
    for (let i=0; i<retLen; i++) {
      let eachObj:Object = result[i];
      let geoCodeResult:GeoCodeResult = new GeoCodeResult();
      geoCodeResult.formattedAddress = eachObj["formatted_address"];
      geoCodeResult.geometry = eachObj["geometry"];
      retArray.push(geoCodeResult);
    }
    return retArray;
  }

  private toggleSelectedResult(clickedIndex:number, geoCodeResult:GeoCodeResult):void {
    this.selectedResult = clickedIndex;
    this.mapLat = geoCodeResult.geometry.location.lat();
    this.mapLng = geoCodeResult.geometry.location.lng();
    this.changeDetectorRef.detectChanges();
  }

}

interface Center {
  lat:number;
  lng:number;
}

export class GeoCodeResult {
  public formattedAddress:string;
  public geometry:GeoCodeGeometry;
}

interface GeoCodeGeometry {
  location:GeoCodeLocation;
}

interface GeoCodeLocation {
  lat():number;
  lng():number;
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import {CommonModule} from "@angular/common";
import {AgmCoreModule} from "@agm/core";

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,

    CommonModule,
    AgmCoreModule.forRoot({ // Google Maps JavaScript 
      /*apiKey: 'Your API KEY HERE'*/
    })
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }