| @@ -8,9 +8,11 @@ | |||||
| <canvas id="result-canvas" #canvasElement width="{{ width }}" height="{{ height }}"></canvas> | <canvas id="result-canvas" #canvasElement width="{{ width }}" height="{{ height }}"></canvas> | ||||
| </div> | </div> | ||||
| <img [src]="temp" *ngIf="temp" #temp class="test-img" width="100px" height="100px" alt=""> | |||||
| <section class="temp-image" [ngClass]="{'active' : tempImg }"> | |||||
| <img *ngIf="tempImg" src="{{ tempImg }}"> | |||||
| </section> | |||||
| <div class="action-buttons"> | |||||
| <div class="action-buttons" *ngIf="!tempImg"> | |||||
| <!-- <button *ngIf="areNeuralNetsLoaded" (click)="stopCameraStream()">Stop stream</button> --> | <!-- <button *ngIf="areNeuralNetsLoaded" (click)="stopCameraStream()">Stop stream</button> --> | ||||
| <!-- <button *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()">{{ isDetecting ? 'Stop detection' : 'Detect and draw' }}</button> --> | <!-- <button *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()">{{ isDetecting ? 'Stop detection' : 'Detect and draw' }}</button> --> | ||||
| @@ -19,4 +21,11 @@ | |||||
| <button class="skin-button" *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()" | <button class="skin-button" *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()" | ||||
| [ngClass]="{'active' : isDetecting }"> <ion-icon name="glasses"></ion-icon> </button> | [ngClass]="{'active' : isDetecting }"> <ion-icon name="glasses"></ion-icon> </button> | ||||
| </div> | </div> | ||||
| <section class="image-action-buttons" *ngIf="tempImg"> | |||||
| <button (click)="approveImage()"> <img src="assets/icons/emojis/thumb-up.png"> </button> | |||||
| <button (click)="tempImg = null"> <img src="assets/icons/emojis/thumb-up.png"> </button> | |||||
| <button> <ion-icon name="share-social-outline"></ion-icon> </button> | |||||
| </section> | |||||
| </ion-content> | </ion-content> | ||||
| @@ -1,10 +1,24 @@ | |||||
| @import '../colors'; | @import '../colors'; | ||||
| .test-img { | |||||
| .temp-image { | |||||
| position: fixed; | position: fixed; | ||||
| z-index: 1; | z-index: 1; | ||||
| left: 50%; | |||||
| top: 50%; | |||||
| left: 0; | |||||
| top: 0; | |||||
| width: 100vw; | |||||
| height: 100vh; | |||||
| transform: scale(0); | |||||
| transition: transform 0.1s; | |||||
| &.active { | |||||
| transform: scale(1); | |||||
| } | |||||
| img { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| object-fit: contain; | |||||
| } | |||||
| } | } | ||||
| .back-button { | .back-button { | ||||
| @@ -13,7 +27,7 @@ | |||||
| right: 10px; | right: 10px; | ||||
| width: 40px; | width: 40px; | ||||
| height: 40px; | height: 40px; | ||||
| background: rgba(white, 0.5); | |||||
| background: rgba($pink, 0.5); | |||||
| border: 0px; | border: 0px; | ||||
| border-radius: 50%; | border-radius: 50%; | ||||
| display: flex; | display: flex; | ||||
| @@ -29,6 +43,7 @@ | |||||
| .container { | .container { | ||||
| position: relative; | position: relative; | ||||
| z-index: 0; | |||||
| } | } | ||||
| .glass-image { | .glass-image { | ||||
| @@ -75,6 +90,7 @@ | |||||
| display: flex; | display: flex; | ||||
| align-items: center; | align-items: center; | ||||
| width: 100%; | width: 100%; | ||||
| z-index: 1; | |||||
| button { | button { | ||||
| width: 50px; | width: 50px; | ||||
| @@ -104,4 +120,43 @@ | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| .image-action-buttons { | |||||
| position: fixed; | |||||
| left: 0; | |||||
| bottom: 20px; | |||||
| width: 200px; | |||||
| margin-left: calc(50% - 100px); | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| padding: 10px; | |||||
| background-color: rgba(black, 0.6); | |||||
| border-radius: 30px; | |||||
| z-index: 1; | |||||
| button { | |||||
| width: 50px; | |||||
| height: 50px; | |||||
| border-radius: 50%; | |||||
| border: 1px solid rgba($blue-grey, 0.6); | |||||
| background-color: transparent; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| &:nth-child(2) { | |||||
| transform: rotate(180deg); | |||||
| } | |||||
| img { | |||||
| width: 20px; | |||||
| } | |||||
| ion-icon { | |||||
| color: white; | |||||
| font-size: 20px; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1,6 +1,7 @@ | |||||
| import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; | ||||
| import { detectSingleFace, loadFaceExpressionModel, loadFaceLandmarkModel, loadFaceLandmarkTinyModel, loadFaceRecognitionModel, loadSsdMobilenetv1Model, loadTinyFaceDetectorModel, TinyFaceDetectorOptions } from 'face-api.js'; | import { detectSingleFace, loadFaceExpressionModel, loadFaceLandmarkModel, loadFaceLandmarkTinyModel, loadFaceRecognitionModel, loadSsdMobilenetv1Model, loadTinyFaceDetectorModel, TinyFaceDetectorOptions } from 'face-api.js'; | ||||
| import { Location } from '@angular/common'; | import { Location } from '@angular/common'; | ||||
| import { ModalController } from '@ionic/angular'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-ar-fan-cam', | selector: 'app-ar-fan-cam', | ||||
| @@ -24,14 +25,15 @@ export class ArFanCamPage implements OnInit { | |||||
| areNeuralNetsLoaded = false; | areNeuralNetsLoaded = false; | ||||
| isDetecting = false; | isDetecting = false; | ||||
| width = 360; | |||||
| height = 270; | |||||
| width: number; | |||||
| height: number; | |||||
| temp: string; | |||||
| tempImg = ''; | |||||
| stream: any; | stream: any; | ||||
| constructor( | constructor( | ||||
| private location: Location | |||||
| private location: Location, | |||||
| private modalController: ModalController | |||||
| ) { } | ) { } | ||||
| loadNeuralNetModels = async () => { | loadNeuralNetModels = async () => { | ||||
| @@ -48,7 +50,7 @@ export class ArFanCamPage implements OnInit { | |||||
| } | } | ||||
| back() { | back() { | ||||
| this.location.back(); | |||||
| this.modalController.dismiss(); | |||||
| this.stopCameraStream(); | this.stopCameraStream(); | ||||
| } | } | ||||
| @@ -107,6 +109,8 @@ export class ArFanCamPage implements OnInit { | |||||
| const dataURI = canvas.toDataURL('image/png'); | const dataURI = canvas.toDataURL('image/png'); | ||||
| this.capturedImageStrings.push(dataURI); | this.capturedImageStrings.push(dataURI); | ||||
| this.tempImg = dataURI; | |||||
| context.resetTransform(); | context.resetTransform(); | ||||
| context.clearRect(0, 0, window.innerWidth, window.innerHeight); | context.clearRect(0, 0, window.innerWidth, window.innerHeight); | ||||
| } | } | ||||
| @@ -142,19 +146,22 @@ export class ArFanCamPage implements OnInit { | |||||
| } | } | ||||
| } | } | ||||
| ngOnInit() { | |||||
| ngOnInit() { | |||||
| this.width = window.innerWidth; | |||||
| this.height = window.innerHeight; | |||||
| } | } | ||||
| ngAfterViewInit() { | ngAfterViewInit() { | ||||
| this.loadNeuralNetModels(); | this.loadNeuralNetModels(); | ||||
| const feedWidth = window.innerWidth; | |||||
| const feedHeight = window.innerHeight; | |||||
| this.width = feedWidth; | |||||
| this.height = feedHeight; | |||||
| this.getCameraStream().then(() => this.detectAndDrawFace(), (err) => console.log(err)); | this.getCameraStream().then(() => this.detectAndDrawFace(), (err) => console.log(err)); | ||||
| } | } | ||||
| approveImage() { | |||||
| this.stopCameraStream(); | |||||
| this.modalController.dismiss({ | |||||
| imageData: this.tempImg | |||||
| }); | |||||
| } | |||||
| } | } | ||||
| @@ -26,11 +26,11 @@ | |||||
| </div> | </div> | ||||
| <ul class="stories"> | <ul class="stories"> | ||||
| <li [routerLink]="['/ar-fan-cam']"> | |||||
| <li (click)="presentCamModal()"> | |||||
| <ion-icon name="add-circle-outline"></ion-icon> | <ion-icon name="add-circle-outline"></ion-icon> | ||||
| <span> Add Story </span> | <span> Add Story </span> | ||||
| </li> | </li> | ||||
| <li *ngFor="let story of fanStories; let i = index" [ngClass]="{'inactive' : story.opened }" | |||||
| <li *ngFor="let story of reversed(fanStories); let i = index" [ngClass]="{'inactive' : story.opened }" | |||||
| (click)="showSlides = true; story.opened = true; goToSlide(i)"> | (click)="showSlides = true; story.opened = true; goToSlide(i)"> | ||||
| <img [src]="story.profileImage"> | <img [src]="story.profileImage"> | ||||
| <span> {{ story.name }} </span> | <span> {{ story.name }} </span> | ||||
| @@ -38,7 +38,7 @@ | |||||
| </ul> | </ul> | ||||
| <ul class="fan-feature-list"> | <ul class="fan-feature-list"> | ||||
| <li [routerLink]="['/ar-fan-cam']"> | |||||
| <li (click)="presentCamModal()"> | |||||
| <div> | <div> | ||||
| <ion-icon name="camera-outline"></ion-icon> | <ion-icon name="camera-outline"></ion-icon> | ||||
| @@ -1,10 +1,11 @@ | |||||
| import { Component, OnInit, ViewChild } from '@angular/core'; | import { Component, OnInit, ViewChild } from '@angular/core'; | ||||
| import { IonSlides } from '@ionic/angular'; | |||||
| import { IonItemOption, IonSlides, ModalController } from '@ionic/angular'; | |||||
| import { GooglePlus } from '@ionic-native/google-plus/ngx'; | import { GooglePlus } from '@ionic-native/google-plus/ngx'; | ||||
| import { Platform } from '@ionic/angular'; | import { Platform } from '@ionic/angular'; | ||||
| import { AngularFireAuth } from '@angular/fire/auth'; | import { AngularFireAuth } from '@angular/fire/auth'; | ||||
| import firebase from 'firebase'; | import firebase from 'firebase'; | ||||
| import { ArFanCamPage } from '../ar-fan-cam/ar-fan-cam.page'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-fan-zone', | selector: 'app-fan-zone', | ||||
| @@ -59,6 +60,7 @@ export class FanZonePage implements OnInit { | |||||
| private google: GooglePlus, | private google: GooglePlus, | ||||
| private fireAuth: AngularFireAuth, | private fireAuth: AngularFireAuth, | ||||
| private platform: Platform, | private platform: Platform, | ||||
| private modalController: ModalController, | |||||
| ) { } | ) { } | ||||
| // async loginWithGoogle() { | // async loginWithGoogle() { | ||||
| @@ -193,4 +195,28 @@ export class FanZonePage implements OnInit { | |||||
| }); | }); | ||||
| } | } | ||||
| reversed(data: Array<any>) { | |||||
| return data.reverse(); | |||||
| } | |||||
| async presentCamModal() { | |||||
| const modal = await this.modalController.create({ | |||||
| component: ArFanCamPage, | |||||
| }); | |||||
| modal.onDidDismiss().then((data: any) => { | |||||
| if (data.data && data.data.imageData) { | |||||
| this.fanStories.push({ | |||||
| profileImage: this.googleUserData.profileImage, | |||||
| name: this.googleUserData.name, | |||||
| storyImage: data.data.imageData, | |||||
| likeCount: 1, | |||||
| opened: false | |||||
| }); | |||||
| } | |||||
| }); | |||||
| return await modal.present(); | |||||
| } | |||||
| } | } | ||||