[Exercice 50] Graphiques AngularCharts, édition temps réel, MultiObjets…

Introductionint


Exercice durant 3 h, comprenant une table éditable et triable, des graphiques qui s’auto modifient en temps réel.

Pour le tester en ligne , c’est ici
On peut choisir les objets dans le modèle de données avec un select html, le modèle de données est  d’un format classique de tableau d’objets JSON.

Par contre, j’ai mis beaucoup trop de 2 way binding(par contrainte de temps), il faudra demain faire une version presque sans 2 way binding et qui actualise les graphiques après clic sur un bouton, sans cela , pbs de perfs si beaucoup d’objets.Le modèle de données multi-objets est censé émuler un Back End, cependant, le fait qu’il soit sous $scope n’est pas trop bien même pour une démo, ça prends trop de ressources mais cela fonctionne, et permet de travailler les tableaux d’objets JSON. Après reflexion, il faut de préfèrence « puiser » dans le modèle multi objet présent sur une base de données back-end,puis ensuite , on peut injecter un objet unique dans le $scope, de cette façon, il n’y a pas trop de 2 way bindings, dans cet exemple, les graphiques devraient être alimentés par une requête sur la base de données, et pas sur le modèle présent en mémoire vive, mais si il y a peu d’objets en mémoire vive, cela peut être envisageable de faire cela.. La liste des objets devrait provenir d’une requête sur un système back end.

J’ai aussi repéré un SUPER système de graphiques que l’on peut modifierpar drag n drop ici :
http://jsfiddle.net/edgarszagorskis/HgtS9/

A exploiter ces jours ci !

Photo de l’exercice :


exo50

Explication sommaire du code :


$scope.listeObjets est un modèle de données pouvant provenir d’un back-End, structuré de manière classique.

Lorsqu’on clique sur un objet dans le menu déroulant, ça retrouve son index dans le modèle de donnée et affiche l’objet dans la table.

Les graphiques eux recapitulent les données de chaque objets. On pourrait ajouter des objets, les graphiques fonctionneraient encore.

Le code :


Le fichier HTML :

<html ng-app="App">
	<head>
		<meta charset="utf-8" />
		<title>Statistiques de production.</title>

		<!-- 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">
		<!-- Custom styles for this template -->
		<link href="sticky-footer.css" rel="stylesheet">

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

		     <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css">

		<!-- UI BOOTSTRAP -->
		<script src='bower_components/angular-bootstrap/ui-bootstrap.min.js'></script>
		<script src='bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js'></script>

		<!-- APPEL LIB ANGULAR CHARTS -->
		<script src="bower_components/Chart.js/Chart.min.js"></script>
		<script src="bower_components/angular-chart.js/dist/angular-chart.min.js"></script>
		<link rel="stylesheet" href="bower_components/angular-chart.js/dist/angular-chart.css">

	</head>

	<body ng-controller="MainCtrl">
		<div class="container-fluid">
			<nav class="navbar navbar-inverse">
			  <div class="container-fluid">
					<div class="navbar-header">
						<a class="navbar-brand" href="#">ProductionStats</a>
					</div>
					<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
						<ul class="nav navbar-nav navbar-right">
							<div class="form-group">
								<form>
								</form>
							</div>
						</ul>
					</div><!-- /.navbar-collapse -->
				</div><!-- /.container-fluid -->
			</nav>

			<div class="row">
				<div class="col-md-6 divSpe">
				<h1>Choix</h1>

				<form >
					<label > Sélectionnez l'objet: </label>
					<select ng-model="objetSelectionne" ng-change="choixObjet()">
					  <option ng-repeat="objet in listeObjets" value="{{listeObjets.indexOf(objet)}}">{{objet.nom}}
						</option> <!-- Récupère l'id de l'objet on s'en sert dans choixObjet() pour trouver l'index de l'objet  -->
					</select>
				 </form>

				</div>
				<div class="col-md-6 divSpe">
				<h1>Détail</h1>
					<img src="{{listeObjets[x].image}}" class="img-responsive" style="max-width:400px;"/>
					<table>
					<tr><td>{{listeObjets[x].marque}}</td></tr>
					<tr><td>{{listeObjets[x].serie}}</td></tr>
					</table>
				</div>
			</div>	

			<div class="row">
				<div class="col-md-6 divSpe table-responsive">
				<h1> Statistiques</h1>
				<!-- <select class="form-control" ng-model="g" required>
					<option value="">Classer par</option>
					<option value="defectueux">Défectueux</option>
					<option value="production">Production</option>
				</select> -->
					<table class="table table-bordered table-hover table-condensed " style="width:100%">

						<thead>
							<tr>
								<th >

								<a href="#" ng-click="sortType = 'jour'; sortReverse = !sortReverse">
									Jour
									<span ng-show="sortType == 'jour' && !sortReverse" class="fa fa-caret-down"></span>
									<span ng-show="sortType == 'jour' && sortReverse" class="fa fa-caret-up"></span></th>
								</a>
								<th  class="a">
									<a href="#" ng-click="sortType = 'production'; sortReverse = !sortReverse">
									Production
									<span ng-show="sortType == 'production' && !sortReverse" class="fa fa-caret-down"></span>
									<span ng-show="sortType == 'production' && sortReverse" class="fa fa-caret-up"></span></a>
								</th>
								<th>
									<a href="#" ng-click="sortType = 'defectueux'; sortReverse = !sortReverse">
									Défectueux
									<span ng-show="sortType == 'defectueux' && !sortReverse" class="fa fa-caret-down"></span>
									<span ng-show="sortType == 'defectueux' && sortReverse" class="fa fa-caret-up"></span></a>
								</th>
								<th>
								Pourcentage Défectueux</th>
							</tr>
						</thead>
						<tbody>
							<tr ng-repeat="objet in listeObjets[x].donnees | orderBy:sortType:sortReverse "> <!-- x provient de la fonction choixObjet() -->
								<td>{{::objet.jour}}</td>
								<td><input type="number" ng-model="objet.production" ng-change="initGraphe();initGraphe2()"></input></td>
								<td><input type="number" ng-model="objet.defectueux" ng-change="initGraphe();initGraphe2()"></td>
								<td>{{((objet.defectueux/objet.production)*100).toFixed(2)}} %</td>
							</tr>
						</tbody>
						<tbody>
							<tr class="success" >
								<td >Total</td>
								<td>{{listeObjets.sommeProduction()}}</td>
								<td>{{listeObjets.sommeDefectueux()}}</td>
								<td>{{((listeObjets.sommeDefectueux()/listeObjets.sommeProduction())*100).toFixed(2)}} %</td>
							</tr>
						</tbody>

					</table> 

								<button class="" ng-click="ajouter()">Ajouter</button>
				</div>	

				<div class="col-md-6 divSpe ">
				<h1> Graphique Comparatif de Production</h1>
					<canvas id="line" class="chart chart-line" chart-data="data"
					  chart-labels="labels" chart-legend="true" chart-series="series"
					  chart-click="onClick" >
					</canvas>
				</div>
			</div>				

			<div class="row">
			<div class="col-md-6 divSpe ">
				<h1> Graphique Comparatif de Défectuosité</h1>
					<canvas id="line" class="chart chart-line" chart-data="data2"
					  chart-labels="labels2" chart-legend="true" chart-series="series2"
					  chart-click="onClick" >
					</canvas>
				</div>
			</div>

			<footer class="footer">
			  <div class="container">
				<p class="text-muted">Votre pied de page.</p>
			  </div>
			</footer>

		<!-- FIND DE DIV GLOBALE FLUID BOOSTRAP POUR LES PHONES -->
		</div>
		<script src="app.js"> </script>
	</body>
</html>
<style>
.container {
    margin-top:10px;
    font-family:arial;
}
input:focus {
    //change more attributes, if you want.
}
input {
    border:none;
    background-color:transparent;
}
.container header {
    padding-bottom:20px;
    border-bottom:1px solid black;
}
ul, input, .container {
    padding:10px;
}
.divSpe{
border: 3px rgb(89,89,89) solid;

background: rgb(218, 211, 210);

color: rgb(25,25,25);
font-size: inherit;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
text-decoration: inherit;
text-align: left;

line-height: 1.3em;
-moz-box-shadow: inset 0px 0px 13px 4px rgb(128,128,128);
-webkit-box-shadow: inset 0px 0px 13px 4px rgb(128,128,128);
box-shadow: inset 0px 0px 13px 4px rgb(128,128,128);

}
.a{
width:10px;
}

</style>

Le fichier JS :

var app = angular.module('App', ['ui.bootstrap','chart.js'])

app.controller('MainCtrl', function($scope,$timeout) {
	
$scope.Math = window.Math;
 $scope.sortType     = 'name'; // set the default sort type
  $scope.sortReverse  = false;  // set the default sort order
  $scope.searchFish   = '';     // set the default search/filter term
  $scope.x = 0;

/* DONNES DE DEMONSTRATION */
$scope.listeObjets = [
{"id":1,"nom":"Carburateur","image":"img-app/64_3.gif","marque":"Renault","serie":"478BVCDE","donnees":[
{"date":"","jour":1,"production":200,"defectueux":10,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":2,"production":180,"defectueux":20,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":3,"production":250,"defectueux":10,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":4,"production":305,"defectueux":75,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":5,"production":250,"defectueux":25,"frequence":"","pourcentage":"","moyenne":""},
]},
{"id":25,"nom":"Démarreur","image":"img-app/demarreur.gif","marque":"PSA","serie":"G785287","donnees":[
{"date":"","jour":1,"production":200,"defectueux":10,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":2,"production":100,"defectueux":20,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":3,"production":250,"defectueux":5,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":4,"production":320,"defectueux":75,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":5,"production":250,"defectueux":78,"frequence":"","pourcentage":"","moyenne":""},
]},
{"id":3,"nom":"Alternateur","image":"img-app/alternateur_coupe.jpg","marque":"FIAT","serie":"G78fef7","donnees":[
{"date":"","jour":1,"production":200,"defectueux":10,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":2,"production":180,"defectueux":79,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":3,"production":505,"defectueux":35,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":4,"production":210,"defectueux":12,"frequence":"","pourcentage":"","moyenne":""},
{"date":"","jour":5,"production":250,"defectueux":25,"frequence":"","pourcentage":"","moyenne":""},
]},
];	


/* Suite au choix de l'objet dans le select, on affiche les données de l'objet choisi dans les élèments de la vue HTML  */
$scope.choixObjet = function (){
	$scope.x = $scope.objetSelectionne; // le ng-repeat s'affiche en fonction de l'index qui a été choisi
	$scope.initGraphe();
	$scope.initGraphe2();
	}

/* SOMME DE LA PRODUCTION DE L OBJET  */
$scope.listeObjets.sommeProduction = function(){
	var total = 0;

	for (var i = 0; i < $scope.listeObjets[$scope.x].donnees.length; i++) {
		total = total + $scope.listeObjets[$scope.x].donnees[i].production;
	}
    return total;
	
};

/* SOMME D OBJETS 1 DEFECTEUX */
$scope.listeObjets.sommeDefectueux = function(){
	var total = 0;
	for (var i = 0; i < $scope.listeObjets[$scope.x].donnees.length; i++) {
		total = total + $scope.listeObjets[$scope.x].donnees[i].defectueux;
	}
    return total;
};

$scope.ajouter = function(){
	$scope.listeObjets[$scope.x].donnees.push({"date":"","jour":$scope.listeObjets[$scope.x].donnees.length+1,"production":0,"defectueux":0,"frequence":"","pourcentage":"","moyenne":""})
	$scope.initGraphe();
	$scope.initGraphe2();

	}

/* GRAPHE */
$scope.initGraphe = function(){
	
	/* Initialisation des données que l on passe ensuite au graphique , on les puise dans $scope.objet, le modele principal de donnees*/

	var labels = []; // dans ce cas les labels seront les jours, c'est l abscisse
	var tabProd = [];// Va contenir tous les chiffres de production des objets
	var k = $scope.x; /* Variable index de l objet actuel */
	var nbObjets = $scope.listeObjets.length;
	var series  = [];
	
	/* CALCULE LES JOURS EN ORDONNEES */
	 /* Attention cest pas bon pour l'instant il faut calculer MAX JOURS de tous les objets */
	for(z=0;z<$scope.listeObjets[k].donnees.length;z++){
				labels.push($scope.listeObjets[k].donnees[z].jour);
			}
	
/* 	CET ALGO PRODUIT UN TABLEAU MULTIDIMENSIONNEL COMPRENANT LES DONNEES DE TOUS LES OBJETS PRESENTS, IL Y A DEUX BOUCLES FOR IMBRIQUEES POUR PARCOURIR TOUT LE MODELE DE DONNEES */
/* IL EST A DESTINATION DE $SCOPE.DATA QUI EST NECESSAIRE A ANGULAR CHARTS */
	for (u=0;u<nbObjets;u++){
		var arr = new Array();
		
			/* CALCULE LA PRODUCTION JOURNALIERE DE LOBJET CHOISI */
			for(z=0;z<$scope.listeObjets[u].donnees.length;z++){
				arr.push($scope.listeObjets[u].donnees[z].production);
				
			}
		tabProd.push(arr); // CREE UN TABLEAU MULTIDIMENSIONNEL UN FORMAT QUE ANGULAR CHARTS ACCEPTE
	}
	
	/* Trouve les Noms des objets  */
	for(z=0;z<$scope.listeObjets.length;z++){
		series.push($scope.listeObjets[z].nom);
		
	}
	
	console.log(series);
	
/* 	console.log(tabProd[0]);
	console.log(tabProd[1]);
	console.log(tabProd[2]); */
	
	$scope.labels = labels; // Attention solution provisoire pour l'instant
	$scope.series = series;
	$scope.data = tabProd; 
	$scope.onClick = function (points, evt) {
		console.log(points, evt);
	};
}
$scope.initGraphe();

/* GRAPHE DEFECTUOSITE*/
$scope.initGraphe2 = function(){
	
	/* Initialisation des données que l on passe ensuite au graphique , on les puise dans $scope.objet, le modele principal de donnees*/

	var labels = []; // dans ce cas les labels seront les jours, c'est l'abscisse

	var tabDefectueux = [];	 // Va contenir tous les chiffres de production d objet defectueux
	var k = $scope.x;
	var nbObjets = $scope.listeObjets.length;
	var series  = [];
	
	/* CALCULE LES JOURS EN ORDONNEES *//
	for(z=0;z<$scope.listeObjets[k].donnees.length;z++){
				labels.push($scope.listeObjets[k].donnees[z].jour);
			}
	
/* 	CET ALGO PRODUIT UN TABLEAU MULTIDIMENSIONNEL COMPRENANT LES DONNEES DE TOUS LES OBJETS PRESENTS, IL Y A DEUX BOUCLES FOR IMBRIQUEES POUR PARCOURIR TOUT LE MODELE DE DONNEES */
/* IL EST A DESTINATION DE $SCOPE.DATA QUI EST NECESSAIRE A ANGULAR CHARTS */
	for (u=0;u<nbObjets;u++){
		var arr = new Array();
		
			/* CALCULE LA PRODUCTION JOURNALIERE DE LOBJET CHOISI */
			for(z=0;z<$scope.listeObjets[u].donnees.length;z++){
				arr.push($scope.listeObjets[u].donnees[z].defectueux);
				
			}
		tabDefectueux.push(arr); // CREE UN TABLEAU MULTIDIMENSIONNEL UN FORMAT QUE ANGULAR CHARTS ACCEPTE
	}
	
	/* Trouve les Noms des objets  */
	for(z=0;z<$scope.listeObjets.length;z++){
		series.push($scope.listeObjets[z].nom);
		
	}
	
	$scope.labels2 = labels; // Attentionsoluce provisoire pour linstant
	$scope.series2 = series;
	$scope.data2 = tabDefectueux; 

}
$scope.initGraphe2();
})


#mes

Publicités