]> de.git.xonotic.org Git - xonotic/xonstat.git/blob - xonstat/templates/player_info.mako
Refactor the damage graph.
[xonotic/xonstat.git] / xonstat / templates / player_info.mako
1 <%inherit file="base.mako"/>
2 <%namespace name="nav" file="nav.mako" />
3 <%namespace file="accuracy.mako" import="accuracy" />
4 <%namespace file="accuracy_graph.mako" import="accuracy_graph" />
5 <%namespace file="damage_graph.mako" import="damage_graph" />
6
7 <%block name="navigation">
8 ${nav.nav('players')}
9 </%block>
10
11 <%block name="css">
12 ${parent.css()}
13 <link href="/static/css/sprites.css" rel="stylesheet">
14 </%block>
15
16 <%block name="js">
17 ${parent.js()}
18 % if player is not None:
19 <script src="/static/js/jquery.flot.min.js"></script>
20 <script type="text/javascript">
21 $(function () {
22   $('#gbtab li').click(function(e) {
23     e.preventDefault();
24     $(this).tab('show');
25   })
26
27   $('#gbtab a:first').tab('show');
28 })
29 </script>
30
31 <script type="text/javascript">
32 $(function () {
33     // plot the accuracy graph
34     function plot_acc_graph(data) {
35     var games = new Array();
36     var avgs = new Array();
37     var accs = new Array();
38
39   var i=0;
40   for(i=0; i < data.games; i++) {
41     avgs[i] = [i, data.avg];
42     accs[i] = [i, data.accs[i][1]];
43     game_link = '/game/' + data.accs[i][0];
44     j = data.games - i;
45     games[i] = [i, '<a href="' + game_link + '">' + j + '</a>'];
46   }
47
48   $.plot(
49     $("#acc-graph"), 
50     [ { label: 'average', data: avgs, hoverable: true, clickable: false }, 
51       { label: 'accuracy', data: accs, lines: {show:true}, points: {show:false}, hoverable: true, clickable: true }, ],
52       { yaxis: {ticks: 10, min: 0, max: 100 },
53         xaxis: {ticks: games},
54         grid: { hoverable: true, clickable: true },
55       });
56 }
57
58 // plot the damage graph
59 function plot_dmg_graph(data) {
60   var games = new Array();
61   var avgs = new Array();
62   var dmgs = new Array();
63
64 var i=0;
65 for(i=0; i < data.games; i++) {
66   avgs[i] = [i, data.avg];
67   dmgs[i] = [i, data.dmgs[i][1]];
68   game_link = '/game/' + data.dmgs[i][0];
69   j = data.games - i;
70   games[i] = [i, '<a href="' + game_link + '">' + j + '</a>'];
71 }
72
73 $.plot(
74   $("#dmg-graph"), 
75   [ { label: 'average', data: avgs, hoverable: true, clickable: false }, 
76     { label: 'efficiency', data: dmgs, lines: {show:true}, points: {show:false}, hoverable: true, clickable: true }, ],
77     { yaxis: {ticks: 10, min: 0 },
78       xaxis: {ticks: games},
79       grid: { hoverable: true, clickable: true },
80     });
81           }
82
83           function showTooltip(x, y, contents) {
84             $('<div id="tooltip">' + contents + '</div>').css( {
85               position: 'absolute',
86               display: 'none',
87               top: y - 35,
88               left: x + 10,
89               border: '1px solid #fdd',
90               padding: '2px',
91               'background-color': '#333333',
92               opacity: 0.80
93             }).appendTo("body").fadeIn(200);
94           }
95
96           var previousPoint = null;
97           var previousLabel = null;
98           $('#acc-graph').bind("plothover", function (event, pos, item) {
99             if (item) {
100               if ((previousLabel != item.series.label) || (previousPoint != item.dataIndex)) {
101                 previousLabel = item.series.label;
102                 previousPoint = item.dataIndex;
103
104                 $("#tooltip").remove();
105                 var x = item.datapoint[0].toFixed(2),
106                 y = item.datapoint[1].toFixed(2);
107
108                 showTooltip(item.pageX, item.pageY, y + "%");
109               }
110             }
111             else {
112               $("#tooltip").remove();
113               previousPoint = null;
114               previousLabel = null;
115             }
116           });
117
118           $('#dmg-graph').bind("plothover", function (event, pos, item) {
119             if (item) {
120               if ((previousLabel != item.series.label) || (previousPoint != item.dataIndex)) {
121                 previousPoint = item.dataIndex;
122                 previousLabel = item.series.label;
123
124                 $("#tooltip").remove();
125                 var x = item.datapoint[0].toFixed(2),
126                 y = item.datapoint[1].toFixed(2);
127
128                 showTooltip(item.pageX, item.pageY, y);
129               }
130             }
131             else {
132               $("#tooltip").remove();
133               previousPoint = null;
134               previousLabel = null;
135             }
136           });
137
138 // bind click events to the weapon images
139 $(".acc-weap").click(function () {
140     var dataurl = $(this).find('a').attr('href');
141
142           $('.accuracy-nav').find('.weapon-active').removeClass('weapon-active');
143           $(this).addClass('weapon-active');
144
145           $.ajax({
146             url: dataurl,
147             method: 'GET',
148             dataType: 'json',
149             success: plot_acc_graph
150           });
151 });
152
153 $(".dmg-weap").click(function () {
154   var dataurl = $(this).find('a').attr('href');
155
156   $('.damage-nav').find('.weapon-active').removeClass('weapon-active');
157   $(this).addClass('weapon-active');
158
159   $.ajax({
160     url: dataurl,
161     method: 'GET',
162     dataType: 'json',
163     success: plot_dmg_graph
164   });
165 });
166
167 // populate the graphs with the default weapons
168 $.ajax({
169 url: '${request.route_url("player_accuracy", id=player.player_id)}',
170 method: 'GET',
171 dataType: 'json',
172 success: plot_acc_graph
173 });
174
175 $.ajax({
176   url: '${request.route_url("player_damage", id=player.player_id)}',
177   method: 'GET',
178   dataType: 'json',
179   success: plot_dmg_graph
180 });
181 })
182 </script>
183 % endif
184 </%block>
185
186 <%block name="title">
187 Player Information
188 </%block>
189
190
191 % if player is None:
192 <h2>This player is so good we couldn't find him!</h2>
193 <p>Seriously though, he probably doesn't exist...just a figment of your imagination. Carry on then!</p>
194
195 % else:
196 <div class="row">
197   <div class="span12">
198     <h2>
199       ${player.nick_html_colors()|n}
200     </h2>
201     <h4>
202       <i><span class="abstime" data-epoch="${player.epoch()}" title="${player.create_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">Joined ${player.joined_pretty_date()}</span> (player #${player.player_id})</i>
203       % if cake_day:
204       <img src="/static/images/icons/24x24/cake.png" title="Happy cake day!" />
205       % endif
206     </h4>
207   </div>
208 </div>
209
210 <div class="row">
211   <div id="gbtabcontainer" class="tabbable tabs-below">
212     <div class="tab-content">
213       % for g in games_played:
214       % if not g.game_type_cd in ['cq']:
215       <div class="tab-pane fade in 
216         % if g.game_type_cd == 'overall':
217         active
218         % endif
219         " id="tab-${g.game_type_cd}">
220         <div class="span5">
221           <p>
222           % if g.game_type_cd in overall_stats:
223           Last Played: <small><span class="abstime" data-epoch="${overall_stats[g.game_type_cd].last_played_epoch}" title="${overall_stats[g.game_type_cd].last_played.strftime('%a, %d %b %Y %H:%M:%S UTC')}"> ${overall_stats[g.game_type_cd].last_played_fuzzy} </span> <br /></small>
224           % else:
225           <small><br /></small>
226           % endif
227
228           Games Played: 
229           % if g.game_type_cd == 'overall':
230           <small><a href="${request.route_url("player_game_index", player_id=player.player_id)}" title="View recent games">
231           % else:
232           <small><a href="${request.route_url("player_game_index", player_id=player.player_id, _query={'type':g.game_type_cd})}" title="View recent ${overall_stats[g.game_type_cd].game_type_descr} games">
233           % endif
234           ${g.games}</a> <br /></small>
235
236           Playing Time: <small>${overall_stats[g.game_type_cd].total_playing_time} <br /></small>
237
238           % if g.game_type_cd in fav_maps:
239           Favorite Map: <small><a href="${request.route_url("map_info", id=fav_maps[g.game_type_cd].map_id)}" title="Go to the detail page for this map">${fav_maps[g.game_type_cd].map_name}</a> <br /></small>
240           % else:
241           <small><br /></small>
242           % endif
243           
244           % if g.game_type_cd == 'ctf':
245           % if overall_stats[g.game_type_cd].total_captures is not None:
246           <small><a href="${request.route_url("player_captimes", id=player.player_id)}">Fastest flag captures...</a> <br /></small>
247           % else:
248           <small><br /></small>
249           % endif
250           % else:
251           <small><br /></small>
252           % endif
253           
254           </p>
255         </div>
256         <div class="span5">
257           <p>
258           Win Percentage: <small>${round(g.win_pct,2)}% (${g.wins} wins, ${g.losses} losses) <br /></small>
259
260           % if g.game_type_cd in overall_stats:
261           % if overall_stats[g.game_type_cd].k_d_ratio is not None:
262           Kill Ratio: <small>${round(overall_stats[g.game_type_cd].k_d_ratio,2)} (${overall_stats[g.game_type_cd].total_kills} kills, ${overall_stats[g.game_type_cd].total_deaths} deaths) <br /></small>
263           % endif
264           % else:
265           <small><br /></small>
266           % endif
267
268           % if g.game_type_cd in elos:
269           % if g.game_type_cd == 'overall':
270           Best Elo: <small>${round(elos[g.game_type_cd].elo,2)} (${elos[g.game_type_cd].game_type_cd}, ${elos[g.game_type_cd].games} games) <br /></small>
271           % else:
272           Elo: <small>${round(elos[g.game_type_cd].elo,2)} (${elos[g.game_type_cd].games} games) <br /></small>
273           % endif
274           % else:
275           <small><br /></small>
276           % endif
277
278           % if g.game_type_cd in ranks:
279           % if g.game_type_cd == 'overall':
280           Best Rank: <small>${ranks[g.game_type_cd].rank} of ${ranks[g.game_type_cd].max_rank} (${ranks[g.game_type_cd].game_type_cd}, percentile: ${round(ranks[g.game_type_cd].percentile,2)}) <br /></small>
281           % else:
282           Rank: 
283           <small>
284             <a href="
285               % if ranks[g.game_type_cd].rank % 20 == 0:
286                 ${request.route_url('rank_index', game_type_cd=g.game_type_cd, _query={'page':ranks[g.game_type_cd].rank/20})}
287
288               % else:
289                 ${request.route_url('rank_index', game_type_cd=g.game_type_cd, _query={'page':ranks[g.game_type_cd].rank/20+1})}
290
291               % endif
292             " title="Player rank page for this player">
293             ${ranks[g.game_type_cd].rank} of ${ranks[g.game_type_cd].max_rank}</a>
294             (percentile: ${round(ranks[g.game_type_cd].percentile,2)})
295             <br />
296           </small>
297           % endif
298           % else:
299           <small><br /></small>
300           % endif
301
302           % if g.game_type_cd == 'ctf':
303           % if overall_stats[g.game_type_cd].cap_ratio is not None:
304           Cap Ratio: <small>${round(overall_stats[g.game_type_cd].cap_ratio,2)} (${overall_stats[g.game_type_cd].total_captures} captures, ${overall_stats[g.game_type_cd].total_pickups} pickups) <br /></small>
305           % else:
306           <small><br /></small>
307           % endif
308           % else:
309           <small><br /></small>
310           % endif
311           </p>
312         </div>
313       </div>
314       % endif
315       % endfor
316     </div>
317   </div>
318 </div>
319 <div class="row">
320   <div class="span12">
321     <ul id="gbtab" class="nav nav-tabs">
322       % for g in games_played:
323       <li>
324       <a href="#tab-${g.game_type_cd}" data-toggle="tab" alt="${g.game_type_cd}" title="${overall_stats[g.game_type_cd].game_type_descr}">
325         <span class="sprite sprite-${g.game_type_cd}"> </span><br />
326         ${g.game_type_cd} <br />
327         <small>(${g.games})</small>
328       </a>
329       </li>
330       % endfor
331     </ul>
332   </div>
333 </div>
334
335 ### ACCURACY GRAPH
336 ${accuracy_graph(recent_weapons)}
337
338 ### DAMAGE GRAPH
339 ${damage_graph(recent_weapons)}
340
341 ##### RECENT GAMES (v2) ####
342 % if recent_games:
343 <div class="row">
344   <div class="span12">
345     <h3>Recent Games</h3>
346     <table class="table table-hover table-condensed">
347       <thead>
348         <tr>
349           <th></th>
350           <th>Type</th>
351           <th>Server</th>
352           <th>Map</th>
353           <th>Result</th>
354           <th>Played</th>
355           <th>Elo</th>
356         </tr>
357       </thead>
358       <tbody>
359       % for rg in recent_games:
360       <tr>
361         <td class="tdcenter"><a class="btn btn-primary btn-small" href="${request.route_url('game_info', id=rg.game_id)}" title="View detailed information about this game">view</a></td>
362         <td class="tdcenter"><span class="sprite sprite-${rg.game_type_cd}" alt="${rg.game_type_cd}" title="${rg.game_type_descr}"></span></td>
363         <td><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
364         <td><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the detail page for this map">${rg.map_name}</a></td>
365         <td>
366           % if rg.team != None:
367           % if rg.team == rg.winner:
368           Win
369           % else:
370           Loss
371           % endif
372           % else:
373           % if rg.rank == 1:
374           Win
375           % else:
376           Loss (#${rg.rank})
377           % endif
378           % endif
379         </td>
380         <td><span class="abstime" data-epoch="${rg.epoch}" title="${rg.start_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${rg.fuzzy_date}</span></td>
381         <td class="tdcenter">
382           <a href="${request.route_url('game_info', id=rg.game_id, _query={'show_elo':1})}" title="View detailed information about this game">
383             % if rg.elo_delta is not None:
384             % if round(rg.elo_delta,2) > 0:
385             <span class="eloup" title="Elo went up by ${round(rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-up"></i></span>
386             % elif round(rg.elo_delta,2) < 0:
387             <span class="elodown" title="Elo went down by ${round(-rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-down"></i></span>
388             % else:
389             <span class="eloneutral" title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
390             % endif
391             % else:
392             <span class="eloneutral" title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
393             % endif
394           </a>
395         </td>
396       </tr>
397       % endfor
398       </tbody>
399     </table>
400     % if total_games > 10:
401     <p><a href="${request.route_url("player_game_index", player_id=player.player_id, page=1)}" title="Game index for ${player.stripped_nick}">More...</a></p>
402     % endif
403   </div>
404 </div>
405 % endif
406 % endif