6 <li each={name, i in mainTabs} class={select: mainTab === i} onclick={parent.changeTab}>{name}</li>
10 /* global moment, c3, opts */
12 this.mainTab = +sessionStorage.getItem('prevTab');
13 opts.observable.trigger("mainTabChanged", this.mainTab);
15 this.changeTab = function(e) {
16 this.mainTab = e.item.i;
17 sessionStorage.setItem('prevTab', e.item.i);
18 opts.observable.trigger("mainTabChanged", e.item.i);
24 <div id="term" show={enabled}>
25 <ul class="tab tabsub" style="float: left; margin-right: 0.2em">
26 <li each={name, i in rangeTabs} class={select: opts.logRange.val === i} onclick={parent.rangeTabChange}>{name}</li>
28 <div style="padding: 0.2em 0;">
29 <input type="text" id="term_from" style="width: 7em">~<input type="text" id="term_to" style="width: 7em">
46 opts.observable.on("mainTabChanged", function(idx) {
47 self.update({enabled: idx >= 0 && idx < self.logTables});
50 var val = sessionStorage.getItem('logRange');
51 opts.logRange.val = val === null ? 2 : +val;
53 this.init = function() {
54 $('#term_from').datepicker({
56 if (opts.logRange.val === 4)
57 opts.observable.trigger("logRangeChanged");
60 $('#term_to').datepicker({
62 if (opts.logRange.val === 4)
63 opts.observable.trigger("logRangeChanged");
68 this.on("mount", this.init);
70 this.rangeTabChange = function(e) {
71 sessionStorage.setItem("logRange", e.item.i);
72 opts.logRange.val = e.item.i;
73 opts.observable.trigger("logRangeChanged");
80 <div each={header, i in tables} show={mainTab === i}>
81 <table class="display compact cell-border" id={"log" + i}>
90 "<th>日付</th><th>海域</th><th>マス</th><th>ボス</th><th>ランク</th><th>ドロップ艦種</th><th>ドロップ艦娘", // ドロップ
91 "<th>日付</th><th style=\"min-width: 3.2em;\">海域</th><th>マス</th><th>ボス</th><th>ランク</th><th>艦隊行動</th><th>味方陣形</th><th>敵陣形</th><th style=\"min-width: 3.2em;\">敵艦隊</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>大破艦</ht><th style=\"min-width: 2.2em;\">敵艦1</th><th>敵艦1HP</th><th style=\"min-width: 2.2em;\">敵艦2</th><th>敵艦2HP</th><th style=\"min-width: 2.2em;\">敵艦3</th><th>敵艦3HP</th><th style=\"min-width: 2.2em;\">敵艦4</th><th>敵艦4HP</th><th style=\"min-width: 2.2em;\">敵艦5</th><th>敵艦5HP</th><th style=\"min-width: 2.2em;\">敵艦6</th><th>敵艦6HP</th><th>味方制空値</th><th>敵制空値</th><th>制空状態</th>", // 海戦
92 "<th>日付</th><th>結果</th><th>遠征</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>開発資材</th><th>高速修復材</th><th>高速建造材</th>", // 遠征
93 "<th>日付</th><th>開発装備</th><th>種別</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>秘書艦</th><th>司令部Lv</th>", // 開発
94 "<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>", // 建造
95 "<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>", // 改修
96 "<th>日付</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>高速建造材</th><th>高速修復材</th><th>開発資材</th><th>改修資材</th>" // 戦果
109 this.on("mount", function() {
110 var records = this.root.querySelectorAll("tr");
111 for (var i = 0; i < records.length; i++)
112 records[i].innerHTML = this.tables[i];
119 opts.observable.on("mainTabChanged", function(idx) {
120 self.update({mainTab: idx});
124 opts.observable.on("logRangeChanged", function() {
128 this.init = function() {
129 for (var t = 0; t < this.tables.length; t++) {
134 order: [[0, "desc"]],
136 lengthMenu: [[50, 100, 200, -1], [50, 100, 200, "All"]],
137 drawCallback: function() {
138 $('#loading').hide();
142 opts.columns = [{ data: 0 }, { data: 1 }, { data: 2 }, { data: 3 }, { data: 4 }, { data: 9 }, { data: 10 }];
143 } else if (t === 1) {
145 for (var i = 0; i < 39; i++) {
146 if (i === 9 || i === 10)
148 entries.push({ data: i });
150 opts.columns = entries;
152 $('#log' + t).dataTable(opts);
156 this.show = function() {
157 if (this.mainTab >= this.jsons.length)
161 var query = "?from=";
162 switch (opts.logRange.val){
164 from = now.clone().startOf('day').hours(5);
166 from.subtract(1, 'days');
167 query += from.valueOf();
170 from = now.clone().startOf('week').hours(5);
171 if (now.hour() < 5 && now.days() === 1)
172 from.subtract(1, 'weeks');
173 query += from.valueOf();
176 if (now.hours() >= 22 &&
177 now.dates() === now.clone().endOf('month').date()) {
178 from = now.clone().hours(22);
180 from = now.clone().startOf('month').subtract(1, 'days').hours(22);
182 query += from.valueOf();
188 from = $('#term_from').datepicker("getDate");
189 var to = $('#term_to').datepicker("getDate");
193 if (from.date() === 1)
194 from.subtract(2, 'hours');
195 query += from.valueOf();
198 if (to.date() === to.clone().endOf('month').date()) {
201 to.add(1, 'days').hours(5);
203 query += "&to=" + to.valueOf();
207 $('#loading').show();
208 var url = this.jsons[this.mainTab] + query;
209 $('#log' + this.mainTab).DataTable().ajax.url(url).load();
215 <form id="chart_type" show={mainTabs[mainTab] === "資材グラフ"}>
216 <div style="margin: 0 0 0.5em 1em;">
217 <label><input type="radio" name="chart_type" value="0" checked={opts.chartSpec.type === 0} onchange={chartTypeChange}>連続</label>
218 <label><input type="radio" name="chart_type" value="1" checked={opts.chartSpec.type === 1} onchange={chartTypeChange}>差分</label>
224 opts.chartSpec.type = +sessionStorage.getItem('chartType');
227 this.chartTypeChange = function(e) {
228 opts.chartSpec.type = +e.target.value;
229 sessionStorage.setItem('chartType', opts.chartSpec.type);
230 opts.observable.trigger("chartTypeChanged");
231 opts.observable.trigger("chartSpecChanged");
234 opts.observable.on("mainTabChanged", function(idx) {
235 self.update({mainTab: idx});
241 <div show={mainTabs[mainTab] === "資材グラフ"}>
242 <ul class="tab tabsub" style="float: left; margin-right: 0.2em" show={chartSpec.type === 0}>
243 <li each={name, i in seqChartRanges} class={select: chartSpec.seqRange === i} onclick={parent.rangeTabChange}>{name}</li>
246 <ul class="tab tabsub" style="float: left; margin-right: 0.2em" show={chartSpec.type === 1}>
247 <li each={name, i in diffChartRanges} class={select: chartSpec.diffRange === i} onclick={parent.rangeTabChange}>{name}</li>
249 <div style="padding: 0.2em 0;">
250 <input type="text" id="chart_from" style="width: 7em">~<input type="text" id="chart_to" style="width: 7em">
251 <label><input type="checkbox" id="tooltip" value="" style="margin-left: 2em;" onchange={tooltipChange} checked={opts.chartSpec.tooltip === 1}>ツールチップ</label>
256 this.seqChartRanges = [
265 this.diffChartRanges = [
273 opts.chartSpec.seqRange = +sessionStorage.getItem('seqChartRange');
274 opts.chartSpec.diffRange = +sessionStorage.getItem('diffChartRange');
275 opts.chartSpec.tooltip = +sessionStorage.getItem('chartTooltip');
276 this.chartSpec = opts.chartSpec;
278 this.rangeTabChange = function(e) {
279 if (opts.chartSpec.type === 0) {
280 opts.chartSpec.seqRange = e.item.i;
281 sessionStorage.setItem('seqChartRange', e.item.i);
283 opts.chartSpec.diffRange = e.item.i;
284 sessionStorage.setItem('diffChartRange', e.item.i);
286 opts.observable.trigger("chartSpecChanged");
289 this.tooltipChange = function(e) {
290 opts.chartSpec.tooltip = +e.target.checked;
291 sessionStorage.setItem('chartTooltip', +e.target.checked);
292 opts.observable.trigger("chartSpecChanged");
295 this.useDatePicker = function() {
296 return opts.chartSpec.type === 0 && opts.chartSpec.seqRange === 5 ||
297 opts.chartSpec.type === 1 && opts.chartSpec.diffRange === 4;
300 this.init = function() {
301 $('#chart_from').datepicker({
302 onClose: function() {
303 if (self.useDatePicker())
304 opts.observable.trigger("chartSpecChanged");
307 $('#chart_to').datepicker({
308 onClose: function() {
309 if (self.useDatePicker())
310 opts.observable.trigger("chartSpecChanged");
318 this.on("mount", self.init);
320 opts.observable.on("mainTabChanged", function(idx) {
321 self.update({mainTab: idx});
324 opts.observable.on("chartTypeChanged", function() {
334 opts.observable.on("chartSpecChanged", function() {
335 if (opts.chartSpec.type === 0)
339 opts.observable.on("chartSizeChanged", function() {
340 if (opts.chartSpec.type === 0)
344 this.header = ["日付", "燃料", "弾薬", "鋼材", "ボーキ", "高速建造材", "高速修復材", "開発資材", "改修資材"];
346 opts.observable.on("offAllLegends", function() {
347 if (opts.chartSpec.type !== 0)
350 self.header.slice(1).forEach(function(c) {
351 self.unselected[c] = true;
355 this.resize = function() {
358 $('#loading').show();
359 setTimeout(function() {
360 self.chart.resize(self.chartSize());
364 this.drawChart = function(data) {
365 var range = this.calcRange(opts.chartSpec.seqRange);
366 if (range.last === 0)
369 $('#loading').show();
371 url: "./資材ログ.json?number=true" +
372 "&from=" + range.first + "&to=" + range.last,
373 success: function(d) { self.drawChart(d); },
374 dataType: "json", cache: false
379 picked = this.pickChartData(data.data, range);
380 picked.data.unshift(self.header);
381 this.drawSeqChart(picked);
384 this.calcRange = function(range) {
386 var last = (new Date()).valueOf();
389 first = moment(last).subtract(24, 'hours').valueOf();
392 first = moment(last).subtract(7, 'days').valueOf();
395 first = moment(last).subtract(1, 'months').valueOf();
398 first = moment(last).subtract(3, 'months').valueOf();
403 var fromDate = $('#chart_from').datepicker("getDate");
404 var toDate = $('#chart_to').datepicker("getDate");
405 if (fromDate === null || toDate === null)
406 return {first: 0, last:0};
407 first = fromDate.valueOf() + 3600 * 5000;
408 last = toDate.valueOf() + this.oneDay + 3600 * 5000;
411 return {first: first, last: last};
414 this.unselected = {};
416 this.drawSeqChart = function(picked) {
417 var size = this.chartSize();
418 this.chart = c3.generate({
426 xFormat: '%Y-%m-%d %H:%M:%S',
443 show: opts.chartSpec.tooltip
455 format: "%m-%d %H:%M",
465 onclick: function(id) {
466 self.unselected[id] = !self.unselected[id];
467 self.chart.toggle(id);
471 onrendered: function() {
472 $('#loading').hide();
473 opts.observable.trigger("chartRendered");
476 self.chart.hide(Object.keys(self.unselected).filter(function(e) {
477 return self.unselected[e];
481 this.pickChartData = function(data, range) {
485 var first = range.first;
486 var last = range.last;
487 var interval, tickInterval, lastTick;
488 if (last <= first + this.oneDay) {
490 tickInterval = 3600 * 1000;
491 lastTick = last - last % tickInterval;
492 } else if (last <= first + this.oneDay * 21) {
494 tickInterval = this.oneDay;
495 lastTick = this.to5am(last);
496 } else if (last <= first + this.oneDay * 63) {
497 interval = 3600 * 1000;
498 tickInterval = this.oneDay * 7;
499 lastTick = this.to5am(moment(last).day(1).valueOf());
500 } else if (last <= first + this.oneDay * 126) {
501 interval = 3600 * 6000;
502 tickInterval = this.oneDay * 14;
503 lastTick = this.to5am(moment(last).day(1).valueOf());
505 var magn = Math.ceil((last - data[0][0]) / (this.oneDay * 365) / 2);
506 interval = this.oneDay * magn;
507 tickInterval = this.oneDay * 28 * magn;
508 lastTick = this.to5am(moment(last).day(1).valueOf());
511 for (var i = data.length - 1; i >= 0; i--) {
516 var v = date - date % interval;
517 if (lastData !== v) {
518 newdata.unshift(row);
526 for (var tick = lastTick; tick > lastData; tick -= tickInterval) {
527 var str = self.toDateString(moment(tick));
529 grid.unshift({ value: str });
531 return { data: newdata, tick: ticks, grid: grid };
540 opts.observable.on("chartSpecChanged", function() {
541 if (opts.chartSpec.type === 1)
545 opts.observable.on("chartSizeChanged", function() {
546 if (opts.chartSpec.type === 1)
550 this.header = ["日付", "燃料", "弾薬", "鋼材", "ボーキ"];
552 opts.observable.on("offAllLegends", function() {
553 if (opts.chartSpec.type !== 1)
556 self.header.slice(1).forEach(function(c) {
557 self.unselected[c] = true;
561 this.resize = function() {
564 $('#loading').show();
565 setTimeout(function() {
566 self.chart.resize(self.chartSize());
570 this.drawChart = function(data) {
571 var range = this.calcRange(opts.chartSpec.diffRange);
572 if (range.last === 0)
575 $('#loading').show();
577 url: "./資材ログ.json?number=true" +
578 "&from=" + range.first + "&to=" + range.last,
579 success: function(d) { self.drawChart(d); },
580 dataType: "json", cache: false
585 picked = this.pickChartData(data.data, range);
586 picked.data.unshift(self.header);
587 this.drawDiffChart(picked);
590 this.calcRange = function(range) {
592 var last = (new Date()).valueOf();
595 first = moment(last).subtract(1, 'months').valueOf();
598 first = moment(last).subtract(3, 'months').valueOf();
601 first = moment(last).subtract(6, 'months').subtract(1, 'weeks').valueOf();
606 var fromDate = $('#chart_from').datepicker("getDate");
607 var toDate = $('#chart_to').datepicker("getDate");
608 if (fromDate === null || toDate === null)
609 return {first: 0, last: 0};
610 var from = fromDate.valueOf() + 3600 * 5000;
611 var to = toDate.valueOf() + this.oneDay + 3600 * 5000;
612 first = Math.max(first, from);
613 last = Math.min(last, to);
616 return {first: first, last: last};
619 this.unselected = {};
621 this.drawDiffChart = function(picked) {
622 var size = this.chartSize();
623 this.chart = c3.generate({
639 groups: [["燃料", "弾薬", "鋼材", "ボーキ"]]
647 show: opts.chartSpec.tooltip
664 format: picked.monthly ? "%Y-%m" : "%m-%d %H:%M",
671 onclick: function(id) {
672 self.unselected[id] = !self.unselected[id];
673 self.chart.toggle(id);
677 onrendered: function() {
678 $('#loading').hide();
679 opts.observable.trigger("chartRendered");
682 self.chart.hide(Object.keys(self.unselected).filter(function(e) {
683 return self.unselected[e];
687 this.pickChartData = function(data, range) {
691 var first = range.first;
692 var last = range.last;
693 var interval, tickInterval, lastTick;
696 return this.pickMonthlyChartData(data);
697 if (last <= first + this.oneDay * 2 * 31) {
698 interval = this.oneDay;
699 tickInterval = this.oneDay * 2;
700 lastTick = this.to5am(last);
702 } else if (last <= first + this.oneDay * 3 * 31) {
703 interval = this.oneDay;
704 tickInterval = this.oneDay * 7;
705 lastTick = this.to5am(last);
708 interval = this.oneDay * 7;
709 tickInterval = this.oneDay * 28;
710 lastTick = this.to5am(moment(last).day(1).valueOf());
712 if (last <= first + this.oneDay * 6 * 38) {
713 tickInterval = this.oneDay * 14;
717 var lastDate = lastTick;
719 for (var i = data.length - 1; i >= 0; i--) {
728 if (date <= lastDate) {
729 var newrow = [lastDate];
730 for (var r = 1; r < 5; r++) {
731 newrow.push(prevRow[r] - row[r]);
733 newdata.unshift(newrow);
734 lastDate = lastDate - interval;
742 if (tickInterval >= this.oneDay * 7)
743 lastTick = moment(lastTick).day(1).hour(5).minute(0).valueOf();
744 for (var tick = lastTick; tick > lastDate; tick -= tickInterval) {
746 grid.unshift({ value: tick });
748 return { data: newdata, tick: ticks, grid: grid, width: barWidth };
751 this.pickMonthlyChartData = function(data) {
759 for (var i = data.length - 1; i >= 0; i--) {
763 var eom = moment(row[0]).endOf('month');
764 prevRow[0] = eom.valueOf();
765 prevMonth = eom.month();
768 date = new Date(row[0]);
769 if (prevMonth !== date.getMonth()) {
770 var newrow = [prevRow[0]];
771 for (var r = 1; r < 5; r++)
772 newrow.push(prevRow[r] - row[r]);
773 newdata.unshift(newrow);
774 ticks.unshift(prevRow[0]);
775 grid.unshift({ value: prevRow[0] });
777 prevMonth = date.getMonth();
780 if (prevRow && date !== prevRow[0]) {
781 newrow = [prevRow[0]];
782 for (r = 1; r < 5; r++)
783 newrow.push(prevRow[r] - row[r]);
784 newdata.unshift(newrow);
785 ticks.unshift(prevRow[0]);
786 grid.unshift({ value: prevRow[0] });
788 return { monthly: true, data: newdata, tick: ticks, grid: grid, width: 0.5 };
791 </differential-chart>
794 <div show={mainTabs[mainTab] === "資材グラフ"}>
795 <span class="c3-legend-item" id="off-all-legends" style="text-decoration: underline; cursor: pointer; z-index: 10; position: absolute; display: none;" onclick={offAllLegends} >全解除</span>
796 <div id="chart" style="clear: both; margin: 1em;"></div>
803 opts.observable.on("mainTabChanged", function(idx) {
804 self.update({mainTab: idx});
805 if (self.mainTabs[idx] === "資材グラフ")
806 opts.observable.trigger("chartSpecChanged");
809 opts.observable.on("chartRendered", function() {
811 if (opts.chartSpec.type === 0) {
812 legend = $(".c3-legend-item-改修資材>text").offset();
815 legend = $(".c3-legend-item-ボーキ>text").offset();
819 $("#off-all-legends").offset({top: legend.top, left: legend.left + offset}).show();
822 this.offAllLegends = function() {
823 opts.observable.trigger("offAllLegends");
827 $(window).resize(function() {
829 clearTimeout(self.timer);
830 self.timer = setTimeout(function() {
831 if (self.mainTabs[self.mainTab] === "資材グラフ")
832 opts.observable.trigger("chartSizeChanged");
833 else if (self.mainTabs[self.mainTab] === "戦果")
834 opts.observable.trigger("achivementChartSizeChanged");
841 <div show={mainTabs[mainTab] === "戦果"}>
842 <span style="margin-left: 1em;">期間: </span><select style="width: 7em; margin-bottom: 1em;" name="月" onchange={monthChange}>
843 <option each={m, i in months} value={m}>{m}</option>
845 <table id="achivement_table" class="display compact cell-border">
847 <tr><th>日付</th><th>戦果</th><th>EO</th><th>月毎</th></tr>
850 <div id="achivementChart" style="margin: 1em;"></div>
854 this.on("mount", function() {
855 $("#achivement_table").dataTable({
859 order: [[0, "desc"]],
863 drawCallback: function() {
864 $('#loading').hide();
871 opts.observable.on("mainTabChanged", function(idx) {
872 self.update({mainTab: idx});
873 if (self.mainTabs[self.mainTab] === "戦果")
878 this.selectedIndex = 0;
880 this.monthChange = function(event) {
881 this.selectedIndex = event.target.selectedIndex;
882 if (this.selectedIndex === 0) {
889 this.calcResult = function(data) {
891 var expPerAch = 10000 / 7.0;
893 var endOfMonth = moment(0);
896 var endOfYear = moment(0);
898 var carryOverAch = 0;
901 var lastDate = moment(0);
903 var nextDate = moment(0);
904 for (var i = 0; i < data.length; i++) {
906 var date = this.parseDate(row[0]);
907 var exp = row[1] - 0;
909 var isNewYear = date.isSameOrAfter(endOfYear);
910 var isNewMonth = date.isSameOrAfter(endOfMonth);
911 var isNewDate = date.isSameOrAfter(nextDate);
912 if (isNewDate || isNewMonth || isNewYear) {
913 if (lastDate.add(1, 'hours').isSameOrBefore(date)) {
914 // 2時を過ぎて最初のexpを戦果の計算に使うと、2時をまたいだ出撃の戦果が前日に加算される。
915 // そこで2時前のexpを使って戦果を計算するが、2時前のexpが正しく出力されていない場合は
916 // 戦果を正しく計算できない。記録の間隔が1時間以上空いているときは、2時をまたいだ出撃が
917 // 行われていない可能性が高いので計算には今のexpを使うことにする。
918 // これは5時基準で出力された過去のデータで、妥当な戦果を計算するために必要な処理である。
921 if (nextDate.valueOf() !== 0) {
922 var d = isNewDate ? nextDate.subtract(1, 'days') : endOfMonth;
923 var m = d.format("YYYY-MM");
926 this.result[m].push([
927 d.format("YYYY-MM-DD"),
928 ((lastExp - prevExp) / expPerAch).toFixed(1), dayEo,
929 ((lastExp - monthExp) / expPerAch + monthEo + carryOverAch + carryOverEo).toFixed(1)
932 prevExp = lastExp === -1 ? exp : lastExp;
934 endOfYear = date.clone().endOf('year').hour(22).startOf('hour');
935 if (endOfYear.isSameOrBefore(date))
936 endOfYear.add(1, 'year');
937 yearExp = lastExp === -1 ? exp : lastExp;
941 endOfMonth = date.clone().endOf('month');
942 if (date.date() === endOfMonth.date())
943 endOfMonth.add(1, 'months').endOf('month');
944 endOfMonth.hour(22).startOf('hour');
945 monthExp = lastExp === -1 ? exp : lastExp;
946 carryOverEo = monthEo * expPerAch / 50000;
947 carryOverAch = (monthExp - yearExp) / 50000;
949 m = endOfMonth.format("YYYY-MM");
952 this.result[m].push([endOfMonth.format("YYYY-MM 引継"),
953 carryOverAch.toFixed(1), carryOverEo.toFixed(1), (carryOverAch + carryOverEo).toFixed(1)]);
956 nextDate = date.clone().hour(2).startOf('hour');
957 if (date.hour() >= 2)
958 nextDate.add(1, 'days');
959 if (nextDate.date() === 1)
960 nextDate.add(1, 'days');
962 if (date.isBefore(date.clone().endOf('month').hour(22).startOf('hour'))) {
963 // 月末22時から翌0時までのEOのボーナス戦果は消える。
972 this.calcChartData = function() {
974 for (var month in this.result) {
975 var data = this.chartData[month] = [];
976 var result = this.result[month];
979 data.push(["日付", "戦果", "EO", "月毎"]);
980 for (var i = 0; i < result.length; i++) {
982 if (row[0].match(/引継/)) {
984 data.push([0, row[1], row[2], row[3]]);
987 d = moment(row[0], "YYYY-MM-DD").date();
989 var ach = (row[3] - eo).toFixed(1);
990 data.push([d, ach, eo, row[3]]);
992 var endOfMonth = moment(month, "YYYY-MM").endOf("month").date();
993 while (d < endOfMonth) {
995 data.push([d, null, null, null]);
1000 this.chartSize = function() {
1001 var width = Math.max($(window).width() - 6 * this.pxPerEm, 800);
1003 height: width * 0.4,
1008 opts.observable.on("achivementChartSizeChanged", function() {
1011 $('#loading').show();
1012 setTimeout(function() {
1013 self.chart.resize(self.chartSize());
1017 this.showChart = function(month) {
1018 this.chart = c3.generate({
1019 bindto: "#achivementChart",
1020 size: this.chartSize(),
1023 rows: this.chartData[month],
1030 onrendered: function() { $('#loading').hide(); }
1034 this.updateData = function(data) {
1036 $('#loading').show();
1039 success: function(data) {
1040 self.updateData(data.data);
1047 this.calcResult(data);
1048 this.calcChartData();
1049 this.months = Object.keys(this.result).sort(function(a, b) {
1060 this.show = function() {
1061 if (this.result === undefined){
1065 var dt = $('#achivement_table').DataTable();
1067 dt.rows.add(this.result[this.months[this.selectedIndex]]).draw();
1068 this.showChart(this.months[this.selectedIndex]);
1074 <div show={mainTabs[mainTab] === "出撃統計"}>
1076 <ul class="tab tabsub" style="float: left; margin-right: 0.2em">
1077 <li each={tabs} class={select: parent.type === type} onclick={parent.changeTab}>{label}</li>
1080 <div style="padding: 0.2em 0;">
1081 <input type="text" id="sortie_stat_from" style="width: 7em">~<input type="text" id="sortie_stat_to" style="width: 7em">
1084 <div style="clear: both;" show={type === "recent"}>
1086 <table id="sortie_stat_day">
1089 <table id="sortie_stat_week">
1092 <table id="sortie_stat_month">
1096 <div show={type === "range"}>
1097 <table id="sortie_stat_all" style="width: 100%;">
1114 this.type = "recent";
1115 this.changeTab = function(e) {
1116 this.type = e.item.type;
1123 this.on("mount", function() {
1124 $("[id^=sortie]").addClass('display compact cell-border');
1128 opts.observable.on("mainTabChanged", function(idx) {
1129 self.update({mainTab: idx});
1130 if (self.mainTabs[self.mainTab] === "出撃統計")
1134 this.init = function() {
1135 this.initDatePicker();
1138 this.initDatePicker = function() {
1139 $('#sortie_stat_from').datepicker({
1140 onClose: function() { if (self.type === "range") self.show(); }
1142 $('#sortie_stat_to').datepicker({
1143 onClose: function() { if (self.type === "range") self.show(); }
1149 this.loadData = function() {
1151 if (this.type === "recent") {
1152 from = moment().subtract(1, 'months').subtract(1, 'day').valueOf();
1153 to = new Date().valueOf();
1155 var fromDate = $('#sortie_stat_from').datepicker("getDate");
1156 var toDate = $('#sortie_stat_to').datepicker("getDate");
1157 if (fromDate === null || toDate === null) {
1161 from = moment(fromDate);
1162 if (from.date() === 1)
1163 from.subtract(2, 'hours');
1164 from = from.valueOf();
1165 to = moment(toDate);
1166 if (to.date() === to.clone().endOf('month').date()) {
1174 url: "./海戦・ドロップ報告書.json?from=" + from + "&to=" + to,
1175 success: function(data) { self.show(data.data); },
1176 dataType: "json", cache: false
1180 this.initResult = function() {
1183 if (this.type === "recent") {
1189 r.day.begin = moment(now).hour(5).minute(0).second(0);
1190 if (now.hour() < 5) {
1191 r.day.begin.subtract(1, 'days');
1193 r.week.begin = moment(now).day(1).hour(5).minute(0).second(0);
1194 if (now.day() === 0 || now.day() === 1 && now.hour() < 5) {
1195 r.week.begin.subtract(1, 'weeks');
1197 if (moment(now).endOf('month').date() === now.date() &&
1198 now.hour() >= 22) { // 月末22時以降
1199 r.month.begin = moment(now).hour(22).minute(0).second(0);
1202 moment(now).date(1).subtract(1, 'days').
1203 hour(22).minute(0).second(0);
1206 r = { all: { stat: {} } };
1207 r.all.begin = moment(0);
1212 this.gatherData = function(data) {
1213 var initStat = function() {
1214 return { start: "-", S: 0, A: 0, B: 0, C: 0, D: 0, R: 0 };
1216 var r = this.initResult();
1217 for (var i = 0; i < data.length; i++) {
1219 var date = moment(row[0]);
1221 var isBoss = row[3].indexOf("ボス") !== -1;
1222 var isStart = row[3].indexOf("出撃") !== -1;
1224 for (var j = 23; j < row.length; j++) {
1225 if (/^輸送/.test(row[j]) && /^0\x2f/.test(row[j + 1]))
1228 var item = /\+(.*)/.exec(row[10]);
1234 for (var term in r) {
1235 if (!r.hasOwnProperty(term))
1238 if (to.begin.isAfter(date))
1240 for (var b = 0; b < 4; b++) {
1241 var name = b < 2 ? "合計" : map;
1242 if (b === 1 || b === 3) {
1245 name = name + " - ボス";
1247 var mo = to.stat[name];
1249 mo = to.stat[name] = initStat();
1251 to.stat["合計 - ボス"] = initStat();
1260 if ((b === 0 || b === 2) && isStart) {
1261 if (mo.start === "-")
1271 this.isItemColumn = function(col) {
1272 return !/^(?:map|start|[SABCDR])$/.test(col);
1275 this.sortItemOrder = function(items) {
1276 ["お米", "梅干", "海苔", "お茶"].reverse().forEach(function(item) {
1277 var idx = items.indexOf(item);
1279 items.splice(idx, 1);
1280 items.unshift(item);
1285 this.setupTable = function(r) {
1286 for (var term in r) {
1287 var header = ["マップ",
1295 var columns = [{ data: "map" },
1303 if (term === "monthly") {
1308 for (col in r[term].stat["合計"]) {
1309 if (this.isItemColumn(col))
1312 this.sortItemOrder(items);
1313 items.forEach(function(item) {
1315 columns.push({data: item});
1317 $("#sortie_stat_" + term).html(
1319 header.reduce(function(acc, cur) {
1320 return acc + "<th>" + cur + "</th>";
1324 r[term].columns = columns;
1328 this.fillupItemRecords = function(r) {
1329 for (var term in r) {
1330 for (var col in r[term].stat["合計"]) {
1331 if (!this.isItemColumn(col))
1333 for (var map in r[term].stat) {
1336 if (!r[term].stat[map][col]){
1337 r[term].stat[map][col] = 0;
1344 this.reorderRows = function(r) {
1345 for (var term in r) {
1346 if (!r.hasOwnProperty(term))
1350 for (var map in r[term].stat) {
1351 if (!r[term].stat.hasOwnProperty(map))
1355 var e = r[term].stat[map];
1359 var boss = map + " - ボス";
1360 e = r[term].stat[boss];
1367 r[term].table = table;
1371 this.show = function(data) {
1373 $('#loading').show();
1377 var r = this.gatherData(data);
1379 this.fillupItemRecords(r);
1380 this.reorderRows(r);
1381 for (var term in r) {
1382 if (!r.hasOwnProperty(term))
1384 var table = $("#sortie_stat_" + term);
1385 table.DataTable().destroy();
1390 columns: r[term].columns
1391 }).rows.add(r[term].table).draw();
1393 $('#loading').hide();