Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
474 changes: 468 additions & 6 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"bootstrap": "^5.2.3",
"font-awesome": "^4.7.0",
"fontawesome": "^5.6.3",
"ol": "^7.3.0",
"osm": "^1.0.0",
"rxjs": "^7.8.1",
"splitwise-js-map": "git+ssh://git@github.com/lezhumain/node-splitwise-js.git",
"tslib": "^2.5.0",
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {HttpClientModule} from "@angular/common/http";
import { TestEndpointComponent } from './test-endpoint/test-endpoint.component';
import { ToastComponent } from './toast/toast.component';
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import { OspMapComponent } from './osp-map/osp-map.component';
import {AutocompleteLibModule} from "angular-ng-autocomplete";
import { BalanceComponent } from './balance/balance.component';
import { BalanceItemComponent } from './balance-item/balance-item.component';
Expand Down Expand Up @@ -54,6 +55,7 @@ import {JoinComponent} from "./join/join.component";
UserEditComponent,
TestEndpointComponent,
ToastComponent,
OspMapComponent,
BalanceComponent,
BalanceItemComponent,
ExpenseFilterComponent,
Expand Down
52 changes: 27 additions & 25 deletions src/app/login/login.component.html
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
<h3>Login</h3>
<div>
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username"
[(ngModel)]="username" >
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password"
[(ngModel)]="password" >
</div>
<br>
<br>
<br>
<div class="col-auto">
<button type="button" class="btn btn-primary mb-3" (click)="doLogin()">
Login
<ng-container *ngIf="loggingIn">
<i id="logging_in" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
</ng-container>
</button>
<button id="regBtn" type="button" class="btn btn-success mb-3" (click)="goRegister()">Register</button>
</div>
</div>
<app-osp-map></app-osp-map>

<!--<h3>Login</h3>-->
<!--<div>-->
<!-- <div class="mb-3">-->
<!-- <label for="username" class="form-label">Username</label>-->
<!-- <input type="text" class="form-control" id="username"-->
<!-- [(ngModel)]="username" >-->
<!-- </div>-->
<!-- <div class="mb-3">-->
<!-- <label for="password" class="form-label">Password</label>-->
<!-- <input type="password" class="form-control" id="password"-->
<!-- [(ngModel)]="password" >-->
<!-- </div>-->
<!-- <br>-->
<!-- <br>-->
<!-- <br>-->
<!-- <div class="col-auto">-->
<!-- <button type="button" class="btn btn-primary mb-3" (click)="doLogin()">-->
<!-- Login-->
<!-- <ng-container *ngIf="loggingIn">-->
<!-- <i id="logging_in" class="fa fa-spinner fa-spin" aria-hidden="true"></i>-->
<!-- </ng-container>-->
<!-- </button>-->
<!-- <button id="regBtn" type="button" class="btn btn-success mb-3" (click)="goRegister()">Register</button>-->
<!-- </div>-->
<!--</div>-->
1 change: 1 addition & 0 deletions src/app/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {ActivatedRoute, Router} from "@angular/router";
import {catchError, first, take} from "rxjs/operators";
import {UserModel} from "../models/user-model";
import {ToastComponent} from "../toast/toast.component";

import {ToastMessage, ToastType} from "../toast/toast.shared";
import {TravelService} from "../travel.service";
import {ExpenseService} from "../expense.service";
Expand Down
16 changes: 16 additions & 0 deletions src/app/osp-map/osp-map.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*@import "navigation.css"; !* Using a string *!*/
@import url("https://openlayers.org/en/v6.1.1/css/ol.css"); /* Using a url */

.map {
width: 100%;
height: 100vh;
}

#popup {
display: block;
width: 300px;
height: 400px;
background-color: aliceblue;
border: thin solid black;
overflow: scroll;
}
6 changes: 6 additions & 0 deletions src/app/osp-map/osp-map.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>osp-map works!</p>
<div id="map" class="map"></div>
<div id="popup" class="ol-popup">
<a href="#" id="popup-closer" class="ol-popup-closer"></a>
<div id="popup-content"></div>
</div>
23 changes: 23 additions & 0 deletions src/app/osp-map/osp-map.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { OspMapComponent } from './osp-map.component';

describe('OspMapComponent', () => {
let component: OspMapComponent;
let fixture: ComponentFixture<OspMapComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ OspMapComponent ]
})
.compileComponents();

fixture = TestBed.createComponent(OspMapComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
229 changes: 229 additions & 0 deletions src/app/osp-map/osp-map.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import {AfterViewInit, Component, OnInit, ViewEncapsulation} from '@angular/core';
import { defaults as defaultControls } from 'ol/control';

import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import ZoomToExtent from 'ol/control/ZoomToExtent';

import * as VectorLaya from "ol/layer/Vector";
import Vector from "ol/source/Vector";

import Style from "ol/style/Style";
import Icon from "ol/style/Icon";
import Circle from "ol/style/Circle";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import {fromLonLat, toLonLat, transform} from "ol/proj";
import {Geometry} from "ol/geom";
import {Fill, Stroke} from "ol/style";

import {IIpInfo, IpInfoService} from "../ip-info.service";
import {MapBrowserEvent, Overlay} from "ol";

@Component({
selector: 'app-osp-map',
templateUrl: './osp-map.component.html',
// styleUrls: ["ol/ol.css", './osp-map.component.css']
styleUrls: ['./osp-map.component.css']
})
export class OspMapComponent implements OnInit, AfterViewInit {
// @ts-ignore
map: Map;

private _vectorSource: Vector<any> | undefined = undefined;
private _data: IIpInfo[] = [];
private overlay: Overlay | undefined = undefined;

constructor(private readonly _ipInfoService: IpInfoService) {}

ngAfterViewInit() {
this.map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new XYZ({
url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'
})
})
],
view: new View({
// center: [813079.7791264898, 5929220.284081122],
center: fromLonLat([111.9006, -8.0647]),
zoom: 5
}),
controls: defaultControls().extend([
new ZoomToExtent({
extent: [
813079.7791264898, 5929220.284081122,
848966.9639063801, 5936863.986909639
]
})
])
});

this.overlay = new Overlay({
element: document.querySelector("#popup") as HTMLDivElement,
autoPan: true,
// autoPanAnimation: {
// duration: 250
// }
});
this.map.addOverlay(this.overlay);

this.map.on('singleclick', (event: MapBrowserEvent<any>) => {
console.log("clicked");
if(!this.overlay) {
return;
}
const overlay = this.overlay;

if (this.map.hasFeatureAtPixel(event.pixel) === true) {
const coordinate = event.coordinate;
overlay.setPosition(coordinate);
this.markerClicked(event);
} else {
overlay.setPosition(undefined);
(document.querySelector("#popup-closer") as HTMLDivElement).blur();
}
});

this._ipInfoService.getIpData().subscribe((data: IIpInfo[]) => {
this._data = data;
this.addMarkers();
})

}

ngOnInit(): void {
}

private addMarker(heatPerc: number, lon: number, lat: number) {
const markerGeometry: Point = new Point(transform(fromLonLat([lon, lat]), 'EPSG:4326', 'EPSG:4326'));
const markerFeature: Feature<Geometry> = new Feature({
geometry: markerGeometry
});

const markerStyle: Icon = new Icon(({
src: 'https://raw.githubusercontent.com/openlayers/openlayers/v3.20.1/examples/resources/logo-70x70.png'
// src: 'https://github.com/openlayers/openlayers/blob/v3.20.1/examples/resources/logo-70x70.png'
// logo-70x70.png
}));

const img = new Circle({
radius: 6,
stroke: new Stroke({
color: '#fff'
}),
fill: new Fill({
color: OspMapComponent.getColor(heatPerc)
})
});

markerFeature.setStyle(new Style({
// image: markerStyle,
image: img
}));

if (this._vectorSource === undefined) {
const vectorSource: Vector<any> = new Vector<any>({
features: [markerFeature]
});
this._vectorSource = vectorSource;

const markerLayer = new VectorLaya.default({
visible: true,
source: this._vectorSource
});

this.map.addLayer(markerLayer);
}
else {
this._vectorSource.addFeature(markerFeature);
}
}

private addMarker0() {
const markerFeature: Feature = new Feature({
geometry: new Point(fromLonLat([111.9006, -8.0647]))
});

const markerLayer = new VectorLaya.default({
source: new Vector({
features: [
markerFeature
]
})
});

this.map.addLayer(markerLayer);
}

private static getColor(heatPerc: number) {
const r = "FF", b = "00";

// 100% -> 0 = 204 - 204
// 0% -> 204 ("CC") = 204 - 0
// X% -> 204 - (204 * heatPerc)
const gNumber = 255 - Math.round(255 * heatPerc);
const g = gNumber === 0 ? "00" : gNumber.toString(16);

const color = `#${r}${g}${b}`.toUpperCase();
// console.log("Color for %s: %s", heatPerc, color);
return color;
}

private addMarkers() {
let max = 0;
const grouped = this._data.reduce((res: {[theKey: string]: any[]}, item: IIpInfo, index: number, allItems: IIpInfo[]) => {
const lon = item.lon;
const lat = item.lat;
const key: string = `${lon}_${lat}`;
if (!res[key]) {
// const all = allItems.filter(a => a.query === ip);
const all = allItems.filter(a => a.lon === lon && a.lat === lat);

if(all.length > max) {
max = all.length;
}

res[key] = all.slice()
}
return res;
}, {});
console.log(grouped);

// const keys = Object.keys(grouped);
for(const key in grouped) {
const arr: IIpInfo[] = grouped[key];
const tot = arr.length;
const perc = tot / max;
this.addMarker(perc, arr[0].lon, arr[0].lat);
}
}

private markerClicked(event: MapBrowserEvent<any>) {
console.log("coord: %o", event.coordinate);

const [lon, lat] = toLonLat(event.coordinate);
console.log("lonlat: %o", [lon, lat]);

const ordered = this._data.map((m: IIpInfo) => {
const newO = Object.assign({}, m);
newO.diff = Math.abs(m.lon - lon);

return newO;
});
ordered.sort((a: IIpInfo, b: IIpInfo) => (a.diff || 0) - (b.diff || 0));
console.log(ordered.join("\n"));

const closest = ordered[0];

const items = this._data.filter(d => d.lon === closest.lon && d.lat === closest.lat);

(document.querySelector("#popup-content") as HTMLDivElement).innerHTML
= `<pre>${JSON.stringify(items, null, 2)}</pre><a href="https://www.google.com/maps/place/@${closest.lat},${closest.lon},18z">See on Google Maps</a>`;
console.log("new content");
}
}
2 changes: 1 addition & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<base href="/">

<!-- <meta name="viewport" content="width=device-width, initial-scale=1"> -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://openlayers.org; media-src *; img-src 'self' data: content: https://*.tile.openstreetmap.org https://raw.githubusercontent.com;">
<meta name="format-detection" content="telephone=no" >
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover" >
Expand Down