一時間ごとのグラフも見れるように
This commit is contained in:
		
							parent
							
								
									8fc1e07136
								
							
						
					
					
						commit
						71a5662195
					
				
					 4 changed files with 251 additions and 148 deletions
				
			
		| 
						 | 
				
			
			@ -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(' ');
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(' ');
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(' ');
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue