mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-22 16:23:50 +02:00
improve: instance activity chart (#1144)
* improve: instance activity chart * wip: ? * Wrong commit * add prev/next day btn, bar width setting, i18n * add show solo, no friend instance btn, add friend icon, i18n * add favorite friend icon, tips, improve the chart display effect, and i18n
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="width: 100%">
|
||||
<div style="height: 25px; margin-top: 60px">
|
||||
<transition name="el-fade-in-linear">
|
||||
<location
|
||||
@@ -30,13 +30,18 @@
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
activityData: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
isDarkMode: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
dtHour12: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
barWidth: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 10
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -48,16 +53,30 @@
|
||||
},
|
||||
computed: {
|
||||
startTimeStamp() {
|
||||
return this.activityData
|
||||
.find((item) => item.location === this.activityDetailData[0].location)
|
||||
return this.activityDetailData
|
||||
.find((item) => item.user_id === this.API.currentUser.id)
|
||||
?.joinTime.valueOf();
|
||||
},
|
||||
endTimeStamp() {
|
||||
return this.activityData
|
||||
.findLast((item) => item.location === this.activityDetailData[0].location)
|
||||
return this.activityDetailData
|
||||
.find((item) => item.user_id === this.API.currentUser.id)
|
||||
?.leaveTime.valueOf();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isDarkMode() {
|
||||
if (this.echartsInstance) {
|
||||
this.echartsInstance.dispose();
|
||||
this.echartsInstance = null;
|
||||
this.initEcharts();
|
||||
}
|
||||
},
|
||||
dtHour12() {
|
||||
if (this.echartsInstance) {
|
||||
this.initEcharts();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
@@ -70,38 +89,46 @@
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.initEcharts(true);
|
||||
},
|
||||
deactivated() {
|
||||
// prevent switch tab play resize animation
|
||||
this.resizeObserver.disconnect();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async initEcharts() {
|
||||
async initEcharts(isFirstLoad = false) {
|
||||
// TODO: unnecessary import, import from individual js file
|
||||
await import('echarts').then((echartsModule) => {
|
||||
echarts = echartsModule;
|
||||
});
|
||||
const chartsHeight = this.activityDetailData.length * (this.barWidth + 10) + 200;
|
||||
const chartDom = this.$refs.activityDetailChart;
|
||||
if (!this.echartsInstance) {
|
||||
this.echartsInstance = echarts.init(chartDom, `${this.isDarkMode ? 'dark' : null}`, {
|
||||
height: this.activityDetailData.length * 40 + 200,
|
||||
useDirtyRect: this.activityDetailData.length > 30
|
||||
height: chartsHeight,
|
||||
useDirtyRect: this.activityDetailData.length > 80
|
||||
});
|
||||
this.resizeObserver.observe(chartDom);
|
||||
}
|
||||
|
||||
this.echartsInstance.resize({
|
||||
height: this.activityDetailData.length * 40 + 200,
|
||||
height: chartsHeight,
|
||||
animation: {
|
||||
duration: 300
|
||||
}
|
||||
});
|
||||
|
||||
this.echartsInstance.setOption(this.getNewOption(), { lazyUpdate: true });
|
||||
this.echartsInstance.setOption(isFirstLoad ? {} : this.getNewOption(), { lazyUpdate: true });
|
||||
this.echartsInstance.on('click', 'yAxis', this.handleClickYAxisLabel);
|
||||
|
||||
setTimeout(() => {
|
||||
this.isLoading = false;
|
||||
this.echartsInstance.dispatchAction({
|
||||
type: 'highlight',
|
||||
seriesIndex: 3 // 对于 seriesLayoutBy: 'row',seriesIndex 对应行索引
|
||||
});
|
||||
}, 200);
|
||||
},
|
||||
handleClickYAxisLabel(params) {
|
||||
@@ -111,6 +138,22 @@
|
||||
}
|
||||
},
|
||||
getNewOption() {
|
||||
const friendOrFavIcon = (display_name) => {
|
||||
const foundItem = this.activityDetailData.find((item) => item.display_name === display_name);
|
||||
|
||||
if (!foundItem) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (foundItem.isFavorite) {
|
||||
return '⭐';
|
||||
}
|
||||
if (foundItem.isFriend) {
|
||||
return '💚';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const getTooltip = (params) => {
|
||||
const activityDetailData = this.activityDetailData;
|
||||
const param = params[1];
|
||||
@@ -121,8 +164,9 @@
|
||||
|
||||
const instanceData = activityDetailData[param.dataIndex];
|
||||
|
||||
const formattedLeftDateTime = dayjs(instanceData.leaveTime).format('HH:mm:ss');
|
||||
const formattedJoinDateTime = dayjs(instanceData.joinTime).format('HH:mm:ss');
|
||||
const format = this.dtHour12 ? 'hh:mm:ss A' : 'HH:mm:ss';
|
||||
const formattedLeftDateTime = dayjs(instanceData.leaveTime).format(format);
|
||||
const formattedJoinDateTime = dayjs(instanceData.joinTime).format(format);
|
||||
|
||||
const timeString = utils.timeToText(instanceData.time, true);
|
||||
const color = param.color;
|
||||
@@ -131,7 +175,7 @@
|
||||
<div style="display: flex; align-items: center;">
|
||||
<div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 5px;"></div>
|
||||
<div>
|
||||
<div>${instanceData.display_name}</div>
|
||||
<div>${instanceData.display_name} ${friendOrFavIcon(instanceData.display_name)}</div>
|
||||
<div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div>
|
||||
<div>${timeString}</div>
|
||||
</div>
|
||||
@@ -139,6 +183,8 @@
|
||||
`;
|
||||
};
|
||||
|
||||
const format = this.dtHour12 ? 'hh:mm A' : 'HH:mm';
|
||||
|
||||
const echartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
@@ -148,7 +194,7 @@
|
||||
formatter: getTooltip
|
||||
},
|
||||
grid: {
|
||||
top: 60,
|
||||
top: 50,
|
||||
left: 160,
|
||||
right: 90
|
||||
},
|
||||
@@ -156,7 +202,11 @@
|
||||
type: 'category',
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
formatter: (value) => (value.length > 20 ? `${value.slice(0, 20)}...` : value)
|
||||
formatter: (value) => {
|
||||
const MAX_LENGTH = 20;
|
||||
const len = value.length;
|
||||
return `${friendOrFavIcon(value)} ${len > MAX_LENGTH ? `${value.substring(0, MAX_LENGTH)}...` : value}`;
|
||||
}
|
||||
},
|
||||
inverse: true,
|
||||
data: this.activityDetailData.map((item) => item.display_name),
|
||||
@@ -168,7 +218,7 @@
|
||||
max: this.endTimeStamp - this.startTimeStamp,
|
||||
axisLine: { show: true },
|
||||
axisLabel: {
|
||||
formatter: (value) => dayjs(value + this.startTimeStamp).format('HH:mm')
|
||||
formatter: (value) => dayjs(value + this.startTimeStamp).format(format)
|
||||
},
|
||||
splitLine: { lineStyle: { type: 'dashed' } }
|
||||
},
|
||||
@@ -194,7 +244,10 @@
|
||||
type: 'bar',
|
||||
stack: 'Total',
|
||||
colorBy: 'data',
|
||||
barWidth: 30,
|
||||
barWidth: this.barWidth,
|
||||
emphasis: {
|
||||
focus: 'self'
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: 2,
|
||||
shadowBlur: 2,
|
||||
@@ -203,12 +256,10 @@
|
||||
},
|
||||
data: this.activityDetailData.map((item) => item.time)
|
||||
}
|
||||
]
|
||||
],
|
||||
backgroundColor: 'rgba(0, 0, 0, 0)'
|
||||
};
|
||||
|
||||
if (this.isDarkMode) {
|
||||
echartsOption.backgroundColor = 'rgba(0, 0, 0, 0)';
|
||||
}
|
||||
return echartsOption;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user