From 1af4f94338c9e0c02178229424400db91ea4c4c2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 22 Oct 2018 22:00:54 +0900
Subject: [PATCH] Implement #2961

---
 .../views/pages/deck/deck.hashtag-column.vue  | 68 ++++++++++++++++++-
 src/server/api/endpoints/charts/hashtag.ts    | 39 +++++++++++
 2 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 src/server/api/endpoints/charts/hashtag.ts

diff --git a/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue b/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
index 70058665e8..5d8c256767 100644
--- a/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
@@ -4,7 +4,10 @@
 		%fa:hashtag%<span>{{ tag }}</span>
 	</span>
 
-	<x-hashtag-tl :tag-tl="tagTl"/>
+	<div class="xroyrflcmhhtmlwmyiwpfqiirqokfueb">
+		<div ref="chart" class="chart"></div>
+		<x-hashtag-tl :tag-tl="tagTl" class="tl"/>
+	</div>
 </x-column>
 </template>
 
@@ -12,6 +15,8 @@
 import Vue from 'vue';
 import XColumn from './deck.column.vue';
 import XHashtagTl from './deck.hashtag-tl.vue';
+import * as G2 from '@antv/g2';
+import * as tinycolor from 'tinycolor2';
 
 export default Vue.extend({
 	components: {
@@ -32,6 +37,67 @@ export default Vue.extend({
 				query: [[this.tag]]
 			};
 		}
+	},
+
+	mounted() {
+		(this as any).api('charts/hashtag', {
+			tag: this.tag,
+			span: 'hour',
+			limit: 30
+		}).then(stats => {
+			const data = [];
+
+			const now = new Date();
+			const y = now.getFullYear();
+			const m = now.getMonth();
+			const d = now.getDate();
+			const h = now.getHours();
+
+			for (let i = 0; i < 30; i++) {
+				const x = new Date(y, m, d, h - i + 1);
+				data.push({
+					x: x,
+					count: stats.count[i]
+				});
+			}
+
+			const chart = new G2.Chart({
+				container: this.$refs.chart as HTMLDivElement,
+				forceFit: true,
+				height: 70,
+				padding: 8,
+				renderer: 'svg'
+			});
+
+			const text = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--primary'));
+
+			chart.area().position('x*count').color(`l(100) 0:${text.clone().setAlpha(0.5).toRgbString()} 1:${text.clone().setAlpha(0.25).toRgbString()}`);
+			chart.line().position('x*count').color(`#${text.clone().toHex()}`).size(2);
+			chart.legend(false);
+			chart.axis('x', false);
+			chart.axis('count', false);
+			chart.tooltip(true, {
+				showTitle: false,
+				crosshairs: {
+					type: 'line'
+				}
+			});
+			chart.source(data);
+			chart.render();
+		});
 	}
 });
 </script>
+
+<style lang="stylus" scoped>
+.xroyrflcmhhtmlwmyiwpfqiirqokfueb
+	background var(--deckColumnBg)
+
+	> .chart
+		margin 16px 0
+		background var(--face)
+
+	> .tl
+		background var(--face)
+
+</style>
diff --git a/src/server/api/endpoints/charts/hashtag.ts b/src/server/api/endpoints/charts/hashtag.ts
new file mode 100644
index 0000000000..b42bc97eff
--- /dev/null
+++ b/src/server/api/endpoints/charts/hashtag.ts
@@ -0,0 +1,39 @@
+import $ from 'cafy';
+import getParams from '../../get-params';
+import { hashtagStats } from '../../../../services/stats';
+
+export const meta = {
+	desc: {
+		'ja-JP': 'ハッシュタグごとの統計を取得します。'
+	},
+
+	params: {
+		span: $.str.or(['day', 'hour']).note({
+			desc: {
+				'ja-JP': '集計のスパン (day または hour)'
+			}
+		}),
+
+		limit: $.num.optional.range(1, 100).note({
+			default: 30,
+			desc: {
+				'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
+			}
+		}),
+
+		tag: $.str.note({
+			desc: {
+				'ja-JP': '対象のハッシュタグ'
+			}
+		}),
+	}
+};
+
+export default (params: any) => new Promise(async (res, rej) => {
+	const [ps, psErr] = getParams(meta, params);
+	if (psErr) throw psErr;
+
+	const stats = await hashtagStats.getChart(ps.span as any, ps.limit, ps.tag);
+
+	res(stats);
+});