1
0
mirror of https://github.com/misskey-dev/misskey synced 2024-11-29 07:18:52 +09:00

一時間ごとのグラフも見れるように

This commit is contained in:
syuilo 2018-08-23 16:36:23 +09:00
parent 8fc1e07136
commit 71a5662195
4 changed files with 251 additions and 148 deletions

View File

@ -1,11 +1,14 @@
<template>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<polyline
:points="points"
fill="none"
stroke-width="1"
stroke="#555"/>
</svg>
<div>
<a @click="span = 'day'">Per day</a> | <a @click="span = 'hour'">Per hour</a>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<polyline
:points="points"
fill="none"
stroke-width="0.3"
stroke="#555"/>
</svg>
</div>
</template>
<script lang="ts">
@ -23,20 +26,40 @@ export default Vue.extend({
},
data() {
return {
viewBoxX: 365,
viewBoxY: 70,
points: null
viewBoxX: 100,
viewBoxY: 30,
points: null,
span: 'day'
};
},
created() {
const peak = Math.max.apply(null, this.chart.map(d => this.type == 'local' ? d.drive.local.totalSize : d.drive.remote.totalSize));
computed: {
stats(): any[] {
return (
this.span == 'day' ? this.chart.perDay :
this.span == 'hour' ? this.chart.perHour :
null
);
}
},
watch: {
stats() {
this.render();
}
},
mounted() {
this.render();
},
methods: {
render() {
const peak = Math.max.apply(null, this.stats.map(d => this.type == 'local' ? d.drive.local.totalSize : d.drive.remote.totalSize));
if (peak != 0) {
const data = this.chart.slice().reverse().map(x => ({
size: this.type == 'local' ? x.drive.local.totalSize : x.drive.remote.totalSize
}));
if (peak != 0) {
const data = this.stats.slice().reverse().map(x => ({
size: this.type == 'local' ? x.drive.local.totalSize : x.drive.remote.totalSize
}));
this.points = data.map((d, i) => `${i},${(1 - (d.size / peak)) * this.viewBoxY}`).join(' ');
this.points = data.map((d, i) => `${(this.viewBoxX / data.length) * i},${(1 - (d.size / peak)) * this.viewBoxY}`).join(' ');
}
}
}
});

View File

@ -1,27 +1,30 @@
<template>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<polyline
:points="pointsNote"
fill="none"
stroke-width="1"
stroke="#41ddde"/>
<polyline
:points="pointsReply"
fill="none"
stroke-width="1"
stroke="#f7796c"/>
<polyline
:points="pointsRenote"
fill="none"
stroke-width="1"
stroke="#a1de41"/>
<polyline
:points="pointsTotal"
fill="none"
stroke-width="1"
stroke="#555"
stroke-dasharray="2 2"/>
</svg>
<div>
<a @click="span = 'day'">Per day</a> | <a @click="span = 'hour'">Per hour</a>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<polyline
:points="pointsNote"
fill="none"
stroke-width="0.3"
stroke="#41ddde"/>
<polyline
:points="pointsReply"
fill="none"
stroke-width="0.3"
stroke="#f7796c"/>
<polyline
:points="pointsRenote"
fill="none"
stroke-width="0.3"
stroke="#a1de41"/>
<polyline
:points="pointsTotal"
fill="none"
stroke-width="0.3"
stroke="#555"
stroke-dasharray="1 1"/>
</svg>
</div>
</template>
<script lang="ts">
@ -39,29 +42,49 @@ export default Vue.extend({
},
data() {
return {
viewBoxX: 365,
viewBoxY: 70,
viewBoxX: 100,
viewBoxY: 30,
pointsNote: null,
pointsReply: null,
pointsRenote: null,
pointsTotal: null
pointsTotal: null,
span: 'day'
};
},
created() {
const peak = Math.max.apply(null, this.chart.map(d => this.type == 'local' ? d.notes.local.diff : d.notes.remote.diff));
computed: {
stats(): any[] {
return (
this.span == 'day' ? this.chart.perDay :
this.span == 'hour' ? this.chart.perHour :
null
);
}
},
watch: {
stats() {
this.render();
}
},
mounted() {
this.render();
},
methods: {
render() {
const peak = Math.max.apply(null, this.stats.map(d => this.type == 'local' ? d.notes.local.diff : d.notes.remote.diff));
if (peak != 0) {
const data = this.chart.slice().reverse().map(x => ({
normal: this.type == 'local' ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal,
reply: this.type == 'local' ? x.notes.local.diffs.reply : x.notes.remote.diffs.reply,
renote: this.type == 'local' ? x.notes.local.diffs.renote : x.notes.remote.diffs.renote,
total: this.type == 'local' ? x.notes.local.diff : x.notes.remote.diff
}));
if (peak != 0) {
const data = this.stats.slice().reverse().map(x => ({
normal: this.type == 'local' ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal,
reply: this.type == 'local' ? x.notes.local.diffs.reply : x.notes.remote.diffs.reply,
renote: this.type == 'local' ? x.notes.local.diffs.renote : x.notes.remote.diffs.renote,
total: this.type == 'local' ? x.notes.local.diff : x.notes.remote.diff
}));
this.pointsNote = data.map((d, i) => `${i},${(1 - (d.normal / peak)) * this.viewBoxY}`).join(' ');
this.pointsReply = data.map((d, i) => `${i},${(1 - (d.reply / peak)) * this.viewBoxY}`).join(' ');
this.pointsRenote = data.map((d, i) => `${i},${(1 - (d.renote / peak)) * this.viewBoxY}`).join(' ');
this.pointsTotal = data.map((d, i) => `${i},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ');
this.pointsNote = data.map((d, i) => `${(this.viewBoxX / data.length) * i},${(1 - (d.normal / peak)) * this.viewBoxY}`).join(' ');
this.pointsReply = data.map((d, i) => `${(this.viewBoxX / data.length) * i},${(1 - (d.reply / peak)) * this.viewBoxY}`).join(' ');
this.pointsRenote = data.map((d, i) => `${(this.viewBoxX / data.length) * i},${(1 - (d.renote / peak)) * this.viewBoxY}`).join(' ');
this.pointsTotal = data.map((d, i) => `${(this.viewBoxX / data.length) * i},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ');
}
}
}
});

View File

@ -1,11 +1,14 @@
<template>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<polyline
:points="points"
fill="none"
stroke-width="1"
stroke="#555"/>
</svg>
<div>
<a @click="span = 'day'">Per day</a> | <a @click="span = 'hour'">Per hour</a>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<polyline
:points="points"
fill="none"
stroke-width="0.3"
stroke="#555"/>
</svg>
</div>
</template>
<script lang="ts">
@ -23,20 +26,40 @@ export default Vue.extend({
},
data() {
return {
viewBoxX: 365,
viewBoxY: 70,
points: null
viewBoxX: 100,
viewBoxY: 30,
points: null,
span: 'day'
};
},
created() {
const peak = Math.max.apply(null, this.chart.map(d => this.type == 'local' ? d.users.local.diff : d.users.remote.diff));
computed: {
stats(): any[] {
return (
this.span == 'day' ? this.chart.perDay :
this.span == 'hour' ? this.chart.perHour :
null
);
}
},
watch: {
stats() {
this.render();
}
},
mounted() {
this.render();
},
methods: {
render() {
const peak = Math.max.apply(null, this.stats.map(d => this.type == 'local' ? d.users.local.diff : d.users.remote.diff));
if (peak != 0) {
const data = this.chart.slice().reverse().map(x => ({
count: this.type == 'local' ? x.users.local.diff : x.users.remote.diff
}));
if (peak != 0) {
const data = this.stats.slice().reverse().map(x => ({
count: this.type == 'local' ? x.users.local.diff : x.users.remote.diff
}));
this.points = data.map((d, i) => `${i},${(1 - (d.count / peak)) * this.viewBoxY}`).join(' ');
this.points = data.map((d, i) => `${(this.viewBoxX / data.length) * i},${(1 - (d.count / peak)) * this.viewBoxY}`).join(' ');
}
}
}
});

View File

@ -8,96 +8,130 @@ export const meta = {
};
export default (params: any) => new Promise(async (res, rej) => {
const daysRange = 365;
const hoursRange = 24;
const now = new Date();
const y = now.getFullYear();
const m = now.getMonth();
const d = now.getDate();
const h = now.getHours();
const stats = await Stats.find({
span: 'day',
date: {
$gt: new Date(y - 1, m, d)
}
}, {
sort: {
date: -1
},
fields: {
_id: 0
}
});
const [statsPerDay, statsPerHour] = await Promise.all([
Stats.find({
span: 'day',
date: {
$gt: new Date(y, m, d - daysRange)
}
}, {
sort: {
date: -1
},
fields: {
_id: 0
}
}),
Stats.find({
span: 'hour',
date: {
$gt: new Date(y, m, d, h - hoursRange)
}
}, {
sort: {
date: -1
},
fields: {
_id: 0
}
}),
]);
const chart: Array<Omit<IStats, '_id'>> = [];
const format = (src: IStats[], span: 'day' | 'hour') => {
const chart: Array<Omit<Omit<IStats, '_id'>, 'span'>> = [];
for (let i = 364; i >= 0; i--) {
const day = new Date(y, m, d - i);
const range =
span == 'day' ? daysRange :
span == 'hour' ? hoursRange :
null;
const stat = stats.find(s => s.date.getTime() == day.getTime());
for (let i = (range - 1); i >= 0; i--) {
const current =
span == 'day' ? new Date(y, m, d - i) :
span == 'hour' ? new Date(y, m, d, h - i) :
null;
if (stat) {
chart.unshift(stat);
} else { // 隙間埋め
const mostRecent = stats.find(s => s.date.getTime() < day.getTime());
if (mostRecent) {
chart.unshift(Object.assign({}, mostRecent, {
date: day
}));
} else {
chart.unshift({
date: day,
span: 'day',
users: {
local: {
total: 0,
diff: 0
},
remote: {
total: 0,
diff: 0
}
},
notes: {
local: {
total: 0,
diff: 0,
diffs: {
normal: 0,
reply: 0,
renote: 0
const stat = src.find(s => s.date.getTime() == current.getTime());
if (stat) {
chart.unshift(stat);
} else { // 隙間埋め
const mostRecent = src.find(s => s.date.getTime() < current.getTime());
if (mostRecent) {
chart.unshift(Object.assign({}, mostRecent, {
date: current
}));
} else {
chart.unshift({
date: current,
users: {
local: {
total: 0,
diff: 0
},
remote: {
total: 0,
diff: 0
}
},
remote: {
total: 0,
diff: 0,
diffs: {
normal: 0,
reply: 0,
renote: 0
notes: {
local: {
total: 0,
diff: 0,
diffs: {
normal: 0,
reply: 0,
renote: 0
}
},
remote: {
total: 0,
diff: 0,
diffs: {
normal: 0,
reply: 0,
renote: 0
}
}
},
drive: {
local: {
totalCount: 0,
totalSize: 0,
diffCount: 0,
diffSize: 0
},
remote: {
totalCount: 0,
totalSize: 0,
diffCount: 0,
diffSize: 0
}
}
},
drive: {
local: {
totalCount: 0,
totalSize: 0,
diffCount: 0,
diffSize: 0
},
remote: {
totalCount: 0,
totalSize: 0,
diffCount: 0,
diffSize: 0
}
}
});
});
}
}
}
}
chart.forEach(x => {
delete x.date;
chart.forEach(x => {
delete x.date;
delete (x as any).span;
});
return chart;
};
res({
perDay: format(statsPerDay, 'day'),
perHour: format(statsPerHour, 'hour')
});
res(chart);
});