Skip to content

Commit

Permalink
feat: geolocation (#79)
Browse files Browse the repository at this point in the history
Co-authored-by: splincode <>
  • Loading branch information
splincode authored May 4, 2023
1 parent a7abad6 commit 1f906a8
Show file tree
Hide file tree
Showing 86 changed files with 2,624 additions and 1,517 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
project: [common, resize-observer, universal, audio]
project: [common, resize-observer, universal, audio, canvas, geolocation]
name: ${{ matrix.project }}
steps:
- uses: actions/checkout@v3.5.2
Expand Down Expand Up @@ -55,6 +55,16 @@ jobs:
directory: ./coverage/audio/
flags: summary,audio
name: audio
- uses: codecov/codecov-action@v3.1.3
with:
directory: ./coverage/canvas/
flags: summary,canvas
name: canvas
- uses: codecov/codecov-action@v3.1.3
with:
directory: ./coverage/geolocation/
flags: summary,geolocation
name: geolocation
- uses: codecov/codecov-action@v3.1.3
with:
directory: ./coverage/resize-observer/
Expand Down
13 changes: 13 additions & 0 deletions apps/demo/src/app/app.browser.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,29 @@ import {BrowserModule} from '@angular/platform-browser';
import {AppComponent} from './app.component';
import {AppRoutingModule} from './app.routes';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HighlightModule, HIGHLIGHT_OPTIONS} from 'ngx-highlightjs';
import {LocationStrategy, PathLocationStrategy} from '@angular/common';

@NgModule({
imports: [
AppRoutingModule,
HighlightModule,
BrowserAnimationsModule,
BrowserModule.withServerTransition({
appId: 'demo',
}),
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [
{
provide: HIGHLIGHT_OPTIONS,
useValue: {fullLibraryLoader: () => import('highlight.js')},
},
{
provide: LocationStrategy,
useClass: PathLocationStrategy,
},
],
})
export class AppBrowserModule {}
6 changes: 6 additions & 0 deletions apps/demo/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export const appRoutes: Routes = [
(await import(`../pages/resize-observer/resize-observer-page.module`))
.ResizeObserverPageModule,
},
{
path: DemoPath.GeolocationPage,
loadChildren: async () =>
(await import(`../pages/geolocation/geolocation-page.module`))
.GeolocationPageModule,
},
{
path: '',
redirectTo: DemoPath.HomePage,
Expand Down
1 change: 1 addition & 0 deletions apps/demo/src/app/constants/demo-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export enum DemoPath {
AudioPage = `audio`,
ResizeObserverPage = `resize-observer`,
CanvasPage = `canvas`,
GeolocationPage = `geolocation`,
}
91 changes: 91 additions & 0 deletions apps/demo/src/pages/geolocation/geolocation-page.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<div class="wrapper">
<section>
<p>
<strong>Angular</strong>
does not have any built-in instruments to use
<strong>Geolocation API</strong>
. This is an
<code>Observable</code>
based abstraction over
<strong>Geolocation API</strong>
to use with
<strong>Angular</strong>
</p>
</section>

<div *ngIf="!!error">
Sorry, position is not available: {{ error.message }}
</div>

<section>
<h2>How to use</h2>
<p>
Usage is pretty simple: just import service in your component and
subscribe to it. Service extends
<code>Observable</code>
and will emit the
<code>Position</code>
object.
</p>

<pre><code [highlight]="sample">
{{sample}}
</code></pre>

<p>You also can use async pipe</p>

<pre><code [highlight]="sampleAsync">
{{sampleAsync}}
</code></pre>

<div class="watch-position">
<div class="switch-container">
<label for="switcher" class="switch-container__text">
Track my position
</label>
<label class="switch">
<input
id="switcher"
type="checkbox"
(click)="toggleWatch()"
/>
<span class="slider round"></span>
</label>
</div>
<div *ngIf="!!toggle">
<div *ngIf="geolocation$ | async as geolocation">
<map
*ngIf="geolocation.coords"
[coordinatesChange]="geolocation.coords"
></map>
</div>
</div>
</div>

<h2>Single position</h2>
<div class="current-position">
<p>
If you need to get position just once and stop observing user
location, you can subscribe to geolocation$ and use
<code>take(1)</code>
RxJs operator. Service is cold, meaning if there are no
Subscribers, it doesn't track position
</p>

<button class="primary-button" (click)="getCurrentPosition()">
Get my position!
</button>

<iframe
*ngIf="!!currentPositionUrl"
width="425"
height="350"
frameborder="0"
scrolling="no"
marginheight="0"
marginwidth="0"
[src]="currentPositionUrl"
></iframe>
</div>
</section>
</div>
58 changes: 58 additions & 0 deletions apps/demo/src/pages/geolocation/geolocation-page.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from '@angular/core';
import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
import {Subscription, take} from 'rxjs';
import {GeolocationService} from '@ng-web-apis/geolocation';
import {SAMPLE} from './samples/sample';
import {SAMPLE_ASYNC} from './samples/sample-async';

@Component({
selector: `geolocation-page`,
templateUrl: `./geolocation-page.component.html`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GeolocationPageComponent {
position: GeolocationPosition | null = null;
toggle = false;
currentPositionUrl: SafeResourceUrl | null = null;
watchSubscription: Subscription | null = null;
error: GeolocationPositionError | null = null;

readonly sample = SAMPLE;
readonly sampleAsync = SAMPLE_ASYNC;

constructor(
readonly geolocation$: GeolocationService,
private readonly domSanitizer: DomSanitizer,
private readonly changeDetectorRef: ChangeDetectorRef,
) {}

getCurrentPosition() {
this.geolocation$.pipe(take(1)).subscribe(
position => {
this.currentPositionUrl = this.getUrl(position);
this.changeDetectorRef.markForCheck();
},
error => {
this.error = error;
this.changeDetectorRef.markForCheck();
},
);
}

toggleWatch() {
this.toggle = !this.toggle;
}

private getUrl(position: GeolocationPosition): SafeResourceUrl {
const longitude = position.coords.longitude;
const latitude = position.coords.latitude;

return this.domSanitizer.bypassSecurityTrustResourceUrl(
`//www.openstreetmap.org/export/embed.html?bbox=${longitude - 0.005},${
latitude - 0.005
},${longitude + 0.005},${latitude + 0.005}&marker=${
position.coords.latitude
},${position.coords.longitude}&layer=mapnik`,
);
}
}
23 changes: 23 additions & 0 deletions apps/demo/src/pages/geolocation/geolocation-page.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {NgModule} from '@angular/core';
import {GeolocationPageComponent} from './geolocation-page.component';
import {RouterModule} from '@angular/router';
import {CommonModule} from '@angular/common';
import {MapComponent} from './map/map.component';
import {POSITION_OPTIONS} from '@ng-web-apis/geolocation';
import {HighlightModule} from 'ngx-highlightjs';

@NgModule({
imports: [
CommonModule,
HighlightModule,
RouterModule.forChild([{path: '', component: GeolocationPageComponent}]),
],
declarations: [GeolocationPageComponent, MapComponent],
providers: [
{
provide: POSITION_OPTIONS,
useValue: {enableHighAccuracy: true, timeout: 3000, maximumAge: 1000},
},
],
})
export class GeolocationPageModule {}
28 changes: 28 additions & 0 deletions apps/demo/src/pages/geolocation/map/map.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div class="map">
<div class="marker" [style.transform]="markerTransform$ | async">
<svg
id="Layer_1"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 365 560"
enable-background="new 0 0 365 560"
xml:space="preserve"
>
<g>
<path
fill="#00AEEF"
d="M182.9,551.7c0,0.1,0.2,0.3,0.2,0.3S358.3,283,358.3,194.6c0-130.1-88.8-186.7-175.4-186.9
C96.3,7.9,7.5,64.5,7.5,194.6c0,88.4,175.3,357.4,175.3,357.4S182.9,551.7,182.9,551.7z M122.2,187.2c0-33.6,27.2-60.8,60.8-60.8
c33.6,0,60.8,27.2,60.8,60.8S216.5,248,182.9,248C149.4,248,122.2,220.8,122.2,187.2z"
/>
</g>
</svg>
</div>
<div *ngIf="currentCoords" class="coords">
<div>long: {{ currentCoords.longitude }}</div>
<div>lat: {{ currentCoords.latitude }}</div>
</div>
</div>
21 changes: 21 additions & 0 deletions apps/demo/src/pages/geolocation/map/map.component.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.map {
min-width: 300px;
height: 300px;
overflow: hidden;
background-color: rgba(236, 234, 234, 0.438);
border: 1px solid rgb(124, 124, 124);
}

.marker {
position: relative;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
}

.coords {
position: absolute;
font-family: monospace;
width: max-content;
}
41 changes: 41 additions & 0 deletions apps/demo/src/pages/geolocation/map/map.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {DomSanitizer, SafeStyle} from '@angular/platform-browser';
import {BehaviorSubject} from 'rxjs';

@Component({
selector: 'map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MapComponent {
@Input()
set coordinatesChange(coords: GeolocationCoordinates) {
this.coordsToStyle(coords);
this.currentCoords = coords;
}

currentCoords: GeolocationCoordinates | null = null;

initialCoords: GeolocationCoordinates | null = null;

markerTransform$ = new BehaviorSubject<SafeStyle>('translate(0px,0px)');

constructor(private readonly domSanitizer: DomSanitizer) {}

private coordsToStyle(coordinates: GeolocationCoordinates) {
if (!this.initialCoords) {
this.initialCoords = coordinates;

return;
}

const deltaX = (this.initialCoords.longitude - coordinates.longitude) * 10000;
const deltaY = (this.initialCoords.latitude - coordinates.latitude) * 10000;
const style = `translate(${deltaX}px,${deltaY}px)`;

const safeStyle = this.domSanitizer.bypassSecurityTrustStyle(style);

this.markerTransform$.next(safeStyle);
}
}
1 change: 1 addition & 0 deletions apps/demo/src/pages/geolocation/samples/sample-async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SAMPLE_ASYNC = `<app-component-using-position [position]="geolocation$ | async"></app-component-using-position>`;
11 changes: 11 additions & 0 deletions apps/demo/src/pages/geolocation/samples/sample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const SAMPLE = `import {GeolocationService} from '@ng-web-apis/geolocation';
// ...
constructor(private readonly geolocation$: GeolocationService) {}
getPosition() {
geolocation$.subscribe((position) => {
doSomethingWithPosition(position);
});
}`;
3 changes: 1 addition & 2 deletions apps/demo/src/pages/home/home-page.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ <h2>Canvas</h2>
/>
</a>
<a
href="https://github.com/ng-web-apis/geolocation"
target="_blank"
class="link"
[routerLink]="['/', link.GeolocationPage]"
[class.not-supported]="!geolocationSupport"
>
<div>
Expand Down
2 changes: 2 additions & 0 deletions apps/demo/src/styles.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import '~highlight.js/styles/github.css';

body,
html {
margin: 0;
Expand Down
2 changes: 2 additions & 0 deletions apps/demo/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"outDir": "./out-tsc/app",
"types": []
},
"include": ["**/*.d.ts"],
"angularCompilerOptions": {
"strictMetadataEmit": false,
"compilationMode": "full"
}
}
2 changes: 1 addition & 1 deletion libs/audio/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = function (config) {
served: true,
},
{
pattern: './test.js',
pattern: './src/test.js',
watched: false,
included: false,
nocache: false,
Expand Down
Loading

0 comments on commit 1f906a8

Please sign in to comment.