OSDN Git Service

各種報告書のタブ上のマウスカーソルを指アイコンにする
[kancollesniffer/KancolleSniffer.git] / LogViewer / index.html
index 4fdfbc8..1d7d6e1 100644 (file)
@@ -1,19 +1,19 @@
-<!DOCTYPE html>
+<!DOCTYPE html>
 <html lang="ja">
 <head>
 <meta charset="utf-8">
 <title>各種報告書 - KancolleSniffer</title>
-
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.7/js/jquery.dataTables.min.js"></script>
 <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.7/css/jquery.dataTables.min.css">
-<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.min.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
-<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.css">
+<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.14/c3.min.js"></script>
+<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.14/c3.min.css">
 <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
 <link rel="stylesheet" type="text/css" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
 <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/i18n/datepicker-ja.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/riot/3.5.0/riot+compiler.min.js"></script>
 <style>
 body {
     font-family:'Lucida Grande','Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
@@ -21,11 +21,9 @@ body {
     font-size: 14px;
 }
 .tab {overflow: hidden; list-style-type: none; margin: 0 0 2em 1em; padding: 0;}
-.tab li {background: #eee; padding: 0.3em 1.5em; float: left; margin-right: 2px;}
-.tab1 li {padding: 0.3em 1em;}
+.tab li {background: #eee; padding: 0.3em 1.5em; float: left; margin-right: 2px; cursor: pointer;}
 .tab li.select {background: #ccc;}
-.contents {list-style-type: none; margin: 0; padding: 0;}
-.hide {display: none;}
+.tabsub li {padding: 0.3em 1em;}
 .c3 .tick {font-family:'Lucida Grande','Hiragino Kaku Gothic ProN', Meiryo, sans-serif; font-size: 12px;}
 .c3-legend-item {font-family:'Lucida Grande','Hiragino Kaku Gothic ProN', Meiryo, sans-serif; font-size: 14px;}
 #loading {
@@ -42,1030 +40,83 @@ body {
 </style>
 </head>
 <body>
-<script>
-/* global moment, c3, $ */
-
-var oneDay = 3600 * 24 * 1000;
-
-function showLog() {
-    var query = "?from=" + moment().subtract(1, 'months').valueOf();
-    if ($('input[name=term]:eq(1)').prop('checked')) {
-        var from = $('#term_from').datepicker("getDate");
-        var to = $('#term_to').datepicker("getDate");
-        if (from != null)
-            query = "?from=" + from.valueOf();
-        if (to != null)
-            query += "&to=" + (to.valueOf() + oneDay);
-    }
-    var jsons = [
-        "海戦・ドロップ報告書.json",
-        "海戦・ドロップ報告書.json",
-        "遠征報告書.json",
-        "開発報告書.json",
-        "建造報告書.json",
-        "改修報告書.json",
-        "資材ログ.json"
-    ];
-    $('#loading').show();
-    var url = jsons[selectedTable] + query;
-    $('#log' + selectedTable).DataTable().ajax.url(url).load();
-}
-
-var tables = 7;
+<div id="loading"><img src="https://kancollesniffer.osdn.jp/ajax-loader.gif" alt="読み込み中..."></div>
 
-function initTables() {
-    for (var t = 0; t < tables; t++) {
-        var opts = {
-            destroy: true,
-            deferRender: true,
-            stateSave: true,
-            order: [[0, "desc"]],
-            pageLength: 50,
-            lengthMenu: [[50, 100, 200, -1], [50, 100, 200, "All"]],
-            drawCallback: function () {
-                $('#loading').hide();
-            }
-        };
-        if (t === 0) {
-            opts.columns = [{ data: 0 }, { data: 1 }, { data: 2 }, { data: 3 }, { data: 4 }, { data: 9 }, { data: 10 }];
-        } else if (t === 1) {
-            var entries = [];
-            for (var i = 0; i < 38; i++) {
-                if (i === 9 || i === 10)
-                    continue;
-                entries.push({ data: i });
-            }
-            opts.columns = entries;
-        }
-        $('#log' + t).dataTable(opts);
-    }
-}
+<script>
+/* global moment, riot */
 
 var timeFormat = "YYYY-MM-DD HH:mm:ss";
-function parseDate(d) {
-    return moment(d, timeFormat);
-}
-
-function toString(d) {
-    return d.format(timeFormat);
-}
-
-function to5am(tick) {
-    return tick - tick % (3600 * 24000) - 3600 * 4000;
-}
-
-var selectedTable = 0;
-var seqChartRange = 0;
-var diffChartRange = 0;
-var chartType = 0;
-var showChart = false;
-var currentPickedData;
-
-function drawChart(data) {
-    if (data == null) {
-        $('#loading').show();
-        $.get("./資材ログ.json?time=" + Date.now(), function (d) { drawChart(d); }, "json");
-        return;
-    }
-    var picked, header;
-    if (chartType === 0) {
-        picked = pickChartData(data.data, seqChartRange);
-        header = ["日付", "燃料", "弾薬", "鋼材", "ボーキ", "高速建造材", "高速修復材", "開発資材", "改修資材"];
-        picked.data.unshift(header);
-        drawSeqChart(picked);
-        currentPickedData = picked;
-    } else {
-        picked = pickDiffChartData(data.data, diffChartRange);
-        header = ["日付", "燃料", "弾薬", "鋼材", "ボーキ"];
-        picked.data.unshift(header);
-        drawDiffChart(picked);
-        currentPickedData = picked;
-    }
-}
-
-var chartSeq, chartDiff;
-
-function redrawChart() {
-    if (!currentPickedData)
-        return;
-    $('#loading').show();
-    setTimeout(function () {
-        if (chartType === 0)
-            chartSeq.resize(chartSize());
-        if (chartType === 1)
-            chartDiff.resize(chartSize());
-    });
-}
-
-var timer;
-$(window).resize(function () {
-    if (timer)
-        clearTimeout(timer);
-    timer = setTimeout(function () {
-        if (showChart)
-            redrawChart();
-    }, 200);
-});
-
-function chartSize() {
-    var pxPerEm = Number($('#chart').css('fontSize').match(/(\d*(\.\d*)?)px/)[1]);
-    return {
-        height: Math.max($(document).height() - 15 * pxPerEm, 400),
-        width: Math.max($(document).width() - 6 * pxPerEm, 800)
-    };
-}
-
-var seqChartUnselected = {};
-
-function drawSeqChart(picked) {
-    var size = chartSize();
-    chartSeq = c3.generate({
-        bindto: '#chart',
-        size: {
-            height: size.height,
-            width: size.width
-        },
-        data: {
-            x: '日付',
-            xFormat: '%Y-%m-%d %X',
-            rows: picked.data,
-            axes: {
-                燃料: 'y',
-                弾薬: 'y',
-                鋼材: 'y',
-                ボーキ: 'y',
-                高速建造材: 'y2',
-                高速修復材: 'y2',
-                開発資材: 'y2',
-                改修資材: 'y2'
-            }
-        },
-        point: {
-            show: false
-        },
-        tooltip: {
-            show: $('#tooltip').prop('checked')
-        },
-        grid: {
-            x: {
-                lines: picked.grid
-            }
-        },
-        axis: {
-            x: {
-                type: 'timeseries',
-                tick: {
-                    rotate: 30,
-                    format: function (x) { return moment(x).format("MM-DD HH:mm"); },
-                    values: picked.tick
-                }
-            },
-            y2: {
-                show: true
-            }
-        },
-        legend: {
-            item: {
-                onclick: function(id) {
-                    seqChartUnselected[id] = !seqChartUnselected[id];
-                    chartSeq.toggle(id);
-                }
-            }
-        },
-        onrendered: function () { $('#loading').hide(); }
-    });
-    for (var id in seqChartUnselected) {
-        if (seqChartUnselected.hasOwnProperty(id) && seqChartUnselected[id])
-            chartSeq.toggle(id);
-    }
-}
-
-function pickChartData(data, range) {
-    var newdata = [];
-    var ticks = [];
-    var grid = [];
-    var first = moment(data[0][0]).valueOf();
-    var last = moment(data[data.length - 1][0]).valueOf();
-    var interval, tickInterval, lastTick;
-    switch (range) {
-        case 0:
-            first = moment(last).subtract(24, 'hours').valueOf();
-            break;
-        case 1:
-            first = moment(last).subtract(7, 'days').valueOf();
-            break;
-        case 2:
-            first = moment(last).subtract(1, 'months').valueOf();
-            break;
-        case 3:
-            first = moment(last).subtract(3, 'months').valueOf();
-            break;
-        case 4:
-            first = moment(data[0][0]).valueOf();
-            break;
-        case 5:
-            var fromDate = $('#chart_from').datepicker("getDate");
-            var toDate = $('#chart_to').datepicker("getDate");
-            if (fromDate == null || toDate == null)
-                return { data: [], tick: [], grid: [] };
-            var from = fromDate.valueOf() + 3600 * 5000;
-            var to = toDate.valueOf() + oneDay + 3600 * 5000;
-            first = Math.max(first, from);
-            last = Math.min(last, to);
-            break;
-    }
-    if (last <= first + oneDay) {
-        interval = 1000;
-        tickInterval = 3600 * 1000;
-        lastTick = last - last % tickInterval;
-    } else if (last <= first + oneDay * 21) {
-        interval = 1000;
-        tickInterval = oneDay;
-        lastTick = to5am(last);
-    } else if (last <= first + oneDay * 63) {
-        interval = 3600 * 1000;
-        tickInterval = oneDay * 7;
-        lastTick = to5am(moment(last).day(1).valueOf());
-    } else if (last <= first + oneDay * 126) {
-        interval = 3600 * 6000;
-        tickInterval = oneDay * 14;
-        lastTick = to5am(moment(last).day(1).valueOf());
-    } else {
-        interval = 3600 * 12000;
-        tickInterval = oneDay * 28;
-        lastTick = to5am(moment(last).day(1).valueOf());
-    }
-    var lastData;
-    for (var i = data.length - 1; i >= 0; i--) {
-        var row = data[i];
-        var date = parseDate(row[0]).valueOf();
-        if (date > first) {
-            if (date <= last) {
-                var v = date - date % interval;
-                if (lastData !== v) {
-                    newdata.unshift(row);
-                    lastData = v;
-                }
-            }
-        } else {
-            break;
-        }
-    }
-    for (var tick = lastTick; tick > lastData; tick -= tickInterval) {
-        var str = toString(moment(tick));
-        ticks.unshift(str);
-        grid.unshift({ value: str });
-    }
-    return { data: newdata, tick: ticks, grid: grid };
-}
-
-var diffChartUnselected = {};
-
-function drawDiffChart(picked) {
-    var size = chartSize();
-    chartDiff = c3.generate({
-        bindto: '#chart',
-        size: {
-            height: size.height,
-            width: size.width
-        },
-        data: {
-            x: '日付',
-            xFormat: '%Y-%m-%d %X',
-            rows: picked.data,
-            axes: {
-                燃料: 'y',
-                弾薬: 'y',
-                鋼材: 'y',
-                ボーキ: 'y'
-            },
-            type: 'bar',
-            groups: [["燃料", "弾薬", "鋼材", "ボーキ"]]
-        },
-        bar: {
-            width: {
-                ratio: picked.width
-            }
-        },
-        tooltip: {
-            show: $('#tooltip').prop('checked')
-        },
-        grid: {
-            x: {
-                lines: picked.grid
-            },
-            y: {
-                lines: [
-                    { value: 0 }
-                ]
-            }
-        },
-        axis: {
-            x: {
-                type: 'timeseries',
-                tick: {
-                    rotate: 30,
-                    format: function (x) { return moment(x).format("MM-DD HH:mm"); },
-                    values: picked.tick
-                }
-            }
-        },
-        legend: {
-            item: {
-                onclick: function(id) {
-                    diffChartUnselected[id] = !diffChartUnselected[id];
-                    chartDiff.toggle(id);
-                }
-            }
-        },
-        onrendered: function () { $('#loading').hide(); }
-    });
-    for (var id in diffChartUnselected) {
-        if (diffChartUnselected.hasOwnProperty(id) && diffChartUnselected[id])
-            chartDiff.toggle(id);
-    }
-}
-
-function pickDiffChartData(data, range) {
-    var newdata = [];
-    var ticks = [];
-    var grid = [];
-    var first = moment(data[0][0]).valueOf();
-    var last = moment(data[data.length - 1][0]).valueOf();
-    var interval, tickInterval, lastTick;
-    var oneDay = 3600 * 24 * 1000;
-    switch (range) {
-        case 0:
-            first = moment(last).subtract(1, 'months').valueOf();
-            break;
-        case 1:
-            first = moment(last).subtract(3, 'months').valueOf();
-            break;
-        case 2:
-            first = moment(last).subtract(6, 'months').subtract(1, 'weeks').valueOf();
-            break;
-        case 3:
-            first = moment(data[0][0]).valueOf();
-            break;
-        case 4:
-            var fromDate = $('#chart_from').datepicker("getDate");
-            var toDate = $('#chart_to').datepicker("getDate");
-            if (fromDate == null || toDate == null)
-                return { data: [], tick: [], grid: [] };
-            var from = fromDate.valueOf() + 3600 * 5000;
-            var to = toDate.valueOf() + oneDay + 3600 * 5000;
-            first = Math.max(first, from);
-            last = Math.min(last, to);
-            break;
-    }
-    var barWidth;
-    if (last <= first + oneDay * 2 * 31) {
-        interval = oneDay;
-        tickInterval = oneDay * 2;
-        lastTick = to5am(last);
-        barWidth = 0.3;
-    } else if (last <= first + oneDay * 3 * 31) {
-        interval = oneDay;
-        tickInterval = oneDay * 7;
-        lastTick = to5am(last);
-        barWidth = 0.1;
-    } else {
-        interval = oneDay * 7;
-        tickInterval = oneDay * 28;
-        lastTick = to5am(moment(last).day(1).valueOf());
-        barWidth = 0.1;
-        if (last <= first + oneDay * 6 * 38) {
-            tickInterval = oneDay * 14;
-            barWidth = 0.3;
-        }
-    }
-    var lastDate = lastTick;
-    var prevRow;
-    for (var i = data.length - 1; i >= 0; i--) {
-        var row = data[i];
-        var date = parseDate(row[0]).valueOf();
-        if (date > first && date <= last) {
-            if (!prevRow) {
-                prevRow = row;
-                continue;
-            }
-            if (date <= lastDate) {
-                var newrow = [prevRow[0]];
-                for (var r = 1; r < 5; r++) {
-                    newrow.push(prevRow[r] - row[r]);
-                }
-                newdata.unshift(newrow);
-                lastDate = lastDate - interval;
-                prevRow = row;
-            }
-        } else {
-            break;
-        }
-    }
-    if (tickInterval >= oneDay * 7)
-        lastTick = moment(lastTick).day(1).hour(5).minute(0).valueOf();
-    for (var tick = lastTick; tick > lastDate; tick -= tickInterval) {
-        var str = toString(moment(tick));
-        ticks.unshift(str);
-        grid.unshift({ value: str });
-    }
-    return { data: newdata, tick: ticks, grid: grid, width: barWidth };
-}
-
-var sortieStatRange = 0;
-
-function loadSortieData() {
-    var from, to;
-    if (sortieStatRange === 0) {
-        from = moment().subtract(1, 'months').subtract(1, 'day').valueOf();
-        to = new Date().valueOf();
-    } else {
-        var fromDate = $('#sortie_stat_from').datepicker("getDate");
-        var toDate = $('#sortie_stat_to').datepicker("getDate");
-        if (fromDate == null || toDate == null) {
-            setSortieStat([]);
-            return;
-        }
-        from = fromDate.valueOf();
-        to = toDate.valueOf() + oneDay;
-    }
-    $.ajax({
-        url: "./海戦・ドロップ報告書.json?from=" + from + "&to=" + to,
-        success: function (data) { setSortieStat(data.data); },
-        dataType: "json", cache: false
-    });
-}
-
-function initSortieStatResult() {
-    var now = moment();
-    var r;
-    if (sortieStatRange === 0) {
-        r = {
-            day: { stat: {} },
-            week: { stat: {} },
-            month: { stat: {} }
+var mixin = {
+    mainTabs: [
+        "ドロップ",
+        "海戦",
+        "遠征",
+        "開発",
+        "建造",
+        "改修",
+        "資材",
+        "資材グラフ",
+        "戦果",
+        "出撃統計"
+    ],
+    logTables: 7,
+    oneDay: 3600 * 24 * 1000,
+    parseDate: function(d) {
+        return moment(d, timeFormat);
+    },
+    toDateString: function(d) {
+        return d.format(timeFormat);
+    },
+    to5am: function(tick) {
+        return tick - tick % (3600 * 24000) - 3600 * 4000;
+    },
+    pxPerEm: Number(getComputedStyle(document.body, null).fontSize.replace(/[^\d]/g, '')),
+    chartSize: function() {
+        return {
+            height: Math.max($(document).height() - 15 * this.pxPerEm, 400),
+            width: Math.max($(document).width() - 6 * this.pxPerEm, 800)
         };
-        r.day.begin = moment(now).hour(5).minute(0).second(0);
-        if (now.hour() < 5) {
-            r.day.begin.subtract(1, 'days');
-        }
-        r.week.begin = moment(now).day(1).hour(5).minute(0).second(0);
-        if (now.day() === 0 || now.day() === 1 && now.hour() < 5) {
-            r.week.begin.subtract(1, 'weeks');
-        }
-        if (moment(now).endOf('month').date() === now.date() &&
-            now.hour() >= 22) { // 月末22時以降
-            r.month.begin = moment(now).hour(22).minute(0).second(0);
-        } else {
-            r.month.begin =
-                moment(now).date(1).subtract(1, 'days').
-                    hour(22).minute(0).second(0);
-        }
-    } else {
-        r = { all: { stat: {} } };
-        r.all.begin = moment(0);
     }
-    return r;
-}
-
-function gatherSortieStat(data) {
-    var initStat = function () {
-        return { start: "-", S: 0, A: 0, B: 0, C: 0, D: 0, R: 0 }
-    };
-    var r = initSortieStatResult();
-    for (var i = 0; i < data.length; i++) {
-        var row = data[i];
-        var date = moment(row[0]);
-        var map = row[1];
-        var isBoss = row[3].indexOf("ボス") !== -1;
-        var isStart = row[3].indexOf("出撃") !== -1;
-        var resR = 0;
-        for (var j = 23; j < row.length; j++) {
-            if (/^輸送/.test(row[j]) && /^0\//.test(row[j + 1]))
-                resR++;
-        }
-        var res = row[4];
-        if (res === "E")
-            res = "D";
-        for (var term in r) {
-            if (!r.hasOwnProperty(term))
-                continue;
-            var to = r[term];
-            if (to.begin.isAfter(date))
-                continue;
-            for (var b = 0; b < 4; b++) {
-                var name = b < 2 ? "合計" : map;
-                if (b === 1 || b === 3) {
-                    if (!isBoss)
-                        continue;
-                    name = name + " - ボス";
-                }
-                var mo = to.stat[name];
-                if (!mo) {
-                    mo = to.stat[name] = initStat();
-                    if (name === "合計")
-                        to.stat["合計 - ボス"] = initStat();
-                }
-                mo["R"] += resR;
-                mo[res]++;
-                if ((b === 0 || b === 2) && isStart) {
-                    if (mo.start === "-")
-                        mo.start = 0;
-                    mo.start++;
-                }
-            }
-        }
-    }
-    return r;
-}
+};
 
-function arrangeSortieStatTable(r) {
-    for (var term in r) {
-        if (!r.hasOwnProperty(term))
-            continue;
-        var table = [];
-        var pushed = {};
-        for (var map in r[term].stat) {
-            if (!r[term].stat.hasOwnProperty(map))
-                continue;
-            if (pushed[map])
-                continue;
-            var e = r[term].stat[map];
-            e.map = map;
-            table.push(e);
-            pushed[map] = 1;
-            var boss = map + " - ボス";
-            e = r[term].stat[boss];
-            if (!e)
-                continue;
-            e.map = boss;
-            table.push(e);
-            pushed[boss] = 1;
-        }
-        r[term].table = table;
-    }
-}
-
-function setSortieStat(data) {
-    if (!data) {
-        $('#loading').show();
-        loadSortieData();
-        return;
-    }
-    var r = gatherSortieStat(data);
-    arrangeSortieStatTable(r);
-    for (var term in r) {
-        if (!r.hasOwnProperty(term))
-            continue;
-        var dt = $("#sortie_stat_" + term).DataTable();
-        dt.clear();
-        dt.rows.add(r[term].table).draw();
-    }
-    $('#loading').hide();
-}
-
-function initSortieStatTables() {
-    var terms = ['day', 'week', 'month', 'all'];
-    for (var i = 0; i < terms.length; i++) {
-        $("#sortie_stat_" + terms[i]).dataTable({
-            paging: false,
-            searching: false,
-            ordering: false,
-            columns: terms[i] !== 'month' ? [
-                { data: "map" },
-                { data: "start" },
-                { data: "S" },
-                { data: "A" },
-                { data: "B" },
-                { data: "C" },
-                { data: "D" },
-                { data: "R" }
-            ] : [
-                    { data: "map" },
-                    { data: "start" },
-                    { data: "S" },
-                    { data: "A" },
-                    { data: "B" },
-                    { data: "C" },
-                    { data: "D" }
-                ]
-        });
-    }
-}
-
-function showAchivementTable(data) {
-    var expPerAch = 10000 / 7.0;
-    if (!data) {
-        $('#loading').show();
-        $.ajax({
-            url: "./戦果.json",
-            success: function (data) {
-                showAchivementTable(data.data);
-            },
-            dataType: 'json',
-            cache: false
-        });
-        return;
-    }
-    var result = [];
-    var dayEo = 0;
-    var endOfMonth = moment(0);
-    var monthExp = 0;
-    var monthEo = 0;
-    var endOfYear = moment(0);
-    var yearExp = 0;
-    var carryOverAch = 0;
-    var carryOverEo = 0;
-    var prevExp = null;
-    var lastDate = moment(0);
-    var lastExp = -1;
-    var nextDate = moment(0);
-    for (var i = 0; i < data.length; i++) {
-        var row = data[i];
-        var date = parseDate(row[0]);
-        var exp = row[1] - 0;
-        var eo = row[2] - 0;
-        var isNewYear = date.isSameOrAfter(endOfYear);
-        var isNewMonth = date.isSameOrAfter(endOfMonth);
-        var isNewDate = date.isSameOrAfter(nextDate);
-        if (isNewDate || isNewMonth || isNewYear) {
-            if (lastDate.add('hour', 1).isSameOrBefore(date)) {
-                // 2時を過ぎて最初のexpを戦果の計算に使うと、2時をまたいだ出撃の戦果が前日に加算される。
-                // そこで2時前のexpを使って戦果を計算するが、2時前のexpが正しく出力されていない場合は
-                // 戦果を正しく計算できない。記録の間隔が1時間以上空いているときは、2時をまたいだ出撃が
-                // 行われていない可能性が高いので計算には今のexpを使うことにする。
-                // これは5時基準で出力された過去のデータで、妥当な戦果を計算するために必要な処理である。
-                lastExp = exp;
-            }
-            if (nextDate != null) {
-                result.push([
-                    (isNewDate ? nextDate.subtract(1, 'days') : endOfMonth).format("YYYY-MM-DD"),
-                    new Number((lastExp - prevExp) / expPerAch).toFixed(1), dayEo,
-                    new Number((lastExp - monthExp) / expPerAch + monthEo + carryOverAch + carryOverEo).toFixed(1)
-                ]);
-            }
-            prevExp = lastExp === -1 ? exp : lastExp;
-            if (isNewYear) {
-                endOfYear = date.clone().endOf('year').hour(22).startOf('hour');
-                if (endOfYear.isSameOrBefore(date))
-                    endOfYear.add(1, 'year').endOf('year');
-                yearExp = lastExp === -1 ? exp : lastExp;
-            }
-            if (isNewMonth) {
-                endOfMonth = date.clone().endOf('month').hour(22).startOf('hour');
-                if (endOfMonth.isSameOrBefore(date))
-                    endOfMonth.add(1, 'month').endOf('month');
-                monthExp = lastExp === -1 ? exp : lastExp;
-                carryOverEo = monthEo * expPerAch / 50000;
-                carryOverAch = (monthExp - yearExp) / 50000;
-                monthEo = 0;
-                result.push([endOfMonth.format("YYYY-MM 引継"),
-                    carryOverAch.toFixed(1), carryOverEo.toFixed(1), (carryOverAch + carryOverEo).toFixed(1)]);
-            }
-            dayEo = 0;
-            nextDate = date.clone().hour(2).startOf('hour');
-            if (date.hour() >= 2)
-                nextDate.add(1, 'days');
-            if (nextDate.date() === 1)
-                nextDate.add(1, 'days');
-        }
-        if (date.isBefore(date.clone().endOf('month').hour(22).startOf('hour'))) {
-            // 月末22時から翌0時までのEOのボーナス戦果は消える。
-            dayEo += eo;
-            monthEo += eo;
-        }
-        lastDate = date;
-        lastExp = exp;
-    }
-    var dt = $('#achivement_table').DataTable();
-    dt.clear();
-    dt.rows.add(result).draw();
-    $('#loading').hide();
-}
-
-function initAchievementTable() {
-    $("#achivement_table").dataTable({
-        destroy: true,
-        deferRener: true,
-        stateSave: true,
-        order: [[0, "desc"]],
-        pageLength: 50,
-        lengthMenu: [[50, 100, 200, -1], [50, 100, 200, "All"]],
-        drawCallback: function () {
-            $('#loading').hide();
-        }
-    });
-}
-
-function selectTopTab(i) {
-    var chart = tables;
-    showChart = false;
-    if (i < tables) {
-        selectedTable = i;
-        showLog();
-    } else if (i === chart) {
-        showChart = true;
-        drawChart();
-    } else if (i === chart + 1) {
-        showAchivementTable();
-    } else if (i === chart + 2) {
-        setSortieStat();
-    }
-    if (i < tables)
-        $('#term').show();
-    else
-        $('#term').hide();
-    var tab = $('.tab0 li');
-    tab.removeClass('select');
-    tab.eq(i).addClass('select');
-    $('#main_contents .hide').hide();
-    $('#main_contents .hide').eq(i).show();
-}
-
-function initAction() {
-    $('.tab0 li').click(function () {
-        var tab = $('.tab0 li');
-        var i = tab.index(this);
-        selectTopTab(i);
-        sessionStorage.setItem('prevTab', i);
-    });
-    $('#range_seq li').click(function () {
-        var tab = $('#range_seq li');
-        var i = tab.index(this);
-        seqChartRange = i;
-        chartType = 0;
-        drawChart();
-        tab.removeClass('select');
-        tab.eq(i).addClass('select');
-        sessionStorage.setItem('prevSeqRange', i);
-    });
-    $('#range_diff li').click(function () {
-        var tab = $('#range_diff li');
-        var i = tab.index(this);
-        diffChartRange = i;
-        chartType = 1;
-        drawChart();
-        tab.removeClass('select');
-        tab.eq(i).addClass('select');
-        sessionStorage.setItem('prevDiffRange', i);
-    });
-    $('input[name="chart_type"]:radio').change(function () {
-        if ($(this).val() === "0") {
-            $("#range_seq").show();
-            $("#range_diff").hide();
-            chartType = 0;
-        } else {
-            $("#range_seq").hide();
-            $("#range_diff").show();
-            chartType = 1;
-        }
-        drawChart();
-        sessionStorage.setItem('chartType', $(this).val());
-    });
-    $('#tooltip').change(function () {
-        drawChart();
-        sessionStorage.setItem('chartTooltip', $(this).prop("checked"));
-    });
-    $('#range_sortie_stat li').click(function () {
-        var tab = $('#range_sortie_stat li');
-        var i = tab.index(this);
-        sortieStatRange = i;
-        tab.removeClass('select');
-        tab.eq(i).addClass('select');
-        if (sortieStatRange === 0) {
-            $('#sortie_stat_recent_tables').show();
-            $('#sortie_stat_all_table').hide();
-        } else {
-            $('#sortie_stat_recent_tables').hide();
-            $('#sortie_stat_all_table').show();
-        }
-        setSortieStat();
-    });
-}
-
-function initTableDatePicker() {
-    $('#term_from').datepicker({
-        defaultDate: moment().subtract(1, 'months').toDate(),
-        onClose: function () { $('input[name=term]').val(['1']) }
-    });
-    $('#term_to').datepicker({
-        onClose: function () { $('input[name=term]').val(['1']) }
-    });
-    $('#term_apply').click(showLog);
-}
-
-function initChartDatePicker() {
-    $('#chart_from').datepicker({
-        onClose: function () { if (useChartDatePicker()) drawChart(); }
-    });
-    $('#chart_to').datepicker({
-        onClose: function () { if (useChartDatePicker()) drawChart(); }
-    });
-}
-
-function useChartDatePicker() {
-    return (chartType === 0 && seqChartRange === 5) ||
-        (chartType === 1 && diffChartRange === 4);
-}
-
-function initSortieStatDatePicker() {
-    $('#sortie_stat_from').datepicker({
-        onClose: function () { if (sortieStatRange === 1) setSortieStat(); }
-    });
-    $('#sortie_stat_to').datepicker({
-        onClose: function () { if (sortieStatRange === 1) setSortieStat(); }
-    });
-}
-
-function restoreChartSettings() {
-    var type = sessionStorage.getItem('chartType');
-    chartType = type == null ? 0 : +type;
-    var tooltip = sessionStorage.getItem('chartTooltip');
-    $('#tooltip').prop('checked', tooltip === "true");
-    var range = sessionStorage.getItem('prevSeqRange');
-    seqChartRange = range == null ? 0 : +range;
-    range = sessionStorage.getItem('prevDiffRange');
-    diffChartRange = range == null ? 0 : +range;
-    $('input[name="chart_type"]:radio').eq(chartType).prop('checked', true);
-    if (chartType === 0) {
-        $('#range_seq').show();
-        $('#range_diff').hide();
-    } else {
-        $('#range_seq').hide();
-        $('#range_diff').show();
-    }
-    $('#range_diff li').removeClass('select');
-    $('#range_diff li').eq(diffChartRange).addClass('select');
-    $('#range_seq li').removeClass('select');
-    $('#range_seq li').eq(seqChartRange).addClass('select');
-}
-
-$(function () {
-    $.fn.dataTable.ext.errMode = 'throw';
-    initAction();
-    initTableDatePicker();
-    initChartDatePicker();
-    initSortieStatDatePicker();
-    $('table').addClass('display compact cell-border');
-    initTables();
-    initAchievementTable();
-    initSortieStatTables();
-    $('#range_sortie_stat li').removeClass('select');
-    $('#range_sortie_stat li').eq(sortieStatRange).addClass('select');
-    restoreChartSettings();
-    var prev = sessionStorage.getItem('prevTab');
-    selectTopTab(prev == null ? 0 : +prev);
-});
 </script>
 
-<div id="loading"><img src="https://kancollesniffer.osdn.jp/ajax-loader.gif" alt="読み込み中..."></div>
-
-<ul class="tab tab0">
-<li>ドロップ</li>
-<li>海戦</li>
-<li>遠征</li>
-<li>開発</li>
-<li>建造</li>
-<li>改修</li>
-<li>資材</li>
-<li>資材グラフ</li>
-<li>戦果</li>
-<li>出撃統計</li>
-</ul>
-
-<form id="term">
-<p>
-<label><input type="radio" name="term" value="0" checked="checked">直近一か月</label>
-<label><input type="radio" name="term" value="1">期間指定: </label>
-<input type="text" id="term_from" style="width: 7em">~<input type="text" id="term_to" style="width: 7em">
-<input type="button" id="term_apply" value="適用">
-</p>
-</form>
-
-<ul class="contents" id="main_contents">
-<li class="hide">
-<table id="log0">
-<thead>
-<tr><th>日付</th><th>海域</th><th>マス</th><th>ボス</th><th>ランク</th><th>ドロップ艦種</th><th>ドロップ艦娘</th></tr>
-</thead>
-</table>
+<main-tab></main-tab>
 
-<li class="hide">
-<table id="log1">
-<thead>
-<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><th>味方制空値</th><th>敵制空値</th><th>制空状態</th></tr>
-</thead>
-</table>
+<log-term></log-term>
 
-<li class="hide">
-<table id="log2">
-<thead>
-<tr><th>日付</th><th>結果</th><th>遠征</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>開発資材</th><th>高速修復材</th><th>高速建造材</th></tr>
-</thead>
-</table>
+<log-tables></log-tables>
 
-<li class="hide">
-<table id="log3">
-<thead>
-<tr><th>日付</th><th>開発装備</th><th>種別</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>秘書艦</th><th>司令部Lv</th></tr>
-</thead>
-</table>
+<chart-type></chart-type>
 
-<li class="hide">
-<table id="log4">
-<thead>
-<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>
-</thead>
-</table>
+<chart-range></chart-range>
 
-<li class="hide">
-<table id="log5">
-<thead>
-<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>
-</thead>
-</table>
+<sequential-chart></sequential-chart>
 
-<li class="hide">
-<table id="log6">
-<thead>
-<tr><th>日付</th><th>燃料</th><th>弾薬</th><th>鋼材</th><th>ボーキ</th><th>高速建造材</th><th>高速修復材</th><th>開発資材</th><th>改修資材</th></tr>
-</thead>
-</table>
+<differential-chart></differential-chart>
 
-<li class="hide">
-<form id="chart_type">
-<div style="margin: 0 0 0.5em 1em;">
-<label><input type="radio" name="chart_type" value="0" checked="checked">連続</label>
-<label><input type="radio" name="chart_type" value="1">差分</label>
-</div>
-</form>
-<ul class="tab tab1" id="range_seq" style="float: left; margin-right: 0.2em">
-<li>一日</li>
-<li>一週間</li>
-<li>一か月</li>
-<li>三か月</li>
-<li>すべて</li>
-<li>期間指定</li>
-</ul>
-<ul class="tab tab1" id="range_diff" style="float: left; margin-right: 0.2em">
-<li>一か月(日)</li>
-<li>三か月(日)</li>
-<li>半年(週)</li>
-<li>すべて(週)</li>
-<li>期間指定</li>
-</ul>
-<div style="padding: 0.2em 0;">
-<input type="text" id="chart_from" style="width: 7em">~<input type="text" id="chart_to" style="width: 7em">
-<label><input type="checkbox" id="tooltip" value="" style="margin-left: 2em;">ツールチップ</label>
-</div>
-<div id="chart" style="clear: both; margin: 1em;"></div>
+<material-chart></material-chart>
 
-<li class="hide">
-<table id="achivement_table">
-<thead>
-<tr><th>日付</th><th>戦果</th><th>EO</th><th>月毎</th></tr>
-</thead>
-</table>
+<achivement-table></achivement-table>
 
-<li class="hide">
-<ul class="tab tab1" id="range_sortie_stat" style="float: left; margin-right: 0.2em">
-<li>直近</li>
-<li>期間指定</li>
-</ul>
-<div style="padding: 0.2em 0;">
-<input type="text" id="sortie_stat_from" style="width: 7em">~<input type="text" id="sortie_stat_to" style="width: 7em">
-</div>
+<sortie-stat></sortie-stat>
 
-<div id="sortie_stat_recent_tables" style="clear: both;">
+<script src="tags.html" type="riot/tag"></script>
 
-<h3>今日</h3>
-<table id="sortie_stat_day">
-<thead>
-<tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th><th>輸送船</th></tr>
-</thead>
-</table>
-
-<h3>今週</h3>
-<table id="sortie_stat_week">
-<thead>
-<tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th><th>輸送船</th></tr>
-</table>
-
-<h3>今月</h3>
-<table id="sortie_stat_month">
-<thead>
-<tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th></tr>
-</table>
-</div>
-
-<div id="sortie_stat_all_table" style="display: none;">
-<table id="sortie_stat_all">
-<thead>
-<tr><th>マップ</th><th>出撃</th><th>S</th><th>A</th><th>B</th><th>C</th><th>D以下</th><th>輸送船</th></tr>
-</thead>
-</table>
-</div>
-
-</ul>
+<script>
+var obs = riot.observable();
+var spec = new Object();
+riot.mixin(mixin);
+riot.mount("log-term", {observable: obs});
+riot.mount("log-tables", {observable: obs});
+riot.mount("chart-type", {observable: obs, chartSpec: spec});
+riot.mount("chart-range", {observable: obs, chartSpec: spec});
+riot.mount("sequential-chart", {observable: obs, chartSpec: spec});
+riot.mount("differential-chart", {observable: obs, chartSpec: spec});
+riot.mount("material-chart", {observable: obs, chartSpec: spec});
+riot.mount("achivement-table", {observable: obs});
+riot.mount("sortie-stat", {observable: obs});
+riot.mount("main-tab", {observable: obs});
+</script>
 </body>
 </html>