Browse Source

Report de r72715 : Lisibilité et ergo des statistiques (Tetue)

- echelle axe des Y à droite (près des mesures les plus récentes)
- legende en dessous des graphes, en ligne
- Titre en fer a gauche, regroupé avec les actions de pagination
- graphe des mois depuis l'origine du site par defaut (graphe des jours inchangé sur 90jours)
- axe des X : date humainement lisible (15 janvier au lieu de 15/01/2013)
- eviter les effets de gradients sur les barres ça gene le lisibilité. On met en plein avec une très légere transparence pour ne presque pas distinguer border et background
- le gris des weekend était a peine visible sur certains ecrans, on le fonce
- la barre des changement d'année est de largeur 1 mois sur le graphe des mois
- ne pas masquer l'explication car elle n'est pas visible
- hierarchie de l'info dans le tableau des résumés

Un peu de refactoring js en utilisant closest('.graphique') au lieu d'enchainer les .parent() qui rendent le code peu robuste
svn/root/tags/plugins/statistiques/0.4.12 v0.4.12
cedric@yterium.com 10 years ago
parent
commit
94020e57b1
  1. 41
      javascript/jquery.tflot.js
  2. 2
      paquet.xml
  3. 13
      prive/squelettes/inclure/stats-visites-data_fonctions.php
  4. 35
      prive/squelettes/inclure/stats-visites-jours.html
  5. 16
      prive/squelettes/inclure/stats-visites-mois.html
  6. 12
      prive/squelettes/inclure/stats-visites-populaires.html
  7. 18
      prive/stats/visites.html
  8. 21
      prive/style_prive_plugin_stats.html

41
javascript/jquery.tflot.js

@ -61,7 +61,8 @@
legend:{
show:true,
container:null,
labelFormatter:null
labelFormatter:null,
noColumns: 3
},
bars: {fill:false},
yaxis: { min: 0 },
@ -86,6 +87,7 @@
$.extend(true, values.options, options.flot);
graph = $("<div class='graphResult' style='width:" + options.width + ";height:" + options.height + ";'></div>").appendTo(graphique);
graph.wrap("<div class='graphResult-wrap'></div>");
gInfo = $("<div class='graphInfo'></div>").appendTo(graphique);
// legende en dehors du dessin ?
@ -94,7 +96,7 @@
values.options.legend.container = legend;
}
// legende avec items clicables pour desactiver certaines series
if (options.legendeActions) {
if (options.legendeExterne && options.legendeActions) {
values.options.legend.labelFormatter = function(label) {
return '<a href="#label">' + label + '</a>';
}
@ -152,7 +154,7 @@
plots[idGraph] = $.plot(graph, values.series, values.options);
// prevoir les actions sur les labels
if (options.legendeActions) {
if (options.legendeExterne && options.legendeActions) {
$.extend(values.options, {legend:{container:null, show:false}});
actionsLegendes($('#graphique'+idGraph));
}
@ -351,11 +353,11 @@
$.extend(true, options, {
lines:{
fill:true,
fillColor: { colors: [ { opacity: 0.7 }, { opacity: 0 } ] }
fillColor: { colors: [ { opacity: 0.9 }, { opacity: 0.9 } ] }
},
bars:{
fill:true,
fillColor: { colors: [ { opacity: 0.7 }, { opacity: 0 } ] }
fillColor: { colors: [ { opacity: 0.9 }, { opacity: 0.9 } ] }
}
});
}
@ -426,16 +428,14 @@
// pour masquer / afficher certaines series
// a ne charger qu'une fois par graph !!!
$(graph).find('.legendLabel a').click(function(){
tr = $(this).parent().parent();
tr.toggleClass('cacher');
tr = $(this).parent().prev('.legendColorBox').toggleClass('cacher').parent();
// bof bof tous ces parent() et ca marche qu'avec legendeExterne:true
master = tr.parent().parent().parent().parent().parent();
master = tr.closest('.graphique');
pid = master.attr('id').substr(9); // enlever 'graphique'
var seriesActives = [];
tr.parent().find('tr:not(.cacher)').each(function(){
nom = $(this).find('a').text();
tr.find('.legendColorBox:not(.cacher)').each(function(){
nom = $(this).next('.legendLabel').find('a').text();
n = collections[pid].values.series.length;
for(i=0;i<n;i++) {
if (collections[pid].values.series[i].label == nom) {
@ -478,7 +478,7 @@
// demarrer la vignette
vignette = $(graphique).find('.graphVignette');
pid = vignette.parent().parent().attr('id').substr(9);
pid = vignette.closest('.graphique').attr('id').substr(9);
vignettes[pid] = $.plot(vignette, series, options.flot);
if (vignettesSelection[pid] !== undefined) {
@ -497,7 +497,7 @@
$(graphique).find('.graphResult').bind("plotselected", function (event, ranges) {
graph = $(event.target);
pid = graph.parent().attr('id').substr(9);
pid = graph.closest('.graphique').attr('id').substr(9);
// clamp the zooming to prevent eternal zoom
if (ranges.xaxis.to - ranges.xaxis.from < 0.00001)
@ -522,7 +522,7 @@
// raz sur double clic
$(graphique).find('.graphResult').dblclick(function (event) {
var graphique;
graphique = $(event.target).parent().parent();
graphique = $(event.target).closest('.graphique');
pid = graphique.attr('id').substr(9);
vignettesSelection[pid] = undefined;
if (vignettes[pid] != undefined) {
@ -546,7 +546,7 @@
// zoom depuis la miniature
vignette.bind("plotselected", function (event, ranges) {
graph = $(event.target);
pid = graph.parent().parent().attr('id').substr(9);
pid = graph.closest('.graphique').attr('id').substr(9);
vignettesSelection[pid] = ranges;
plots[pid].setSelection(ranges);
});
@ -554,7 +554,7 @@
// raz depuis la miniature sur double clic
vignette.dblclick(function (event) {
var graphique;
graphique = $(event.target).parent().parent().parent();
graphique = $(event.target).closest('.graphique');
pid = graphique.attr('id').substr(9);
vignettesSelection[pid] = undefined;
@ -586,7 +586,7 @@
$("#x").text(pos.x.toFixed(2));
$("#y").text(pos.y.toFixed(2));
graph = $(event.target);
pid = graph.parent().attr('id').substr(9);
pid = graph.closest('.graphique').attr('id').substr(9);
if (options.show) {
if (item) {
@ -634,7 +634,7 @@
d.setUTCHours(0);
var i = d.getTime();
do {
markings.push({ xaxis: { from: i, to: i + 2*jour }, color: '#f6f6f6' });
markings.push({ xaxis: { from: i, to: i + 2*jour }, color: '#e8e8e8' });
i += 7*jour;
} while (i < axes.xaxis.max);
@ -652,6 +652,9 @@
var markings = [];
var heure = 60 * 60 * 1000;
var jour = 24 * heure;
var width_year = jour;
if (axes.xaxis.options.minTickSize[1]=="month")
width_year = 30.4*jour;
// les mois et les ans...
d = new Date(axes.xaxis.min);
@ -663,7 +666,7 @@
i = d.getTime();
if (m == 0) {couleur = '#CA5F18';}
else {couleur = '#D7C2AF'; }
markings.push({ xaxis: { from: i, to: i + jour}, color: couleur });
markings.push({ xaxis: { from: i, to: i + (m==0?width_year:jour)}, color: couleur });
if (++m == 12) {m=0; ++y;}
d = new Date(Date.UTC(y,m,1,0,0,0));
} while (d.getTime() < axes.xaxis.max);

2
paquet.xml

@ -1,7 +1,7 @@
<paquet
prefix="stats"
categorie="statistique"
version="0.4.11"
version="0.4.12"
etat="stable"
compatibilite="[3.0.0;3.1.*]"
logo="prive/themes/spip/images/statistique-32.png"

13
prive/squelettes/inclure/stats-visites-data_fonctions.php

@ -5,6 +5,19 @@ if (!defined('_ECRIRE_INC_VERSION')) return;
include_spip('inc/acces');
include_spip('inc/statistiques');
function duree_affiche($duree,$periode){
if (intval($duree))
return $duree;
if ($periode=='mois'){
$debut = sql_getfetsel("date","spip_visites","","","date","0,1");
$debut = strtotime($debut);
$duree = ceil((time()-$debut)/24/3600);
return $duree;
}
return 90;
}
function duree_zoom($duree,$sens='plus'){
$largeur_abs = 420/$duree;

35
prive/squelettes/inclure/stats-visites-jours.html

@ -1,63 +1,64 @@
#SET{c,#VAL{article}|classement_populaires}
#SET{duree,#ENV{duree,0}|duree_affiche{jour}}
<p class="pagination">
<div class="pagination">
<span class="dl">
#SET{args,#ARRAY{id_article,#ID_ARTICLE,duree,#DUREE}}
#SET{args,#ARRAY{id_article,#ID_ARTICLE,duree,#GET{duree}}}
<a href="[(#URL_PAGE{transmettre,[(#VAL{statistiques}|param_low_sec{#GET{args}, '', 'transmettre'})]})]" class="noajax"><:statistiques:csv:></a>
</span>
|
[<span class="duree">(#ENV{duree,90}) <:info_jours:></span>] |
<a href="[(#SELF|parametre_url{duree,#ENV{duree,90}|duree_zoom{moins}})]"
[<span class="duree">(#GET{duree}) <:info_jours:></span>] |
<a href="[(#SELF|parametre_url{duree,#GET{duree}|duree_zoom{moins}})]"
class="ajax">[(#CHEMIN_IMAGE{zoomout-24.png}|balise_img{<:statistiques:info_zoom:> -})]</a>
<a href="[(#SELF|parametre_url{duree,#ENV{duree,90}|duree_zoom{plus}})]"
<a href="[(#SELF|parametre_url{duree,#GET{duree}|duree_zoom{plus}})]"
class="ajax">[(#CHEMIN_IMAGE{zoomin-24.png}|balise_img{<:statistiques:info_zoom:> +})]</a>
</p>
</div>
#SET{max,0}
#SET{moy,0}
#SET{last,0}
#SET{lastlast,0}
<B_statsj>
<table class='spip info visites' style="width:145px;position:absolute;#LANG_RIGHT:0px;margin-top:30px;">
<table class='spip info visites' style="width:145px;position:absolute;#LANG_RIGHT:0px;margin-top:10px;">
<caption><:statistiques:resume:></caption>
<tbody>
<tr>
<tr class="odd on">
<th><:info_maximum|trim{':'}|trim|ucfirst:></th>
<td class='num'>#GET{max}</td>
</tr>
<tr>
<tr class="odd on">
<th><:info_moyenne|trim{':'}|trim|ucfirst:></th>
<td class='num'>[(#GET{moy}|round)]</td>
</tr>
<tr>
<tr class="even">
<th><a href="#URL_ECRIRE{stats_referers,jour=jour}"
title="<:info_moyenne|trim{':'}|trim|attribut_html:>"><:info_aujourdhui|trim{':'}|trim|ucfirst:></a></th>
<td class='num'>#GET{last}</td>
</tr>
<tr>
<tr class="even">
<th><a href="#URL_ECRIRE{stats_referers,jour=veille}"
title="<:info_moyenne|trim{':'}|trim|attribut_html:>"><:info_hier|trim{':'}|trim|ucfirst:></a></th>
<td class='num'>#GET{lastlast}</td>
</tr>
<BOUCLE_art(ARTICLES){id_article}{statut?}>
<tr>
<tr class="odd">
<th><:statistiques:info_popularite_5|trim{':'}|trim|ucfirst:></th>
<td class='num'>[(#CHAMP_SQL{popularite}|round)]</td>
</tr>
<tr>
<tr class="odd">
<th><:info_total|trim{':'}|trim|ucfirst:></th>
<td class='num'>[(#VISITES|round)]</td>
</tr>
<tr>
<tr class="odd">
<th></th>
<td class='num'>[<strong>(#ID_ARTICLE|array_search{#GET{c}}|plus{1})</strong>[(#GET{c}|count|singulier_ou_pluriel{info_classement_1,info_classement_2,liste})]]</td>
</tr>
</BOUCLE_art>
<tr>
<tr class="odd">
<th><:info_total|trim{':'}|trim|ucfirst:></th>
<td class='num'>[(#REM|stats_total)]</td>
</tr>
<tr>
<tr class="odd">
<th><:statistiques:info_popularite_2|trim{':'}|trim|ucfirst:></th>
<td class='num'>[(#CONFIG{popularite_total}|round)]</td>
</tr>
@ -76,7 +77,7 @@
</tr>
</thead>
<tbody>
<BOUCLE_statsj(DATA){source stats_visites,jour,#ENV{duree,90},#ENV{id_article}}>
<BOUCLE_statsj(DATA){source stats_visites,jour,#GET{duree},#ENV{id_article}}>
<tr class="c_[(#CLE|affdate{l}|substr{0,3})][(#COMPTEUR_BOUCLE|=={#TOTAL_BOUCLE}|oui)c_today]">
<th title="[(#CLE|affdate{'Y/m/d'})]">[(#COMPTEUR_BOUCLE|=={#TOTAL_BOUCLE}|?{<:info_aujourdhui:>,[(#CLE|nom_jour) ][(#CLE|affdate_jourcourt)]})]</th>
<td class="val">#VALEUR{visites}</td>

16
prive/squelettes/inclure/stats-visites-mois.html

@ -1,17 +1,17 @@
#SET{duree,#ENV{duree,0}|duree_affiche{mois}}
<p class="pagination">
<div class="pagination">
<span class="dl">
#SET{args,#ARRAY{id_article,#ID_ARTICLE,duree,#DUREE}}
#SET{args,#ARRAY{id_article,#ID_ARTICLE,duree,#GET{duree}}}
<a href="[(#URL_PAGE{transmettre,[(#VAL{statistiques}|param_low_sec{#GET{args}, '', 'transmettre'})]})]" class="noajax"><:statistiques:csv:></a>
</span>
|
[<span class="duree">(#ENV{duree,365}|div{30}|intval) <:date_mois:></span>] |
<a href="[(#SELF|parametre_url{duree,#ENV{duree,365}|duree_zoom{moins}})]"
[<span class="duree">(#GET{duree}|div{30}|intval) <:date_mois:></span>] |
<a href="[(#SELF|parametre_url{duree,#GET{duree}|duree_zoom{moins}})]"
class="ajax">[(#CHEMIN_IMAGE{zoomout-24.png}|balise_img{<:statistiques:info_zoom:> -})]</a>
<a href="[(#SELF|parametre_url{duree,#ENV{duree,365}|duree_zoom{plus}})]"
<a href="[(#SELF|parametre_url{duree,#GET{duree}|duree_zoom{plus}})]"
class="ajax">[(#CHEMIN_IMAGE{zoomin-24.png}|balise_img{<:statistiques:info_zoom:> +})]</a>
</p>
</div>
<B_statsm>
@ -26,7 +26,7 @@
</tr>
</thead>
<tbody>
<BOUCLE_statsm(DATA){source stats_visites,mois,#ENV{duree,365},#ENV{id_article}}>
<BOUCLE_statsm(DATA){source stats_visites,mois,#GET{duree},#ENV{id_article}}>
<tr class="c_[(#CLE|affdate{l}|substr{0,3})][(#COMPTEUR_BOUCLE|=={#TOTAL_BOUCLE}|oui)c_today]">
<th title="[(#CLE|affdate{'Y/m/01'})]">[(#CLE|affdate_mois_annee)]</th>
<td class="val">#VALEUR{visites}</td>

12
prive/squelettes/inclure/stats-visites-populaires.html

@ -8,7 +8,7 @@
<B_pluspop>
<ol class='classement'>
<BOUCLE_pluspop(ARTICLES){id_article IN #GET{c}}{0,30}{doublons}>
<li[ class="(#EXPOSE)"]><a href="[(#SELF|parametre_url{id_article,#ID_ARTICLE})]" class="ajax"
<li[ class="(#EXPOSE)"]><a href="[(#SELF|parametre_url{id_article,#ID_ARTICLE})]#contenu" class="ajax"
title="<:statistiques:info_popularite_3{visites=#VISITES,popularite=#POPULARITE}|attribut_html:>">#TITRE</a></li>
</BOUCLE_pluspop>
</ol>
@ -16,7 +16,7 @@
<p class="center">[...]</p>
<ol class='classement'>
<BOUCLE_derniers(ARTICLES){popularite>0}{!par date}{0,10}{doublons}>
<li value="[(#ID_ARTICLE|array_search{#GET{c}}|plus{1})]"[ class="(#EXPOSE)"]><a href="[(#SELF|parametre_url{id_article,#ID_ARTICLE})]" class="ajax"
<li value="[(#ID_ARTICLE|array_search{#GET{c}}|plus{1})]"[ class="(#EXPOSE)"]><a href="[(#SELF|parametre_url{id_article,#ID_ARTICLE})]#contenu" class="ajax"
title="<:statistiques:info_popularite_3{visites=#VISITES,popularite=#POPULARITE}|attribut_html:>">#TITRE</a></li>
</BOUCLE_derniers>
</ol>
@ -32,14 +32,16 @@
<B_plusvisites>
<ol class='classement'>
<BOUCLE_plusvisites(ARTICLES){popularite>0}{!par visites}{0,30}>
<li value="[(#ID_ARTICLE|array_search{#GET{c}}|plus{1})]"[ class="(#EXPOSE)"]><a href="[(#SELF|parametre_url{id_article,#ID_ARTICLE})]" class="ajax"
<li value="[(#ID_ARTICLE|array_search{#GET{c}}|plus{1})]"[ class="(#EXPOSE)"]><a href="[(#SELF|parametre_url{id_article,#ID_ARTICLE})]#contenu" class="ajax"
title="<:statistiques:info_popularite_3{visites=#VISITES,popularite=#POPULARITE}|attribut_html:>">#TITRE</a></li>
</BOUCLE_plusvisites>
</ol>
</B_plusvisites>
<h4><a href='#' onclick="$(this).parent().next().toggle('fast');return false;"><:statistiques:info_comment_lire_tableau:></a></h4>
<p class="none"><:statistiques:texte_comment_lire_tableau:></p>
<br class="nettoyeur" />
<hr />
<h4><:statistiques:info_comment_lire_tableau:></h4>
<p><:statistiques:texte_comment_lire_tableau:></p>
</div>
</div>

18
prive/stats/visites.html

@ -13,14 +13,15 @@ function trace_stats_table(table, classes, options) {
// copier le titre des tableaux
titre = $table.find("caption").text();
$table.siblings('.pagination').before("<h3 class='caption'>" + titre + "</h3>");
$table
.before("<h3 class='caption'>" + titre + "</h3>")
.wrap("<div class='" + classes + "'></div>");
// mettre les visites avec un fond colore pour le graphique
$table.find("thead th:eq(1)").data({fill: true, serie: 'bar', color: '#FFD845'});
$table.find("thead th:eq(1)").data({fill: true, serie: 'bar', color: '#FFD845',lineWidth:0});
$table.find("thead th:eq(2)").data({serie: 'line', color: '#7FC4FF'});
$table.find("thead th:eq(3)").data({fill: true, serie: 'bar', color: '#A9DD3A'});
$table.find("thead th:eq(3)").data({fill: true, serie: 'bar', color: '#A9DD3A',lineWidth:0});
// mettre les previsions en premier
// (pour que les autres graph passent par dessus)
@ -34,7 +35,7 @@ function trace_stats_table(table, classes, options) {
params = {
legendeExterne:true,
legendeActions:true,
width:($('.large #page').length)?'695px':'500px', // 795px, 600px (sans le tableau de resume) ...
width:($('.large #page').length)?'755px':'560px', // 795px, 600px (sans le tableau de resume) ...
height:'250px',
modeDate:true,
zoom:true,
@ -47,6 +48,9 @@ function trace_stats_table(table, classes, options) {
}
},
flot:{
grid:{
axismargin:10
},
xaxis:{
labelWidth:45,
monthNames: [
@ -63,6 +67,9 @@ function trace_stats_table(table, classes, options) {
'[(#VAL{2000-11-01}|nom_mois)]',
'[(#VAL{2000-12-01}|nom_mois)]'
]
},
yaxis:{
position: "right"
}
},
infobulle:{show:true}
@ -79,6 +86,7 @@ function trace_stats(){
grille:{weekend:true},
flot:{
xaxis:{
timeformat:"%d %b",
minTickSize: [1, "day"]
},
bars:{barWidth:24 * 60 * 60 * 1000}
@ -94,7 +102,7 @@ function trace_stats(){
timeformat:"%b %y",
minTickSize: [1, "month"]
},
bars:{barWidth:30 * 24 * 60 * 60 * 1000 /* nb de jours... approximatif */}
bars:{barWidth:30.4 * 24 * 60 * 60 * 1000 /* nb de jours... approximatif */}
}
});

21
prive/style_prive_plugin_stats.html

@ -24,17 +24,19 @@
ol.classement {list-style:decimal;margin:0;padding:0;padding-#GET{left}:40px;margin-bottom:1.5em;}
table.visites caption,
h3.caption {font-size:1.3em;font-weight:bold;text-align:center;margin:0.5em auto; clear:both;}
table.visites caption, h3.caption {font-size:1.3em;font-weight:bold;text-align: center;margin:0.5em auto; clear:both;}
.stats_visites #contenu h3.caption {float:#GET{left};margin:0.5em auto;}
table.visites {width: 80%; margin-bottom: 1em; border-collapse: collapse; border-spacing: 0; line-height: normal;border:1px solid #999;}
table.visites a {color:#[(#GET{foncee}|couleur_foncer)];}
table.visites tr.row_first { background-color:#[(#GET{foncee}|couleur_foncer)];color:#fff;border: 1px solid #ddd; }
table.visites.info tr.row_first { background-color:#fff;color:#000;border: 1px solid #ddd; }
table.info.visites tr.row_first { background-color:#fff;color:#000;border: 1px solid #ddd; }
table.info.visites tr.odd td,table.info.visites tr.odd th { background-color:transparent; }
table.visites th, table.visites td { padding: 0.20em 0.40em; text-align: #GET{left}; border: 1px solid #ddd; }
table.visites th { vertical-align: bottom; font-weight: bold; }
table.visites.info th { vertical-align: top; }
table.visites tbody th { font-weight: normal; }
table.visites .on th { font-weight: bold; }
table.visites td { vertical-align: top; }
table.visites td.val, table.visites td.mean, table.visites td.cumul { text-align:center; }
@ -50,14 +52,17 @@ table#visites tr.c_recap th {background-color:#[(#GET{foncee}|couleur_foncer)];c
/* graphique flot */
.graphique{clear:both; overflow:hidden; margin-bottom:2em;}
.graphResult{float:#GET{left};}
.graphInfo{float:#GET{left}; margin:0.5em;}
.graphInfo td.legendLabel { padding-left:.5em; padding-right:1em; }
.graphLegend{margin-bottom:0.5em; }
.graphResult-wrap {padding: 10px 25px;float:#GET{left};}
.graphResult{}
.graphInfo{float:#GET{left}; clear:#GET{left};margin-#GET{left}:20px;}
.graphInfo td {padding: 5px;}
.graphInfo td.legendLabel { padding-left:0; padding-right:1em; vertical-align: top;}
.graphLegend{margin-top:0.5em; }
.graphVignette{}
.graphique .tickLabels {font-size: 11px !important;line-height: 14px;}
.graphLegend .legendColorBox div{width:14px; height:10px;}
.graphLegend .cacher .legendColorBox div div{position:absolute; left:-3000em;}
.graphLegend .legendColorBox.cacher div div{position:absolute; left:-3000em;}
.tooltip_statistiques{

Loading…
Cancel
Save