diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..b7af840 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,31 @@ +on: push +name: Build Angular +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [12.x] + + steps: + - uses: actions/checkout@v1 + + - name: Cache node modules + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Node ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Push to GitHub Packages + uses: docker/build-push-action@v1 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: docker.pkg.github.com + repository: openhistorymap/ohm-map/ohm-map + tag_with_ref: true diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2e22645 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "angular.enable-strict-mode-prompt": false +} \ No newline at end of file diff --git a/angular.json b/angular.json index d1310b7..d261e26 100644 --- a/angular.json +++ b/angular.json @@ -127,5 +127,8 @@ } } }, - "defaultProject": "ohm-map" + "defaultProject": "ohm-map", + "cli": { + "analytics": false + } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a61356a..62bcefe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1745,6 +1745,14 @@ "@types/node": "*" } }, + "@types/html2canvas": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/html2canvas/-/html2canvas-1.0.0.tgz", + "integrity": "sha512-BJpVf+FIN9UERmzhbtUgpXj6XBZpG67FMgBLLoj9HZKd9XifcCpSV+UnFcwTZfEyun4U/KmCrrVOG7829L589w==", + "requires": { + "html2canvas": "*" + } + }, "@types/jasmine": { "version": "3.5.14", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.14.tgz", @@ -3756,6 +3764,21 @@ "timsort": "^0.3.0" } }, + "css-line-break": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.0.1.tgz", + "integrity": "sha512-gwKYIMUn7xodIcb346wgUhE2Dt5O1Kmrc16PWi8sL4FTfyDj8P5095rzH7+O8CTZudJr+uw2GCI/hwEkDJFI2w==", + "requires": { + "base64-arraybuffer": "^0.2.0" + }, + "dependencies": { + "base64-arraybuffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", + "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==" + } + } + }, "css-loader": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.5.3.tgz", @@ -5735,6 +5758,15 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html2canvas": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.3.2.tgz", + "integrity": "sha512-4+zqv87/a1LsaCrINV69wVLGG8GBZcYBboz1JPWEgiXcWoD9kroLzccsBRU/L9UlfV2MAZ+3J92U9IQPVMDeSQ==", + "requires": { + "css-line-break": "2.0.1", + "text-segmentation": "^1.0.2" + } + }, "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", @@ -7864,6 +7896,28 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "ngx-capture": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/ngx-capture/-/ngx-capture-0.12.1.tgz", + "integrity": "sha512-rMTIIEV0HQAA95Hlf+THdmXfJdPDfjDX9vB1VAOWxVcmHtnPCukhcSz9ck+7kf5VsmvcQ/7QQFcbttVSAPKAFw==", + "requires": { + "@types/html2canvas": "1.0.0", + "html2canvas": "1.3.2", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + } + } + }, + "ngx-matomo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/ngx-matomo/-/ngx-matomo-0.1.4.tgz", + "integrity": "sha512-AKZMnJGyytZqAxuSh+k/AulyQhgqlnnsmtkfvHMJyNuh5g+wVpIbwac36RyeFU3El6INgZVso2CCLElV3bQnBQ==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -12170,6 +12224,14 @@ } } }, + "text-segmentation": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.2.tgz", + "integrity": "sha512-uTqvLxdBrVnx/CFQOtnf8tfzSXFm+1Qxau7Xi54j4OPTZokuDOX8qncQzrg2G8ZicAMOM8TgzFAYTb+AqNO4Cw==", + "requires": { + "utrie": "^1.0.1" + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -12719,6 +12781,21 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, + "utrie": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.1.tgz", + "integrity": "sha512-JPaDXF3vzgZxfeEwutdGzlrNoVFL5UvZcbO6Qo9D4GoahrieUPoMU8GCpVpR7MQqcKhmShIh8VlbEN3PLM3EBg==", + "requires": { + "base64-arraybuffer": "^1.0.1" + }, + "dependencies": { + "base64-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz", + "integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==" + } + } + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", diff --git a/package.json b/package.json index eed9c5a..bab1b09 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "@modalnodes/mn-configurator": "0.0.4", "@modalnodes/mn-docker": "0.0.3", "@modalnodes/mn-registry": "0.0.3", + "ngx-capture": "^0.12.1", + "ngx-matomo": "^0.1.4", "ol": "^6.4.3", "rxjs": "~6.5.5", "tslib": "^2.0.0", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5e37108..7fb47fa 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { MnDockerService } from '@modalnodes/mn-docker'; import { HttpClient } from '@angular/common/http'; +import { MatomoInjector } from 'ngx-matomo'; import env from '../assets/env.json'; @@ -15,8 +16,10 @@ declare const mapboxgl; export class AppComponent implements OnInit { constructor( + private matomoInjector: MatomoInjector ) {} ngOnInit() { + this.matomoInjector.init('//tracker.openhistorymap.org/', 2); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 237e764..6809d97 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,6 +4,7 @@ import { MnConfiguratorModule } from '@modalnodes/mn-configurator'; import { MnDockerModule } from '@modalnodes/mn-docker'; import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import { MatomoModule } from 'ngx-matomo'; import { AppComponent } from './app.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -12,6 +13,8 @@ import { StyleSelectorComponent } from './style-selector/style-selector.componen import { DecimaldatePipe } from './decimaldate.pipe'; import { NicedatePipe } from './nicedate.pipe'; import { DateComponent } from './date/date.component'; +import {ClipboardModule} from '@angular/cdk/clipboard'; +import { ShareDirective } from './share.directive'; @NgModule({ declarations: [ @@ -20,15 +23,18 @@ import { DateComponent } from './date/date.component'; StyleSelectorComponent, DecimaldatePipe, NicedatePipe, - DateComponent + DateComponent, + ShareDirective ], imports: [ BrowserModule, BrowserAnimationsModule, AppRoutingModule, + ClipboardModule, MnDockerModule, MnConfiguratorModule, SharedModule, + MatomoModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/decimaldate.pipe.ts b/src/app/decimaldate.pipe.ts index a9df7a7..b51874c 100644 --- a/src/app/decimaldate.pipe.ts +++ b/src/app/decimaldate.pipe.ts @@ -58,5 +58,4 @@ export class DecimaldatePipe implements PipeTransform { ret.setMilliseconds(rest); return ret; } - } diff --git a/src/app/map/map.component.html b/src/app/map/map.component.html index 2c3a88c..c9d1363 100644 --- a/src/app/map/map.component.html +++ b/src/app/map/map.component.html @@ -1,5 +1,5 @@ - +

OpenHistoryMap

@@ -8,15 +8,18 @@

OpenHistoryMap

- - - + + + - + + + +
@@ -26,12 +29,22 @@

OpenHistoryMap

- About - How to join - How to help - Donate + OHM Home + OHM Blog + OHM Index + About OHM + How to help/donate to OHM + + +

What is here

+
+ + + {{event.properties.name}} + +

Events

@@ -41,11 +54,35 @@

Events

{{event.properties.name}}
- + + +

Ephemeral

+
+ + + {{event.properties.name}} + +
+ + +

Sharing

+ + +
+ + + facebook Share on Facebook + twitter Share on Twitter + Share on Linkedin + class Share on Classroom + + +
+ - - + +
diff --git a/src/app/map/map.component.scss b/src/app/map/map.component.scss index 1781cb1..421ba8d 100644 --- a/src/app/map/map.component.scss +++ b/src/app/map/map.component.scss @@ -17,8 +17,15 @@ width: 256px; background-color: #3f51b5; color: white; + a{ + color:white; + } } .info{ padding: 16px; + color:white; + a, a:hover, a:visited{ + color:white; + } } \ No newline at end of file diff --git a/src/app/map/map.component.ts b/src/app/map/map.component.ts index 7a1da78..e80f9ce 100644 --- a/src/app/map/map.component.ts +++ b/src/app/map/map.component.ts @@ -1,18 +1,20 @@ import { OhmService } from './../ohm.service'; import { DateComponent } from './../date/date.component'; import { DecimaldatePipe } from './../decimaldate.pipe'; -import { Component, OnInit, Input, isDevMode } from '@angular/core'; +import { Component, OnInit, Input, isDevMode, ViewChild } from '@angular/core'; import { MnDockerService } from '@modalnodes/mn-docker'; import { HttpClient } from '@angular/common/http'; -import env from '../../assets/env.json'; import { ActivatedRoute } from '@angular/router'; import { Location } from '@angular/common'; -import { NicedatePipe } from '../nicedate.pipe'; -import { timeInterval } from 'rxjs/operators'; import { MatDialog } from '@angular/material/dialog'; import { Observable } from 'rxjs'; +import { MatomoTracker } from 'ngx-matomo'; +import { MatSidenav } from '@angular/material/sidenav'; +import { Clipboard } from '@angular/cdk/clipboard'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { NgxCaptureService } from 'ngx-capture'; declare const mapboxgl; declare const vis; @@ -56,14 +58,24 @@ export class MapComponent implements OnInit { infoData: any; + @ViewChild('ibar') ibar: MatSidenav; + @ViewChild('sharebar') sharebar: MatSidenav; + @ViewChild('screen') screen: any; + share_link: string; + + selectedFeatures = []; constructor( private ds: MnDockerService, private ar: ActivatedRoute, private l: Location, private md: MatDialog, private ohm: OhmService, - private http: HttpClient + private http: HttpClient, + private matomoTracker: MatomoTracker, + private _snackBar: MatSnackBar, + private clipboard: Clipboard, + private capture: NgxCaptureService ) { } ngOnInit(): void { @@ -92,6 +104,7 @@ export class MapComponent implements OnInit { style: this.style, // stylesheet location center: this.start.center, // starting position [lng, lat] zoom: this.start.zoom, // starting zoom + preserveDrawingBuffer: true, transformRequest: (url, resourceType) => { let nurl = url; if (isDevMode()) { @@ -121,6 +134,29 @@ export class MapComponent implements OnInit { this.map.on('moveend', () => { this.changeUrl(); }); + this.map.on('mouseenter', () => { + this.map.getCanvas().style.cursor = 'pointer'; + }); + + // Change it back to a pointer when it leaves. + this.map.on('mouseleave', () => { + this.map.getCanvas().style.cursor = ''; + }); + this.map.on('click', (e) => { + console.log(e.lngLat); + this.ohm.drilldown(e.lngLat).subscribe(feats=>{ + //this.ibar.open(); + if(feats.length > 0) { + this.selectedFeatures = feats; + console.log(feats[0].properties); + new mapboxgl.Popup() + .setLngLat(e.lngLat) + .addTo(this.map); + } + + }) + }); + const container = document.getElementById('visualization'); @@ -148,9 +184,23 @@ export class MapComponent implements OnInit { }); } + copy_url(){ + this.capture.getImage(this.screen.elementRef.nativeElement, true).subscribe(img=>{ + this.ohm.su(window.location.href, img).subscribe(data =>{ + this.clipboard.copy(data); + this.share_link = data; + this.sharebar.open(); + this._snackBar.open('Address ready to share','Close', { + duration: 1000 + }); + }); + }) + } + changeUrl(ev = null): void{ const c = this.map.getCenter(); this.l.go(`/${this.atDate}/${this.map.getZoom()}/${c.lat}/${c.lng}` + (this.rels ? '/' + this.rels : '')); + this.matomoTracker.trackPageView(`/${this.atDate}/${this.map.getZoom()}/${c.lat}/${c.lng}` + (this.rels ? '/' + this.rels : '')); if (ev) { this.map.getSource('ohm').setSourceProperty(() => { }); this.map.getSource('ohm-boundaries')?.setSourceProperty(() => { }); @@ -162,7 +212,9 @@ export class MapComponent implements OnInit { changeStyle(style): void { this.style = style; - this.map.setStyle(style); + try{ + this.map.setStyle(style); + } catch(ex) { } } toDateFloat(date: Date): number{ @@ -189,7 +241,7 @@ export class MapComponent implements OnInit { this.atDate = parseFloat(this.atDate.toString()) + delta; this.timeline.setCustomTime(this.toFloatDate(this.atDate), 'atTime'); this.changeUrl(this.atDate); - }, this.speed); + }, 4000); } else { clearInterval(this.startstopInterval); } diff --git a/src/app/ohm.service.ts b/src/app/ohm.service.ts index f99a177..390a8b5 100644 --- a/src/app/ohm.service.ts +++ b/src/app/ohm.service.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -11,7 +11,28 @@ export class OhmService { private http: HttpClient ) { } - getEvents(date, amount = 20): Observable { - return this.http.get('http://51.15.160.236:9034/events/' + date + '?limit=' + amount); + getEvents(date, bbox=null, amount = 20, from=null, to=null): Observable { + if(bbox){ + return this.http.get('https://api.events.openhistorymap.org/events/timeline.json?bbox='+bbox.join(',')+'&date=' + date + '&limit=' + amount+'&from='+from+'&to='+to); + } else { + return of([]); + } + } + + getStats(date, bbox=null, amount = 20, from=null, to=null): Observable { + if(bbox){ + return this.http.get('https://api.stats.openhistorymap.org/stats.json?bbox='+bbox.join(',')+'&date=' + date + '&limit=' + amount+'&from='+from+'&to='+to); + } else { + return of([]); + } + } + + drilldown(lnglat, radius=100, time='now'): Observable{ + console.log('getting the elements around the selected point') + return of([]); + } + + su(url: string, image:string = null): Observable{ + return this.http.post('https://su.openhistorymap.org/?url='+url, image); } } diff --git a/src/app/share.directive.spec.ts b/src/app/share.directive.spec.ts new file mode 100644 index 0000000..1c1e580 --- /dev/null +++ b/src/app/share.directive.spec.ts @@ -0,0 +1,8 @@ +import { ShareDirective } from './share.directive'; + +describe('ShareDirective', () => { + it('should create an instance', () => { + const directive = new ShareDirective(); + expect(directive).toBeTruthy(); + }); +}); diff --git a/src/app/share.directive.ts b/src/app/share.directive.ts new file mode 100644 index 0000000..9c71c55 --- /dev/null +++ b/src/app/share.directive.ts @@ -0,0 +1,18 @@ +import { Directive, Input } from '@angular/core'; + +@Directive({ + selector: '[share]', + host: { + "(click)": "onClick($event)" + } +}) +export class ShareDirective { + + @Input('share') url = '' + constructor() { } + + onClick(e){ + window.open(this.url, 'share', "width=400,height=300,toolbar=no,status=no,menubar=no"); + } + +} diff --git a/src/assets/info.json b/src/assets/info.json index c3e5f08..e8bc6d1 100644 --- a/src/assets/info.json +++ b/src/assets/info.json @@ -1,3 +1,3 @@ { - "info": "OpenHistoryMap si propone di accorciare questo divario seppur in maniera minima, dando la possibilità a chiunque di consultare ed avere esperienza dei dati archeologici pubblicati." + "info": "OpenHistoryMap is an italian non profit association (APS) founded by a team of archaeologists and software developers based in Bologna, Italy. The aim is the creation of a web-GIS platform containing spatial historical and archaeological data.

OHM is an open source project using open source tools. The code is available on github

Technology and academia are the main sources of data, as you can see in our OHM Data Index, but end users can contribute as well, by sharing their datasets and by exploring the map and the data." } \ No newline at end of file diff --git a/src/index.html b/src/index.html index 6e2a1c2..d290981 100644 --- a/src/index.html +++ b/src/index.html @@ -15,7 +15,22 @@ - + + + +