[Application 57] « Evalue ton coin » : Positionnement GPS, prise de photo, évaluations …

evaluetoncoin

Introduction


Micro app faite ce matin en 4h00, exploitant la webcam et le positionnement GPS. Pas Back End. Pour tester, c’est ici .

Synopsis


Un commercial doit se balader avec son portable ou sa tablette et prendre des photos et noter le coin avec des knobs. A la fin de la session, les données sont centralisées sur la base du données du Back End, et un tri est possible ainsi que l’élaboration de statistiques graphiques avec charts.js.

Processus de développement :


Pas d’uml, il s’agit d’un  exo, lol.

Phase 1 : Design et Css botstrap

Phase 2 : Coding Js et AngularJs.

Phase 3 : élaboration de web Storage et du back End pour l’hibernation.

Compatibilité : Firefox et Firefox Mobile

Explication sommaire du code :


Soit $scope.nouvelEndroit un nouvel endroit(objet json), alors $scope.endroits est le tableau d’objets json contenant tous les $scope.nouvelEndroit, et $scope.endroits peut être peuplé d’une acquisition BackEnd sur Mysql ou noSql.

Les photos sont stockées en Base 64 , pour les afficher, Jquery est utilisée parce que angular est trop couteux en dirtycheking.

Par contre, AngularJs est très bien sur le tableau récapitulatif, pour trier.

Note: le web Storage ne veut pas fonctionner avec le tableau des images qui est contenu dans un objet dans le modèle. Je n’ai pas d’explication à cela pour l’instant, c’est très embétant.

Le code :


index.html:


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Evalue ton coin</title>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
		<!-- CHARGEMENT DES LIBRAIRIES -->

		<!-- JQUERY ET BOOTSRAP -->
        <script src="bower_components/jquery/dist/jquery.min.js"></script>
        <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
		<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css">

        <!-- ANGULARJS -->
        <script src='bower_components/angular/angular.min.js'></script>

		<!-- NG -KNOB -->
         <script src="bower_components/d3/d3.min.js"></script>
        <script src="bower_components/ng-knob/dist/ng-knob.min.js"></script>

		<!-- APPLICATION PERSO -->
		<script src="js/app.js"></script>
		<link rel="stylesheet" type="text/css" href="css/style.css">

		<!-- FIN DE CHARGEMENT DES LIBRAIRIES -->
  </head>

<body ng-app="neutre" ng-controller="neutreCtrl">
	<div class="container-fluid">

        <nav class="navbar navbar-inverse">
            <div class="container-fluid">
                <!-- Brand and toggle get grouped for better mobile display -->
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span class="sr-only">Toggle navigation</span>
                    </button>
                    <a class="navbar-brand" href="#">Evalue ton coin</a>
                </div>
                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                </div><!-- /.navbar-collapse -->
            </div><!-- /.container-fluid -->
        </nav>

	<div class="row ">
		<div class="col-lg-12 " >
			 <div class="panel panel panel-warning">

				<div class="panel-heading">
					<i class="fa fa-picture-o"></i> Evalue le coin :
					<div class="box-tools pull-right">
						<button class="btn btn-primary btn-sm pull-right" ng-model="collapsed" ng-click="collapsed=!collapsed" data-widget="collapse"><i class="fa fa-minus"></i></button>
					</div>
				</div>

				<div ng-show="!collapsed" class="panel-body" style="min-height:350px;">

					<div class="col-lg-6 " >
						<div class="panel  panel-primary ">
							 <div class="panel-heading" >
								<i class="fa fa-picture-o"></i> Ta position
							</div>
							<div class="panel-body">
								<div><b>Longitude :</b> {{test}} Latitude : {{latitude}}</div>
								<div><b>Adresse :</b>{{adresse}} </div>
								<div style="overflow:auto"><div id="map" ></div></div>
							</div>
						</div>
					</div>

					<div class="col-lg-6 " >
						<div class="panel  panel-primary ">
							 <div class="panel-heading" >
								<i class="fa fa-picture-o"></i> Prends ta photo
							</div>
							<div class="panel-body text-right">
								<video id="v" style="width:100%;"></video>
								<button id="prends" class="btn-warning btn-block">Prends une photo</button>
							</div>
						</div>
					</div>

					<div class="col-lg-12 " >
						<div class="panel  panel-primary ">
							 <div class="panel-heading" >
								<i class="fa fa-picture-o"></i> Liste de tes photos
							</div> <canvas id="canvas" style="display:none;width:50px;"></canvas>
							<div class="panel-body" id="listePhoto" style="min-height:150px;">

								<!-- <img src="" id="photo" alt="photo">   -->
								<!-- <div ng-repeat="photo in photos"><img ng-src="{{::photo}}" style="width:150px;float:left"></img></div>  -->
							</div>
						</div>
					</div>

					<div class="col-lg-12 " >
						<div class="panel  panel-danger  ">
							 <div class="panel-heading" >
								<i class="fa fa-picture-o"></i> Affecte une note
							</div>
								<div class="panel-body" style="overflow:auto" >
									<div class="form-group input-group col-lg-3" style="float: left;">
										<span class="input-group-addon " >Propreté</span>
										<ui-knob value="nouvelEndroit.proprete" options="options"></ui-knob>
									</div>
									<div class="form-group input-group col-lg-3" style="float: left;">
										<span class="input-group-addon">Rangement</span>
										<ui-knob value="nouvelEndroit.rangement" options="options"></ui-knob>
									</div>
									<div class="form-group input-group col-lg-3" style="float: left;">
										<span class="input-group-addon">Fréquentation</span>
										<ui-knob value="nouvelEndroit.frequentation" options="options"></ui-knob>
									</div>

									<div class="form-group input-group col-lg-3" style="float: left;">
										<span class="input-group-addon">Général</span>
										<ui-knob value="nouvelEndroit.general" options="options"></ui-knob>
									</div>
								</div>
						</div>
					</div>

				</div>

				<div class="panel-footer ">
					<div class="form-group text-right">
						<button ng-click="enregistrerEvaluation();showAlert()" class="btn-primary btn-block">Enregistrer</button>
						 <div  ng-show="alertMsg.show"  class="alert alert-success " role="alert" ><strong>Bien Joué</strong> Vous avez bien évalué le coin. </div>
                    </div>

                </div>
            </div>
        </div>
    </div>

	<div class="row">

	   <!-- TEMPLATE DE SELECTION DUN OBJET -->
	   <div class="col-lg-12" >
		   <div class="panel panel panel-warning">
				<div class="panel-heading">
					<i class="fa fa-list"></i> Liste des évaluations

				</div>

				<div class="panel-body table-responsive" style="min-height:350px;">
					<table class="table table-bordered table-hover  " style="width:100%">

							<thead>
								<tr>
								   <th>
										Adresse
									</th>
									<th  >
										<a href="#" ng-click="sortType = 'date'; sortReverse = !sortReverse">
										Date
										<span ng-show="sortType == 'date' && !sortReverse" class="fa fa-caret-down"></span>
										<span ng-show="sortType == 'date' && sortReverse" class="fa fa-caret-up"></span></a>
									</th>
									<th  >
										<a href="#" ng-click="sortType = 'proprete'; sortReverse = !sortReverse">
										Propreté
										<span ng-show="sortType == 'proprete' && !sortReverse" class="fa fa-caret-down"></span>
										<span ng-show="sortType == 'proprete' && sortReverse" class="fa fa-caret-up"></span></a>
									</th>
									<th  >
										<a href="#" ng-click="sortType = 'rangement'; sortReverse = !sortReverse">
										Rangement
										<span ng-show="sortType == 'rangement' && !sortReverse" class="fa fa-caret-down"></span>
										<span ng-show="sortType == 'rangement' && sortReverse" class="fa fa-caret-up"></span></a>
									</th>
									<th  >
										<a href="#" ng-click="sortType = 'frequentation'; sortReverse = !sortReverse">
										Fréquentation
										<span ng-show="sortType == 'frequentation' && !sortReverse" class="fa fa-caret-down"></span>
										<span ng-show="sortType == 'frequentation' && sortReverse" class="fa fa-caret-up"></span></a>
									</th>
										<th  >
										<a href="#" ng-click="sortType = 'general'; sortReverse = !sortReverse">
										Général
										<span ng-show="sortType == 'general' && !sortReverse" class="fa fa-caret-down"></span>
										<span ng-show="sortType == 'general' && sortReverse" class="fa fa-caret-up"></span></a>
									</th>

									<!-- <th>
										Editer
									</th> -->
								</tr>
							</thead>
							<tbody>
								<tr ng-repeat="endroit in endroits | orderBy:sortType:sortReverse |filter:k">
									<td>{{endroit.adresse}}</td>
									<td>{{endroit.date| date:'MM/dd/yyyy @ h:mma'}}</td>
									<td>{{endroit.proprete}}</td>
									<td>{{endroit.rangement}}</td>
									<td>{{endroit.frequentation}}</td>
									<td>{{endroit.general}}</td>
									 <!-- <td><button ng-click="editerEndroit(endroit)" class= "fa fa-edit">Editer</button></td> -->
								</tr>
							</tbody>
					</table>
				</div>

				<div class="panel-footer ">
					<div class="form-group">
						<!-- <input type="text" class="form-control " ng-model="k" placeholder="Chercher une adresse">  -->
					</div> <!-- <button class="btn">Rafraichir</button> -->
				</div>
			</div>	

		</div>	

	</div>

<!-- FIN DE DIV GLOABLE FLUID -->
</div>

</body>
</html>

app.js :

angular.module('neutre', ['ui.knob'])

.controller('neutreCtrl', function($scope,$http,$timeout) {

	var d = new Date();
	photos = []; // Contient les photos d une nouvelle evaluation
	$scope.nouvelEndroit = [];
	$scope.nouvelEndroit.date = d;
	$scope.endroits = []; // Liste des endroits visitéss

	/* CRUD  */

	/* Sauvegarde une évaluation, avec les photos en base 64 la date, l adresse acquiert par google map */
	$scope.enregistrerEvaluation = function(){
		$scope.nouvelEndroit.photos = photos; // Place les photos dans l objet a enregistrer
		$scope.endroits.push($scope.nouvelEndroit);
		localStorage.setItem('end',$scope.nouvelEndroit.photos);
		$scope.value = localStorage.getItem('end');
		/* 	console.log("golok"+$scope.value); */
		initEndroit();

	}

	/* REINITIALISATION DU FORMULAIRE APRES UNE EVAL */
	initEndroit = function(){
		var d = new Date();
		photos = [];
		$scope.nouvelEndroit = [];
		$scope.nouvelEndroit.date = d;
		$('#listePhoto').html("");
	}

	/* GEOLOCALISATION */
	// Detecte l'api avant de l'utiliser 

	if (navigator.geolocation) {
	 // Insère la carte dans la div "map"
		var mapElem = document.getElementById("map"),

		// cette fonction en cas de succès d'acces à la position récupère la long et la lat puis affiche google map

			successCallback = function(position) {
				var lat = position.coords.latitude,
					long = position.coords.longitude;
			$scope.$apply(function(){
				$scope.latitude = lat;
				$scope.test=long;
				getAdresse(lat,long);
			});

				mapElem.innerHTML = '<img src="http://maps.googleapis.com/maps/api/staticmap?markers=' + lat + ',' + long + '&zoom=15&size=300x300&sensor=false" />';

			},

		// Cette fonction se lance si l'endroit ne peut pas être localisé
		errorCallback = function() {
				  alert("Désolé, je ne peux pas trouver vos coordonnées GPS.");
			};

		// Start watching the user’s location, updating once per second (1s = 1000ms)
		// and execute the appropriate callback function based on whether the user
		// was successfully located or not

		navigator.geolocation.watchPosition(successCallback, errorCallback, {
			maximumAge: 1000
		});
	}

	getAdresse = function (lat,long){
		$http.get('http://maps.googleapis.com/maps/api/geocode/json?latlng=' + lat + ',' + long + '&sensor=true',{header : {'Content-Type' : 'application/json; charset=UTF-8'}}).success(function(data){
			/* console.log(data.results[0].formatted_address); */
			/* POSITION SE METS A JOUR EN TEMPS REEL AVEC LE $SCOPE */
			$scope.adresse = data.results[0].formatted_address;
			$scope.nouvelEndroit.adresse = data.results[0].formatted_address;
			}).error(function(data){ $scope.infos = " Pas de données ou pb de connexion"});

	}

	/* VIDEO */

	  ;(function(){
    <!-- la fonction générique qui est censée s adapter a tous les navigateurs -->
        function userMedia(){
            return navigator.getUserMedia = navigator.getUserMedia ||
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.msGetUserMedia || null;

        }

        // Maintenant, on peut l utiliser
        if( userMedia() ){
            var videoPlaying = false;
            var constraints = {
                video: true,
                audio:false
            };
            var video = document.getElementById('v');

            var media = navigator.getUserMedia(constraints, function(stream){

                // L url de l objet est different dans webkit
                var url = window.URL || window.webkitURL;

                // creer l url et set la source de la video
                video.src = url ? url.createObjectURL(stream) : stream;

                // lance la video
                video.play();
                videoPlaying  = true;
            }, function(error){
                console.log("ERROR");
                console.log(error);
            });

            // ecoute l action utilisateur sur le bouton prendre une photo
            document.getElementById('prends').addEventListener('click', function(){
                if (videoPlaying){
                    var canvas = document.getElementById('canvas');
                    canvas.width = video.videoWidth;
                    canvas.height = video.videoHeight;
                    canvas.getContext('2d').drawImage(video, 0, 0);
                    var data = canvas.toDataURL('image/webp');
                   /* document.getElementById('photo').setAttribute('src', data);  */
					/* console.log(data); */
					photos.push(data);
					/* console.log(photos);  */
					$('#listePhoto').prepend('<img  src="' + data + '" style="width:150px;"/>')// Affiche avec Jqeury la photo en base 64 dans la liste des photos
				}
            }, false);

        } else {
            console.log("KO");
        }
    })();

	/* Parametrage de l'aspect des KNOBS */
		$scope.options = {
		  skin: {
			type: 'tron'
		  },
		  size: 150,
		  unit: "",
		  barWidth: 20,
		   bgColor: '#2C3E50',
			 barColor: '#FFAE1A',
		  textColor: '#eee',
		  trackColor: 'rgba(255,0,0,.1)',
		  prevBarColor: 'rgba(0,0,0,.2)',
		  subText: {
			enabled: false,
			text: 'CPU used'
		  },
		  scale: {
			enabled: true,
			type: 'lines',
			width: 3
		  },
		  step: 0.1,
		  max:10,
		  displayPrevious: true
		};

		/* Montrer un message Bootstrap sur click. */
		 $scope.alertMsg = {
				show: false,
				text:"Alert message is ::show"
			};
			$scope.showAlert =function(){
				 $scope.alertMsg.show = true;
				$timeout(function(){
					$scope.alertMsg.show = false;
				}, 2000);
			}

/* FIN DU CONTROLEUR */
});

  
Publicités