OSDN Git Service

任意の期間の資材グラフを表示できるようにする
[kancollesniffer/KancolleSniffer.git] / LogViewer / index.html
1 <!DOCTYPE html>
2 <html lang="ja">
3 <head>
4 <meta charset="utf-8">
5 <title>各種報告書 - KancolleSniffer</title>
6
7 <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
8 <script src="//cdnjs.cloudflare.com/ajax/libs/datatables/1.10.7/js/jquery.dataTables.min.js"></script>
9 <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/datatables/1.10.7/css/jquery.dataTables.min.css">
10 <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.min.js"></script>
11 <script src="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
12 <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css">
13 <script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js"></script>
14 <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
15 <link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
16 <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/i18n/datepicker-ja.min.js"></script>
17 <style>
18 body {
19     font-family:'Lucida Grande','Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
20     line-height: 1.5;
21     font-size: 14px;
22 }
23 .tab {overflow: hidden; list-style-type: none; margin: 0em 0em 2em 1em; padding: 0em;}
24 .tab li {background: #eee; padding: 0.3em 1.5em; float: left; margin-right: 2px;}
25 .tab1 li {padding: 0.3em 1em;}
26 .tab li.select {background: #ccc;}
27 .contents {list-style-type: none; margin: 0em; padding: 0em;}
28 .hide {display: none;}
29 #loading {
30     width: 48px;
31     height: 48px;
32     display: none;
33     position: fixed;
34     top: 50%;
35     left: 50%;
36     margin-top: -24px;
37     margin-left: -24px;
38     z-index: 100;
39 }
40 </style>
41
42 </head>
43 <body>
44 <script>
45 function showLog()
46 {
47     var query = "?from=" + moment().subtract(1, 'months').valueOf();
48     if ($('input[name=term]:eq(1)').prop('checked')) {
49         from = $('#term_from').datepicker("getDate");
50         to = $('#term_to').datepicker("getDate");
51         if (from != null)
52             query = "?from=" + from.valueOf();
53         if (to != null)
54             query += "&to=" + (to.valueOf() + 3600 * 24 * 1000);
55     }
56     var jsons = [
57         "海戦・ドロップ報告書.json",
58         "海戦・ドロップ報告書.json",
59         "遠征報告書.json",
60         "開発報告書.json",
61         "建造報告書.json",
62         "改修報告書.json",
63         "資材ログ.json"
64     ];
65     $('#loading').show();
66     var url = jsons[selectedTable] + query;
67     $('#log' + selectedTable).DataTable().ajax.url(url).load();
68 }
69
70 var tables = 7;
71
72 function initTables()
73 {
74     for (var t = 0; t < tables; t++) {
75         var opts = {
76             destroy: true,
77             deferRender: true,
78             stateSave: true,
79             order: [[0, "desc"]],
80             pageLength: 50,
81             lengthMenu: [[50, 100, 200, -1],[50, 100, 200, "All"]],
82             drawCallback: function () {
83                 $('#loading').hide();
84             }
85         };
86         if (t == 0) {
87             opts.columns = [{data: 0}, {data: 1}, {data: 2}, {data: 3}, {data: 4}, {data: 9}, {data: 10}];
88         } else if (t == 1) {
89             var entries = [];
90             for (i = 0; i < 35; i++) {
91                 if (i == 9 || i == 10)
92                     continue;
93                 entries.push({data: i})
94             }
95             opts.columns = entries;
96         }
97         $('#log' + t).dataTable(opts);
98     }
99 }
100
101 const timeFormat = "YYYY-MM-DD HH:mm:ss";
102 function parseDate(d)
103 {
104     return moment(d, timeFormat);
105 }
106
107 function toString(d)
108 {
109     return d.format(timeFormat);
110 }
111
112 function to5am(tick)
113 {
114     return tick - tick % (3600 * 24000) - 3600 * 4000;
115 }
116
117 function pickChartData(data, range)
118 {
119     var newdata = [];
120     var ticks = [];
121     var grid = [];
122     var first = moment(data[0][0]).valueOf();
123     var last = moment(data[data.length - 1][0]).valueOf();
124     var interval, tickInterval, lastTick;
125     const oneDay = 3600 * 24 * 1000;
126     switch (range) {
127     case 0:
128         first = moment(last).subtract(24, 'hours').valueOf();
129         break;
130     case 1:
131         first = moment(last).subtract(7, 'days').valueOf();
132         break;
133     case 2:
134         first = moment(last).subtract(1, 'months').valueOf();
135         break;
136     case 3:
137         first = moment(data[0][0]).valueOf();
138         break;
139     case 4:
140         fromDate = $('#chart_from').datepicker("getDate");
141         toDate = $('#chart_to').datepicker("getDate");
142         if (fromDate == null || toDate == null)
143             return { data: [], tick: [], grid: [] };
144         from = fromDate.valueOf() + 3600 * 5000;
145         to = toDate.valueOf() + oneDay + 3600 * 5000;
146         first = Math.max(first, from);
147         last = Math.min(last, to);
148         break;
149     }
150     if (last <= first + oneDay) {
151         interval = 1000;
152         tickInterval = 3600 * 1000;
153         lastTick = last - last % tickInterval;
154     } else if (last <= first + oneDay * 21) {
155         interval = 1000;
156         tickInterval = oneDay;
157         lastTick = to5am(last);
158     } else if (last <= first + oneDay * 63) {
159         interval = 3600 * 2000;
160         tickInterval = oneDay * 7;
161         lastTick = to5am(moment(last).day(1).valueOf());
162     } else {
163         interval = 3600 * 12000;
164         tickInterval = oneDay * 14;
165         lastTick = to5am(moment(last).day(1).valueOf());
166     }
167     var last_data;
168     for (var i = data.length - 1; i >= 0; i--) {
169         var row = data[i];
170         var date = parseDate(row[0]).valueOf();
171         if (date > first) {
172             if (date <= last) {
173                 var v = date - date % interval;
174                 if (last_data != v) {
175                     newdata.unshift(row);
176                     last_data = v;
177                 }
178             }
179         } else {
180             break;
181         }
182     }
183     for (var tick = lastTick; tick > last_data; tick -= tickInterval)
184     {
185         var str = toString(moment(tick));
186         ticks.unshift(str);
187         grid.unshift({value: str});
188     }
189     return { data: newdata, tick: ticks, grid: grid };
190 }
191
192 var selectedTable = 0;
193 var selectedRange = 0;
194
195 function drawChart(data)
196 {
197     if (data == null) {
198         $('#loading').show();
199         $.get("./資材ログ.json?time=" + Date.now(), function (data) { drawChart(data);}, "json");
200         return;
201     }
202     picked = pickChartData(data.data, selectedRange);
203     var header = ["日付","燃料","弾薬","鋼材","ボーキ","高速建造材","高速修復材","開発資材","改修資材"];
204     picked.data.unshift(header);
205     var chart = c3.generate({
206         bindto: '#chart',
207         size: {
208             height: 400,
209             width: 800
210         },
211         data: {
212             x: '日付',
213             xFormat: '%Y-%m-%d %X',
214             rows: picked.data,
215             axes: {
216                 燃料: 'y',
217                 弾薬: 'y',
218                 鋼材: 'y',
219                 ボーキ: 'y',
220                 高速建造材: 'y2',
221                 高速修復材: 'y2',
222                 開発資材: 'y2',
223                 改修資材: 'y2'
224             }
225         },
226         point: {
227             show: false
228         },
229         tooltip: {
230             show: $('#tooltip').prop('checked')
231         },
232         grid: {
233             x: {
234                 lines: picked.grid
235             }
236         },
237         axis: {
238             x: {
239                 type: 'timeseries',
240                 tick: {
241                     rotate: 30,
242                     format: function (x) { return moment(x).format("MM-DD HH:mm"); },
243                     values: picked.tick
244                 },
245                 height: 60
246             },
247             y2: {
248                 show: true
249             }
250         },
251         onrendered: function () { $('#loading').hide(); }
252     });
253 }
254
255 function setSortieStat(data) {
256     if (!data) {
257         $('#loading').show();
258         var from = moment().subtract(1, 'months').valueOf();
259         $.get("./海戦・ドロップ報告書.json?time=" + Date.now() + "&from=" + from, function (data) { setSortieStat(data.data);}, "json");
260         return;
261     }
262     var r = {
263         day: {stat: {}},
264         week: {stat: {}},
265         month: {stat: {}}
266     };
267     var initStat = function () { return {start:"-", S:0, A:0, B:0, C:0, D:0} };
268     now = moment();
269     r.day.begin = moment(now).hour(5).minute(0);
270     if (now.hour() < 5) {
271         r.day.begin.subtract(1, 'days');
272     }
273     r.week.begin = moment(now).day(1).hour(5).minute(0);
274     if (now.day() == 0 || now.day() == 1 && now.hour() < 5) {
275         r.week.begin.subtract(1, 'weeks');
276     }
277     r.month.begin = moment(now).date(1).hour(5).minute(0);
278     if (now.date() == 1 && now.hours() < 5) {
279         r.month.begin.subtract(1, 'months');
280     }
281     for (var i = 0; i < data.length; i++) {
282         var row = data[i];
283         var date = moment(row[0]);
284         var map = row[1];
285         var isBoss = row[3].indexOf("ボス") != -1;
286         var isStart = row[3].indexOf("出撃") != -1;
287         var res = row[4];
288         if (res == "E")
289             res = "D";
290         for (var term in r) {
291             to = r[term];
292             if (to.begin.isAfter(date))
293                 continue;
294             for (var b = 0; b < 4; b++) {
295                 var name = b < 2 ? "合計" : map;
296                 if (b == 1 || b == 3) {
297                     if (!isBoss)
298                         continue;
299                     name = name + " - ボス";
300                 }
301                 var mo = to.stat[name];
302                 if (!mo) {
303                     mo = to.stat[name] = initStat();
304                     if (name == "合計")
305                         to.stat["合計 - ボス"] = initStat();
306                 }
307                 mo[res]++;
308                 if ((b == 0 || b == 2) && isStart)
309                 {
310                     if (mo.start == "-")
311                         mo.start = 0;
312                     mo.start++
313                 }
314             }
315         }
316     }
317     for (term in r) {
318         var table = [];
319         for (map in r[term].stat)
320         {
321             var e = r[term].stat[map];
322             e.map = map;
323             table.push(e);
324         }
325         var dt = $("#sortie_stat_" + term).DataTable();
326         dt.clear();
327         dt.rows.add(table).draw();
328     }
329     $('#loading').hide();
330 }
331
332 function initSortieStat()
333 {
334     var terms = ['day', 'week', 'month'];
335     for (var i = 0; i < terms.length; i++) {
336         $("#sortie_stat_" + terms[i]).dataTable({
337             paging: false,
338             searching: false,
339             ordering: false,
340             columns: [
341                 { data: "map" },
342                 { data: "start" },
343                 { data: "S" },
344                 { data: "A" },
345                 { data: "B" },
346                 { data: "C" },
347                 { data: "D" }
348             ]
349         });
350     }
351 }
352
353 function selectTopTab(i)
354 {
355     var chart = tables;
356     if (i < tables) {
357         selectedTable = i;
358         showLog();
359     } else if (i == chart) {
360         drawChart();
361     } else if (i == chart + 1) {
362         setSortieStat();
363     }
364     if (i < tables)
365         $('#term').show();
366     else
367         $('#term').hide();
368     var tab = $('.tab0 li');
369     tab.removeClass('select');
370     tab.eq(i).addClass('select');
371     $('.contents .hide').hide();
372     $('.contents .hide').eq(i).show();
373 }
374
375 function initAction()
376 {
377     $('.tab0 li').click(function() {
378         var tab = $('.tab0 li');
379         var i = tab.index(this)
380         selectTopTab(i);
381         sessionStorage.setItem('prevTab', i);
382     });
383     $('.tab1 li').click(function() {
384         var tab = $('.tab1 li');
385         var i = tab.index(this);
386         selectedRange = i;
387         drawChart();
388         tab.removeClass('select');
389         tab.eq(i).addClass('select');
390         sessionStorage.setItem('prevRange', i);
391     });
392     $('#tooltip').change(function() {
393         drawChart();
394     });
395 }
396
397 function initTableDatePicker()
398 {
399     $('#term_from').datepicker({
400         defaultDate: moment().subtract(1, 'months').toDate(),
401         onClose: function() {$('input[name=term]').val(['1'])}
402     });
403     $('#term_to').datepicker({
404         onClose: function() {$('input[name=term]').val(['1'])}
405     });
406     $('#term_apply').click(showLog);
407 }
408
409 function initChartDatePicker()
410 {
411     $('#chart_from').datepicker({
412         onClose: function() {if (selectedRange == 4) drawChart();}
413     })
414     $('#chart_to').datepicker({
415         onClose: function() {if (selectedRange == 4) drawChart();}
416     });
417 }
418
419 $(function() {
420     $.fn.dataTable.ext.errMode = 'throw';
421     initAction();
422     initTableDatePicker();
423     initChartDatePicker();
424     $('table').addClass('display compact cell-border');
425     initTables();
426     initSortieStat();
427     var range = sessionStorage.getItem('prevRange');
428     selectedRange = range == null ? 0 : +range;
429     $('.tab1 li').eq(range).addClass('select');
430     var prev = sessionStorage.getItem('prevTab');
431     selectTopTab(prev == null ? 0 : +prev);
432 });
433 </script>
434
435 <div id="loading"><img src="http://kancollesniffer.osdn.jp/ajax-loader.gif" alt="読み込み中..."></div>
436
437 <ul class="tab tab0">
438 <li>ドロップ</li>
439 <li>海戦</li>
440 <li>遠征</li>
441 <li>開発</li>
442 <li>建造</li>
443 <li>改修</li>
444 <li>資材</li>
445 <li>資材グラフ</li>
446 <li>出撃統計</li>
447 </ul>
448
449 <form id="term">
450 <p>
451 <label><input type="radio" name="term" value="0" checked="checked">直近一か月</label>
452 <label><input type="radio" name="term" value="1">期間指定: </label>
453 <input type="text" id="term_from" style="width: 7em">~<input type="text" id="term_to" style="width: 7em">
454 <input type="button" id="term_apply" value="適用">
455 </p>
456 </form>
457
458 <ul class="contents">
459 <li class="hide">
460 <table id="log0">
461 <thead>
462 <tr><th>日付</th><th>海域</th><th>マス</th><th>ボス</th><th>ランク</th><th>ドロップ艦種</th><th>ドロップ艦娘</th></tr>
463 </thead>
464 </table>
465
466 <li class="hide">
467 <table id="log1">
468 <thead>
469 <tr><th>日付</th><th>海域</th><th>マス</th><th>ボス</th><th>ランク</th><th>艦隊行動</th><th>味方陣形</th><th>敵陣形</th><th>敵艦隊</th><th>味方艦1</th><th>味方艦1HP</th><th>味方艦2</th><th>味方艦2HP</th><th>味方艦3</th><th>味方艦3HP</th><th>味方艦4</th><th>味方艦4HP</th><th>味方艦5</th><th>味方艦5HP</th><th>味方艦6</th><th>味方艦6HP</th><th>敵艦1</th><th>敵艦1HP</th><th>敵艦2</th><th>敵艦2HP</th><th>敵艦3</th><th>敵艦3HP</th><th>敵艦4</th><th>敵艦4HP</th><th>敵艦5</th><th>敵艦5HP</th><th>敵艦6</th><th>敵艦6HP</th></tr>
470 </thead>
471 </table>
472
473 <li class="hide">
474 <table id="log2">
475 <thead>
476 <tr><th>日付</th><th>結果</th><th>遠征</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>開発資材</th><th>高速修復材</th><th>高速建造材</th></tr>
477 </thead>
478 </table>
479
480 <li class="hide">
481 <table id="log3">
482 <thead>
483 <tr><th>日付</th><th>開発装備</th><th>種別</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>秘書艦</th><th>司令部Lv</th></tr>
484 </thead>
485 </table>
486
487 <li class="hide">
488 <table id="log4">
489 <thead>
490 <tr><th>日付</th><th>種類</th><th>名前</th><th>艦種</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>開発資材</th><th>空きドック</th><th>秘書艦</th><th>司令部Lv</th></tr>
491 </thead>
492 </table>
493
494 <li class="hide">
495 <table id="log5">
496 <thead>
497 <tr><th>日付</th><th>改修装備</th><th>レベル</th><th>成功</th><th>確実化</th><th>消費装備</th><th>消費数</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>開発資材</th><th>改修資材</th><th>秘書艦</th><th>二番艦</th></tr>
498 </thead>
499 </table>
500
501 <li class="hide">
502 <table id="log6">
503 <thead>
504 <tr><th>日付</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>高速建造材</th><th>高速修復材</th><th>開発資材</th><th>改修資材</th></tr>
505 </thead>
506 </table>
507
508 <li class="hide">
509 <ul class="tab tab1" style="float: left; margin-right: 2px;">
510 <li>一日</li>
511 <li>一週間</li>
512 <li>一か月</li>
513 <li>すべて</li>
514 <li>期間指定</li>
515 </ul>
516 <div style="padding: 0.2em 0em;">
517 <input type="text" id="chart_from" style="width: 7em">~<input type="text" id="chart_to" style="width: 7em">
518 <label><input type="checkbox" id="tooltip" value="" style="margin-left: 2em;">ツールチップ</label>
519 </div>
520 <div id="chart" style="clear: both; width: 800px; margin: 1em;"></div>
521
522 <li class="hide">
523 <h3>今日</h3>
524 <table id="sortie_stat_day">
525 <thead>
526 <tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th></tr>
527 </thead>
528 </table>
529
530 <h3>今週</h3>
531 <table id="sortie_stat_week">
532 <thead>
533 <tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th></tr>
534 </table>
535
536 <h3>今月</h3>
537 <table id="sortie_stat_month">
538 <thead>
539 <tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th></tr>
540 </table>
541 </ul>
542 </body>
543 </html>