diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 000000000..92cde390a
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,3 @@
+{
+ "singleQuote": true
+}
\ No newline at end of file
diff --git a/docs/content/guides/auto-fit-bounds.md b/docs/content/guides/auto-fit-bounds.md
new file mode 100644
index 000000000..67d6f01a7
--- /dev/null
+++ b/docs/content/guides/auto-fit-bounds.md
@@ -0,0 +1,19 @@
++++
+date = "2018-09-22T09:31:00-01:00"
+draft = false
+title = "Enable auto fit bounds"
+
++++
+
+Angular Google Maps (AGM) has an auto fit bounds feature, that adds all containing components to the bounds of the map.
+To enable it, set the `fitBounds` input of `agm-map` to `true` and add the `agmFitBounds` input/directive to `true` for all components
+you want to include in the bounds of the map.
+
+```html
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/docs/content/guides/implement-auto-fit-bounds.md b/docs/content/guides/implement-auto-fit-bounds.md
new file mode 100644
index 000000000..26e0ae96c
--- /dev/null
+++ b/docs/content/guides/implement-auto-fit-bounds.md
@@ -0,0 +1,54 @@
++++
+date = "2018-09-22T09:31:00-01:00"
+draft = false
+title = "Support auto fit bounds for custom components"
+
++++
+
+Angular Google Maps (AGM) has an auto fit bounds feature, that adds all containing components to the bounds of the map:
+
+```html
+
+
+
+```
+
+Let`s say we have a custom component, that extends the features of AGM:
+
+
+```html
+
+
+
+```
+
+To add support the auto fit bounds feature for ``, we have to implement the `FitBoundsAccessor`:
+
+```typescript
+import { FitBoundsAccessor, FitBoundsDetails } from '@agm/core';
+import { forwardRef, Component } from '@angular/core';
+
+@Component({
+ selector: 'my-custom-component',
+ template: '',
+ providers: [
+ {provide: FitBoundsAccessor, useExisting: forwardRef(() => MyCustomComponent)}
+ ],
+})
+export class MyCustomComponent implements FitBoundsAccessor {
+ **
+ * This is a method you need to implement with your custom logic.
+ */
+ getFitBoundsDetails$(): Observable {
+ return ...;
+ }
+}
+```
+
+The last step is to change your template. Add the `agmFitBounds` input/directive and set the value to true:
+
+```html
+
+
+
+```
\ No newline at end of file
diff --git a/packages/core/core.module.ts b/packages/core/core.module.ts
index f4f4277bc..97b0edc2b 100644
--- a/packages/core/core.module.ts
+++ b/packages/core/core.module.ts
@@ -13,6 +13,7 @@ import {LazyMapsAPILoader} from './services/maps-api-loader/lazy-maps-api-loader
import {LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral} from './services/maps-api-loader/lazy-maps-api-loader';
import {MapsAPILoader} from './services/maps-api-loader/maps-api-loader';
import {BROWSER_GLOBALS_PROVIDERS} from './utils/browser-globals';
+import {AgmFitBounds} from '@agm/core/directives/fit-bounds';
/**
* @internal
@@ -21,7 +22,7 @@ export function coreDirectives() {
return [
AgmMap, AgmMarker, AgmInfoWindow, AgmCircle, AgmRectangle,
AgmPolygon, AgmPolyline, AgmPolylinePoint, AgmKmlLayer,
- AgmDataLayer
+ AgmDataLayer, AgmFitBounds
];
}
diff --git a/packages/core/directives.ts b/packages/core/directives.ts
index d4bb07238..3edc4fef9 100644
--- a/packages/core/directives.ts
+++ b/packages/core/directives.ts
@@ -8,3 +8,4 @@ export {AgmMarker} from './directives/marker';
export {AgmPolygon} from './directives/polygon';
export {AgmPolyline} from './directives/polyline';
export {AgmPolylinePoint} from './directives/polyline-point';
+export {AgmFitBounds} from './directives/fit-bounds';
diff --git a/packages/core/directives/fit-bounds.ts b/packages/core/directives/fit-bounds.ts
new file mode 100644
index 000000000..954b10af7
--- /dev/null
+++ b/packages/core/directives/fit-bounds.ts
@@ -0,0 +1,78 @@
+import { Directive, OnInit, Self, OnDestroy, Input, OnChanges, SimpleChanges } from '@angular/core';
+import { FitBoundsService, FitBoundsAccessor, FitBoundsDetails } from '../services/fit-bounds';
+import { Subscription, Subject } from 'rxjs';
+import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
+import { LatLng, LatLngLiteral } from '@agm/core';
+
+/**
+ * Adds the given directive to the auto fit bounds feature when the value is true.
+ * To make it work with you custom AGM component, you also have to implement the {@link FitBoundsAccessor} abstract class.
+ * @example
+ *
+ */
+@Directive({
+ selector: '[agmFitBounds]'
+})
+export class AgmFitBounds implements OnInit, OnDestroy, OnChanges {
+ /**
+ * If the value is true, the element gets added to the bounds of the map.
+ * Default: true.
+ */
+ @Input() agmFitBounds: boolean = true;
+
+ private _destroyed$: Subject = new Subject();
+ private _latestFitBoundsDetails: FitBoundsDetails | null = null;
+
+ constructor(
+ @Self() private readonly _fitBoundsAccessor: FitBoundsAccessor,
+ private readonly _fitBoundsService: FitBoundsService
+ ) {}
+
+ /**
+ * @internal
+ */
+ ngOnChanges(changes: SimpleChanges) {
+ this._updateBounds();
+ }
+
+ /**
+ * @internal
+ */
+ ngOnInit() {
+ this._fitBoundsAccessor
+ .getFitBoundsDetails$()
+ .pipe(
+ distinctUntilChanged(
+ (x: FitBoundsDetails, y: FitBoundsDetails) =>
+ x.latLng.lat === y.latLng.lng
+ ),
+ takeUntil(this._destroyed$)
+ )
+ .subscribe(details => this._updateBounds(details));
+ }
+
+ private _updateBounds(newFitBoundsDetails?: FitBoundsDetails) {
+ if (newFitBoundsDetails) {
+ this._latestFitBoundsDetails = newFitBoundsDetails;
+ }
+ if (!this._latestFitBoundsDetails) {
+ return;
+ }
+ if (this.agmFitBounds) {
+ this._fitBoundsService.addToBounds(this._latestFitBoundsDetails.latLng);
+ } else {
+ this._fitBoundsService.removeFromBounds(this._latestFitBoundsDetails.latLng);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ ngOnDestroy() {
+ this._destroyed$.next();
+ this._destroyed$.complete();
+ if (this._latestFitBoundsDetails !== null) {
+ this._fitBoundsService.removeFromBounds(this._latestFitBoundsDetails.latLng);
+ }
+ }
+}
diff --git a/packages/core/directives/map.ts b/packages/core/directives/map.ts
index 00d30964f..ac1454abf 100644
--- a/packages/core/directives/map.ts
+++ b/packages/core/directives/map.ts
@@ -15,6 +15,9 @@ import {PolygonManager} from '../services/managers/polygon-manager';
import {PolylineManager} from '../services/managers/polyline-manager';
import {KmlLayerManager} from './../services/managers/kml-layer-manager';
import {DataLayerManager} from './../services/managers/data-layer-manager';
+import {FitBoundsService} from '../services/fit-bounds';
+
+declare var google: any;
/**
* AgmMap renders a Google Map.
@@ -43,7 +46,8 @@ import {DataLayerManager} from './../services/managers/data-layer-manager';
selector: 'agm-map',
providers: [
GoogleMapsAPIWrapper, MarkerManager, InfoWindowManager, CircleManager, RectangleManager,
- PolylineManager, PolygonManager, KmlLayerManager, DataLayerManager
+ PolylineManager, PolygonManager, KmlLayerManager, DataLayerManager, DataLayerManager,
+ FitBoundsService
],
host: {
// todo: deprecated - we will remove it with the next version
@@ -180,8 +184,9 @@ export class AgmMap implements OnChanges, OnInit, OnDestroy {
/**
* Sets the viewport to contain the given bounds.
+ * If this option to `true`, the bounds get automatically computed from all elements that use the {@link AgmFitBounds} directive.
*/
- @Input() fitBounds: LatLngBoundsLiteral|LatLngBounds = null;
+ @Input() fitBounds: LatLngBoundsLiteral|LatLngBounds|boolean = false;
/**
* The initial enabled/disabled state of the Scale control. This is disabled by default.
@@ -267,6 +272,7 @@ export class AgmMap implements OnChanges, OnInit, OnDestroy {
];
private _observableSubscriptions: Subscription[] = [];
+ private _fitBoundsSubscription: Subscription;
/**
* This event emitter gets emitted when the user clicks on the map (but not when they click on a
@@ -317,7 +323,7 @@ export class AgmMap implements OnChanges, OnInit, OnDestroy {
*/
@Output() mapReady: EventEmitter = new EventEmitter();
- constructor(private _elem: ElementRef, private _mapsWrapper: GoogleMapsAPIWrapper) {}
+ constructor(private _elem: ElementRef, private _mapsWrapper: GoogleMapsAPIWrapper, protected _fitBoundsService: FitBoundsService) {}
/** @internal */
ngOnInit() {
@@ -378,6 +384,9 @@ export class AgmMap implements OnChanges, OnInit, OnDestroy {
// remove all listeners from the map instance
this._mapsWrapper.clearInstanceListeners();
+ if (this._fitBoundsSubscription) {
+ this._fitBoundsSubscription.unsubscribe();
+ }
}
/* @internal */
@@ -417,13 +426,13 @@ export class AgmMap implements OnChanges, OnInit, OnDestroy {
private _updatePosition(changes: SimpleChanges) {
if (changes['latitude'] == null && changes['longitude'] == null &&
- changes['fitBounds'] == null) {
+ !changes['fitBounds']) {
// no position update needed
return;
}
// we prefer fitBounds in changes
- if (changes['fitBounds'] && this.fitBounds != null) {
+ if ('fitBounds' in changes) {
this._fitBounds();
return;
}
@@ -447,11 +456,42 @@ export class AgmMap implements OnChanges, OnInit, OnDestroy {
}
private _fitBounds() {
+ switch (this.fitBounds) {
+ case true:
+ this._subscribeToFitBoundsUpdates();
+ break;
+ case false:
+ if (this._fitBoundsSubscription) {
+ this._fitBoundsSubscription.unsubscribe();
+ }
+ break;
+ default:
+ this._updateBounds(this.fitBounds);
+ }
+ }
+
+ private _subscribeToFitBoundsUpdates() {
+ this._fitBoundsSubscription = this._fitBoundsService.getBounds$().subscribe(b => this._updateBounds(b));
+ }
+
+ protected _updateBounds(bounds: LatLngBounds|LatLngBoundsLiteral) {
+ if (this._isLatLngBoundsLiteral(bounds)) {
+ const newBounds = google.maps.LatLngBounds();
+ newBounds.union(bounds);
+ bounds = newBounds;
+ }
+ if (bounds.isEmpty()) {
+ return;
+ }
if (this.usePanning) {
- this._mapsWrapper.panToBounds(this.fitBounds);
+ this._mapsWrapper.panToBounds(bounds);
return;
}
- this._mapsWrapper.fitBounds(this.fitBounds);
+ this._mapsWrapper.fitBounds(bounds);
+ }
+
+ private _isLatLngBoundsLiteral(bounds: LatLngBounds|LatLngBoundsLiteral): bounds is LatLngBoundsLiteral {
+ return (bounds).extend === undefined;
}
private _handleMapCenterChange() {
diff --git a/packages/core/directives/marker.ts b/packages/core/directives/marker.ts
index 5762827c0..b663bda63 100644
--- a/packages/core/directives/marker.ts
+++ b/packages/core/directives/marker.ts
@@ -1,14 +1,11 @@
-import {Directive, EventEmitter, OnChanges, OnDestroy, SimpleChange,
- AfterContentInit, ContentChildren, QueryList, Input, Output
-} from '@angular/core';
-import {Subscription} from 'rxjs';
-
-import {MouseEvent} from '../map-types';
+import { AfterContentInit, ContentChildren, Directive, EventEmitter, Input, OnChanges, OnDestroy, Output, QueryList, SimpleChange, forwardRef } from '@angular/core';
+import { Observable, ReplaySubject, Subscription } from 'rxjs';
+import { tap } from 'rxjs/operators';
+import { MarkerLabel, MouseEvent } from '../map-types';
+import { FitBoundsAccessor, FitBoundsDetails } from '../services/fit-bounds';
import * as mapTypes from '../services/google-maps-types';
-import {MarkerManager} from '../services/managers/marker-manager';
-
-import {AgmInfoWindow} from './info-window';
-import {MarkerLabel} from '../map-types';
+import { MarkerManager } from '../services/managers/marker-manager';
+import { AgmInfoWindow } from './info-window';
let markerId = 0;
@@ -37,13 +34,16 @@ let markerId = 0;
*/
@Directive({
selector: 'agm-marker',
+ providers: [
+ {provide: FitBoundsAccessor, useExisting: forwardRef(() => AgmMarker)}
+ ],
inputs: [
'latitude', 'longitude', 'title', 'label', 'draggable: markerDraggable', 'iconUrl',
'openInfoWindow', 'opacity', 'visible', 'zIndex', 'animation'
],
outputs: ['markerClick', 'dragEnd', 'mouseOver', 'mouseOut']
})
-export class AgmMarker implements OnDestroy, OnChanges, AfterContentInit {
+export class AgmMarker implements OnDestroy, OnChanges, AfterContentInit, FitBoundsAccessor {
/**
* The latitude position of the marker.
*/
@@ -144,6 +144,8 @@ export class AgmMarker implements OnDestroy, OnChanges, AfterContentInit {
private _id: string;
private _observableSubscriptions: Subscription[] = [];
+ protected readonly _fitBoundsDetails$: ReplaySubject = new ReplaySubject(1);
+
constructor(private _markerManager: MarkerManager) { this._id = (markerId++).toString(); }
/* @internal */
@@ -174,12 +176,14 @@ export class AgmMarker implements OnDestroy, OnChanges, AfterContentInit {
}
if (!this._markerAddedToManger) {
this._markerManager.addMarker(this);
+ this._updateFitBoundsDetails();
this._markerAddedToManger = true;
this._addEventListeners();
return;
}
if (changes['latitude'] || changes['longitude']) {
this._markerManager.updateMarkerPosition(this);
+ this._updateFitBoundsDetails();
}
if (changes['title']) {
this._markerManager.updateTitle(this);
@@ -210,6 +214,17 @@ export class AgmMarker implements OnDestroy, OnChanges, AfterContentInit {
}
}
+ /**
+ * @internal
+ */
+ getFitBoundsDetails$(): Observable {
+ return this._fitBoundsDetails$.asObservable();
+ }
+
+ protected _updateFitBoundsDetails() {
+ this._fitBoundsDetails$.next({latLng: {lat: this.latitude, lng: this.longitude}});
+ }
+
private _addEventListeners() {
const cs = this._markerManager.createEventObservable('click', this).subscribe(() => {
if (this.openInfoWindow) {
diff --git a/packages/core/services.ts b/packages/core/services.ts
index 1dfb9206f..cfb35e6af 100644
--- a/packages/core/services.ts
+++ b/packages/core/services.ts
@@ -10,3 +10,4 @@ export {DataLayerManager} from './services/managers/data-layer-manager';
export {GoogleMapsScriptProtocol, LAZY_MAPS_API_CONFIG, LazyMapsAPILoader, LazyMapsAPILoaderConfigLiteral} from './services/maps-api-loader/lazy-maps-api-loader';
export {MapsAPILoader} from './services/maps-api-loader/maps-api-loader';
export {NoOpMapsAPILoader} from './services/maps-api-loader/noop-maps-api-loader';
+export {FitBoundsAccessor, FitBoundsDetails} from './services/fit-bounds';
diff --git a/packages/core/services/fit-bounds.spec.ts b/packages/core/services/fit-bounds.spec.ts
new file mode 100644
index 000000000..a8bbf4852
--- /dev/null
+++ b/packages/core/services/fit-bounds.spec.ts
@@ -0,0 +1,130 @@
+import { TestBed, fakeAsync, tick, discardPeriodicTasks } from '@angular/core/testing';
+import { FitBoundsService } from './fit-bounds';
+import { MapsAPILoader } from './maps-api-loader/maps-api-loader';
+import { LatLngBounds } from '@agm/core';
+import { take, first } from 'rxjs/operators';
+
+describe('FitBoundsService', () => {
+ let loader: MapsAPILoader;
+ let fitBoundsService: FitBoundsService;
+ let latLngBoundsConstructs: number;
+ let latLngBoundsExtend: jest.Mock;
+
+ beforeEach(fakeAsync(() => {
+ loader = {
+ load: jest.fn().mockReturnValue(Promise.resolve())
+ };
+
+ latLngBoundsConstructs = 0;
+ latLngBoundsExtend = jest.fn();
+
+ (window).google = {
+ maps: {
+ LatLngBounds: class LatLngBounds {
+ extend: jest.Mock = latLngBoundsExtend;
+
+ constructor() {
+ latLngBoundsConstructs += 1;
+ }
+ }
+ }
+ };
+
+ TestBed.configureTestingModule({
+ providers: [
+ {provide: MapsAPILoader, useValue: loader},
+ FitBoundsService
+ ]
+ });
+
+ fitBoundsService = TestBed.get(FitBoundsService);
+ tick();
+ }));
+
+ it('should wait for the load event', () => {
+ expect(loader.load).toHaveBeenCalledTimes(1);
+ expect(latLngBoundsConstructs).toEqual(0);
+ });
+
+ it('should emit empty bounds when API finished loaded but the are not entries in the includeInBounds$ map', fakeAsync(() => {
+ const success = jest.fn();
+ fitBoundsService.getBounds$().pipe(first()).subscribe(success);
+ tick();
+ expect(success).toHaveBeenCalledTimes(1);
+ discardPeriodicTasks();
+ }));
+
+ it('should emit the new bounds every 200ms by default', fakeAsync(() => {
+ const success = jest.fn();
+ fitBoundsService.getBounds$().subscribe(success);
+ tick(1);
+ fitBoundsService.addToBounds({lat: 2, lng: 2});
+ fitBoundsService.addToBounds({lat: 2, lng: 2});
+ fitBoundsService.addToBounds({lat: 3, lng: 3});
+ expect(success).toHaveBeenCalledTimes(1);
+ tick(150);
+ expect(success).toHaveBeenCalledTimes(1);
+ tick(200);
+ expect(success).toHaveBeenCalledTimes(2);
+ discardPeriodicTasks();
+ }));
+
+ it('should provide all latLng to the bounds', fakeAsync(() => {
+ const success = jest.fn();
+ fitBoundsService.getBounds$().subscribe(success);
+ tick(1);
+ const latLngs = [
+ {lat: 2, lng: 2},
+ {lat: 3, lng: 3},
+ {lat: 4, lng: 4}
+ ];
+ fitBoundsService.addToBounds(latLngs[0]);
+ fitBoundsService.addToBounds(latLngs[1]);
+ fitBoundsService.addToBounds(latLngs[2]);
+ expect(latLngBoundsExtend).toHaveBeenCalledTimes(0);
+ tick(200);
+ expect(latLngBoundsExtend).toHaveBeenCalledTimes(3);
+ expect(latLngBoundsExtend).toHaveBeenCalledWith(latLngs[0]);
+ expect(latLngBoundsExtend).toHaveBeenCalledWith(latLngs[1]);
+ expect(latLngBoundsExtend).toHaveBeenCalledWith(latLngs[2]);
+ discardPeriodicTasks();
+ }));
+
+ it('should remove latlng from bounds and emit the new bounds after the sample time', fakeAsync(() => {
+ const success = jest.fn();
+ fitBoundsService.getBounds$().subscribe(success);
+ tick(1);
+ fitBoundsService.addToBounds({lat: 2, lng: 2});
+ fitBoundsService.addToBounds({lat: 3, lng: 3});
+ tick(200);
+ latLngBoundsExtend.mockReset();
+
+ fitBoundsService.removeFromBounds({lat: 2, lng: 2});
+ fitBoundsService.removeFromBounds({lat: 3, lng: 3});
+ tick(150);
+ expect(latLngBoundsExtend).toHaveBeenCalledTimes(0);
+ tick(200);
+
+ expect(latLngBoundsExtend).toHaveBeenCalledTimes(0);
+ discardPeriodicTasks();
+ }));
+
+ it('should use the new _boundsChangeSampleTime$ for all next bounds', fakeAsync(() => {
+ const success = jest.fn();
+ fitBoundsService.getBounds$().subscribe(success);
+ tick(1);
+ fitBoundsService.addToBounds({lat: 2, lng: 2});
+ fitBoundsService.addToBounds({lat: 3, lng: 3});
+ tick(200);
+ success.mockReset();
+
+ fitBoundsService.changeFitBoundsChangeSampleTime(100);
+ fitBoundsService.removeFromBounds({lat: 2, lng: 2});
+ fitBoundsService.removeFromBounds({lat: 3, lng: 3});
+ tick(100);
+
+ expect(success).toHaveBeenCalledTimes(1);
+ discardPeriodicTasks();
+ }));
+
+});
diff --git a/packages/core/services/fit-bounds.ts b/packages/core/services/fit-bounds.ts
new file mode 100644
index 000000000..09558acce
--- /dev/null
+++ b/packages/core/services/fit-bounds.ts
@@ -0,0 +1,88 @@
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable, from, timer } from 'rxjs';
+import {
+ flatMap,
+ map,
+ skipWhile,
+ sample,
+ switchMap,
+ shareReplay
+} from 'rxjs/operators';
+import { LatLng, LatLngBounds, LatLngLiteral } from './google-maps-types';
+import { MapsAPILoader } from './maps-api-loader/maps-api-loader';
+
+declare var google: any;
+
+export interface FitBoundsDetails {
+ latLng: LatLng | LatLngLiteral;
+}
+
+/**
+ * @internal
+ */
+export type BoundsMap = Map;
+
+/**
+ * Class to implement when you what to be able to make it work with the auto fit bounds feature
+ * of AGM.
+ */
+export abstract class FitBoundsAccessor {
+ abstract getFitBoundsDetails$(): Observable;
+}
+
+/**
+ * The FitBoundsService is responsible for computing the bounds of the a single map.
+ */
+@Injectable()
+export class FitBoundsService {
+ protected readonly bounds$: Observable;
+ protected readonly _boundsChangeSampleTime$ = new BehaviorSubject(200);
+ protected readonly _includeInBounds$ = new BehaviorSubject(new Map());
+
+ constructor(loader: MapsAPILoader) {
+ this.bounds$ = from(loader.load()).pipe(
+ flatMap(() => this._includeInBounds$),
+ sample(
+ this._boundsChangeSampleTime$.pipe(switchMap(time => timer(0, time)))
+ ),
+ map(includeInBounds => this._generateBounds(includeInBounds)),
+ shareReplay(1)
+ );
+ }
+
+ private _generateBounds(
+ includeInBounds: Map
+ ) {
+ const bounds = new google.maps.LatLngBounds() as LatLngBounds;
+ includeInBounds.forEach(b => bounds.extend(b));
+ return bounds;
+ }
+
+ addToBounds(latLng: LatLng | LatLngLiteral) {
+ const id = this._createIdentifier(latLng);
+ if (this._includeInBounds$.value.has(id)) {
+ return;
+ }
+ const map = this._includeInBounds$.value;
+ map.set(id, latLng);
+ this._includeInBounds$.next(map);
+ }
+
+ removeFromBounds(latLng: LatLng | LatLngLiteral) {
+ const map = this._includeInBounds$.value;
+ map.delete(this._createIdentifier(latLng));
+ this._includeInBounds$.next(map);
+ }
+
+ changeFitBoundsChangeSampleTime(timeMs: number) {
+ this._boundsChangeSampleTime$.next(timeMs);
+ }
+
+ getBounds$(): Observable {
+ return this.bounds$;
+ }
+
+ protected _createIdentifier(latLng: LatLng | LatLngLiteral): string {
+ return `${latLng.lat}+${latLng.lng}`;
+ }
+}
diff --git a/packages/core/services/google-maps-types.ts b/packages/core/services/google-maps-types.ts
index 1012a1db5..67d7b67b0 100644
--- a/packages/core/services/google-maps-types.ts
+++ b/packages/core/services/google-maps-types.ts
@@ -20,6 +20,7 @@ export interface LatLng {
constructor(lat: number, lng: number): void;
lat(): number;
lng(): number;
+ toString(): string;
}
export interface Marker extends MVCObject {
@@ -127,7 +128,7 @@ export interface RectangleOptions {
export interface LatLngBounds {
contains(latLng: LatLng): boolean;
equals(other: LatLngBounds|LatLngBoundsLiteral): boolean;
- extend(point: LatLng): void;
+ extend(point: LatLng|LatLngLiteral): void;
getCenter(): LatLng;
getNorthEast(): LatLng;
getSouthWest(): LatLng;
diff --git a/tslint.json b/tslint.json
index 3d4c0bd22..4e08d2f46 100644
--- a/tslint.json
+++ b/tslint.json
@@ -49,8 +49,7 @@
"typedef": [
true,
"parameter",
- "property-declaration",
- "member-variable-declaration"
+ "property-declaration"
],
"typedef-whitespace": [
true,
@@ -81,7 +80,7 @@
"no-attribute-parameter-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
- "no-forward-ref": true,
+ "no-forward-ref": false,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"pipe-naming": [true, "camelCase", "agm"],