diff --git a/src/classes/utils.js b/src/classes/utils.js index eddfae31..ded16a23 100644 --- a/src/classes/utils.js +++ b/src/classes/utils.js @@ -1,3 +1,5 @@ +let echarts = null; + export default { removeFromArray(array, item) { var { length } = array; @@ -319,5 +321,15 @@ export default { return 0; }); return node; + }, + // lazy load echarts + loadEcharts() { + if (echarts) { + return Promise.resolve(echarts); + } + return import('echarts').then((module) => { + echarts = module; + return echarts; + }); } }; diff --git a/src/components/charts/InstanceActivity.vue b/src/components/charts/InstanceActivity.vue index 9c47e3ce..9f39ce2f 100644 --- a/src/components/charts/InstanceActivity.vue +++ b/src/components/charts/InstanceActivity.vue @@ -2,10 +2,9 @@
- Instance Activity + {{ $t('view.charts.instance_activity.header') }}
-
{{ $t('view.charts.instance_activity.tips.header') }}
{{ $t('view.charts.instance_activity.tips.online_time') }}
{{ $t('view.charts.instance_activity.tips.click_Y_axis') }}
{{ $t('view.charts.instance_activity.tips.click_instance_name') }}
@@ -15,7 +14,11 @@
- +
@@ -31,7 +34,6 @@
{ + configRepository.getInt('VRCX_InstanceActivityBarWidth', 25).then((value) => { this.barWidth = value; }); configRepository.getBool('VRCX_InstanceActivityDetailVisible', true).then((value) => { @@ -248,7 +249,7 @@ configRepository.getBool('VRCX_InstanceActivitySoloInstanceVisible', true).then((value) => { this.isSoloInstanceVisible = value; }); - configRepository.getBool('VRCX_InstanceActivityNoFriendInstaceVisible', true).then((value) => { + configRepository.getBool('VRCX_InstanceActivityNoFriendInstanceVisible', true).then((value) => { this.isNoFriendInstanceVisible = value; }); }, @@ -256,22 +257,20 @@ try { const [echartsModule] = await Promise.all([ // lazy load echarts - // reduce the VRCX initial screen load times - // TODO: export lazy load func to a single file - import('echarts').catch((error) => { + utils.loadEcharts().catch((error) => { console.error('lazy load echarts failed', error); return null; }), - this.getActivityData() + this.getActivityData(), + this.getAllDateOfActivity() ]); if (echartsModule) { - echarts = echartsModule; + this.echarts = echartsModule; } - if (this.activityData.length && echarts) { + if (this.activityData.length && this.echarts) { // activity data is ready, but world name data isn't ready // so init echarts with empty data, reduce the render time of init screen this.initEcharts(true); - this.getAllDateOfActivity(); this.getWorldNameData(); } else { this.isLoading = false; @@ -292,7 +291,7 @@ const chartsHeight = this.activityData.length * (this.barWidth + 10) + 200; const chartDom = this.$refs.activityChartRef; if (!this.echartsInstance) { - this.echartsInstance = echarts.init(chartDom, `${this.isDarkMode ? 'dark' : null}`, { + this.echartsInstance = this.echarts.init(chartDom, `${this.isDarkMode ? 'dark' : null}`, { height: chartsHeight }); this.resizeObserver.observe(chartDom); @@ -484,7 +483,7 @@ }, changeIsNoFriendInstanceVisible(value) { this.isNoFriendInstanceVisible = value; - configRepository.setBool('VRCX_InstanceActivityNoFriendInstaceVisible', value).finally(() => { + configRepository.setBool('VRCX_InstanceActivityNoFriendInstanceVisible', value).finally(() => { this.handleChangeSettings(); }); }, @@ -510,7 +509,6 @@ if (idx !== -1) { if (isNext) { if (idx - 1 < this.allDateOfActivityArray.length) { - console.log(this.selectedDate, this.allDateOfActivityArray[idx + 1]); this.selectedDate = this.allDateOfActivityArray[idx - 1]; this.reloadData(); } @@ -728,17 +726,19 @@ } } .tips-popover { - :first-child { - font-size: 14px; - font-weight: bold; - margin-bottom: 5px; - } - :not(:first-child) { + & > div { margin-bottom: 5px; font-size: 12px; } - i { - margin-right: 3px; + & > div:last-child { + @extend %flex; + margin-top: 10px; + i { + margin-right: 3px; + } + } + & .el-icon-warning-outline { + font-size: 12px; } } .settings { @@ -754,7 +754,7 @@ & > div:first-child { > div { width: 160px; - padding-left: 15px; + padding-left: 20px; } } } diff --git a/src/components/charts/InstanceActivityDetail.vue b/src/components/charts/InstanceActivityDetail.vue index b9d16f8b..24e6b5a9 100644 --- a/src/components/charts/InstanceActivityDetail.vue +++ b/src/components/charts/InstanceActivityDetail.vue @@ -20,8 +20,6 @@ import dayjs from 'dayjs'; import utils from '../../classes/utils'; - let echarts = null; - export default { name: 'InstanceActivityDetail', inject: ['API', 'showUserDialog'], @@ -46,6 +44,7 @@ }, data() { return { + echarts: null, isLoading: true, echartsInstance: null, usersFirstActivity: null, @@ -100,14 +99,15 @@ methods: { async initEcharts(isFirstLoad = false) { - // TODO: unnecessary import, import from individual js file - await import('echarts').then((echartsModule) => { - echarts = echartsModule; - }); + if (!this.echarts) { + const module = await utils.loadEcharts(); + this.echarts = module; + } + 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}`, { + this.echartsInstance = this.echarts.init(chartDom, `${this.isDarkMode ? 'dark' : null}`, { height: chartsHeight, useDirtyRect: this.activityDetailData.length > 80 }); @@ -149,15 +149,25 @@ uniqueUserEntries.push(entry); } const elements = userGroupedEntries.get(entry.user_id); - const offset = Math.max(0, elements.length === 0 ? entry.joinTime.valueOf() - this.startTimeStamp : entry.joinTime.valueOf() - this.startTimeStamp - elements[elements.length - 1].tail); - const tail = elements.length === 0 ? offset + entry.time : elements[elements.length - 1].tail + offset + entry.time; - const element = { offset: offset, time: entry.time, tail: tail, entry: entry }; + const offset = Math.max( + 0, + elements.length === 0 + ? entry.joinTime.valueOf() - this.startTimeStamp + : entry.joinTime.valueOf() - this.startTimeStamp - elements[elements.length - 1].tail + ); + const tail = + elements.length === 0 + ? offset + entry.time + : elements[elements.length - 1].tail + offset + entry.time; + const element = { offset, time: entry.time, tail, entry }; elements.push(element); } this.usersFirstActivity = uniqueUserEntries; const generateSeries = () => { - const maxEntryCount = Math.max(...Array.from(userGroupedEntries.values()).map((entries) => entries.length)); + const maxEntryCount = Math.max( + ...Array.from(userGroupedEntries.values()).map((entries) => entries.length) + ); const placeholderSeries = (data) => { return { name: 'Placeholder', @@ -173,7 +183,7 @@ color: 'transparent' } }, - data: data, + data }; }; const timeSeries = (data) => { @@ -183,29 +193,38 @@ stack: 'Total', colorBy: 'data', barWidth: this.barWidth, + emphasis: { + focus: 'self' + }, itemStyle: { borderRadius: 2, shadowBlur: 2, shadowOffsetX: 0.7, shadowOffsetY: 0.5 }, - data: data, + data }; }; // generate series having placeholder and time series for each user - const series = Array(maxEntryCount).fill(0).flatMap((_, index) => { - return [ - placeholderSeries(uniqueUserEntries.map((entry) => { - const element = userGroupedEntries.get(entry.user_id)[index]; - return element ? element.offset : 0; - })), - timeSeries(uniqueUserEntries.map((entry) => { - const element = userGroupedEntries.get(entry.user_id)[index]; - return element ? element.time : 0; - })) - ]; - }); + const series = Array(maxEntryCount) + .fill(0) + .flatMap((_, index) => { + return [ + placeholderSeries( + uniqueUserEntries.map((entry) => { + const element = userGroupedEntries.get(entry.user_id)[index]; + return element ? element.offset : 0; + }) + ), + timeSeries( + uniqueUserEntries.map((entry) => { + const element = userGroupedEntries.get(entry.user_id)[index]; + return element ? element.time : 0; + }) + ) + ]; + }); return series; }; diff --git a/src/localization/en/en.json b/src/localization/en/en.json index 554c0870..9d88e751 100644 --- a/src/localization/en/en.json +++ b/src/localization/en/en.json @@ -229,8 +229,8 @@ "tips": { "header": "Tips", "online_time": "Online time refers to the game time recorded by VRCX for the current day.", - "click_Y_axis": "Click Y-axis label to open user/world dialog.", - "click_instance_name": "Click instance name for previous instance info.", + "click_Y_axis": "Click Y-axis label to navigate to the instance details or open User dialog.", + "click_instance_name": "Click instance name to open Previous Instance Info dialog.", "accuracy_notice": "Info from local database may not be accurate" }, "settings": { diff --git a/src/localization/ja/en.json b/src/localization/ja/en.json index b9bfe7d2..268fa85d 100644 --- a/src/localization/ja/en.json +++ b/src/localization/ja/en.json @@ -221,7 +221,7 @@ "charts": { "header": "チャート", "instance_activity": { - "header": "インスタンスアクティビティ", + "header": "インスタンスログ", "online_time": "オンライン時間", "previous_day": "前日", "next_day": "翌日", @@ -229,8 +229,8 @@ "tips": { "header": "ヒント", "online_time": "オンライン時間とは、VRCXが記録した当日のゲームプレイ時間です。", - "click_Y_axis": "Y軸ラベルをクリックでプレイヤー/ワールドダイアログを表示します。", - "click_instance_name": "インスタンス名をクリックで以前のインスタンス情報ダイアログを表示します。", + "click_Y_axis": "Y軸ラベルをクリックで、インスタンスの詳細へジャンプ、またはユーザーダイアログを表示できます。", + "click_instance_name": "インスタンス名をクリックで、以前のインスタンス情報ダイアログを表示できます。", "accuracy_notice": "ローカルデータベースからの情報であり、正確ではない可能性があります。" }, "settings": {