summaryrefslogtreecommitdiff
path: root/src/client/widgets/activity.chart.vue
blob: 9702d66663d2e41a10a153ab25cf64871b1aef50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<template>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" @mousedown.prevent="onMousedown">
	<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>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import * as os from '@/os';

function dragListen(fn) {
	window.addEventListener('mousemove',  fn);
	window.addEventListener('mouseleave', dragClear.bind(null, fn));
	window.addEventListener('mouseup',    dragClear.bind(null, fn));
}

function dragClear(fn) {
	window.removeEventListener('mousemove',  fn);
	window.removeEventListener('mouseleave', dragClear);
	window.removeEventListener('mouseup',    dragClear);
}

export default defineComponent({
	props: ['data'],
	data() {
		return {
			viewBoxX: 147,
			viewBoxY: 60,
			zoom: 1,
			pos: 0,
			pointsNote: null,
			pointsReply: null,
			pointsRenote: null,
			pointsTotal: null
		};
	},
	created() {
		for (const d of this.data) {
			d.total = d.notes + d.replies + d.renotes;
		}

		this.render();
	},
	methods: {
		render() {
			const peak = Math.max.apply(null, this.data.map(d => d.total));
			if (peak != 0) {
				const data = this.data.slice().reverse();
				this.pointsNote = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.notes / peak)) * this.viewBoxY}`).join(' ');
				this.pointsReply = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' ');
				this.pointsRenote = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.renotes / peak)) * this.viewBoxY}`).join(' ');
				this.pointsTotal = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ');
			}
		},
		onMousedown(e) {
			const clickX = e.clientX;
			const clickY = e.clientY;
			const baseZoom = this.zoom;
			const basePos = this.pos;

			// 動かした時
			dragListen(me => {
				let moveLeft = me.clientX - clickX;
				let moveTop = me.clientY - clickY;

				this.zoom = baseZoom + (-moveTop / 20);
				this.pos = basePos + moveLeft;
				if (this.zoom < 1) this.zoom = 1;
				if (this.pos > 0) this.pos = 0;
				if (this.pos < -(((this.data.length - 1) * this.zoom) - this.viewBoxX)) this.pos = -(((this.data.length - 1) * this.zoom) - this.viewBoxX);

				this.render();
			});
		}
	}
});
</script>

<style lang="scss" scoped>
svg {
	display: block;
	padding: 16px;
	width: 100%;
	box-sizing: border-box;
	cursor: all-scroll;
}
</style>