WIP #300 Performance page done. Use ref() instead of reactive() in independant Vue3 component.

This commit is contained in:
Cindy Chang
2024-06-13 15:40:51 +08:00
parent f6989c4759
commit 0689e79013
2 changed files with 105 additions and 62 deletions

View File

@@ -1,5 +1,5 @@
<template> <template>
<Chart type="line" :data="freqChartData" :options="freqChartOptions" class="h-96" /> <Chart type="line" :data="primeVueSetDataState" :options="primeVueSetOptionsState" class="h-96" />
</template> </template>
<script> <script>
@@ -19,51 +19,23 @@ const cloneDeep = (obj) => JSON.parse(JSON.stringify(obj));
// 試著把 chart 獨立成一個 vue component // 試著把 chart 獨立成一個 vue component
// 企圖防止 PrimeVue 誤用其他圖表 option 值的 bug // 企圖防止 PrimeVue 誤用其他圖表 option 值的 bug
export default { export default {
setup() { props: {
chartData: {
type: Object,
},
content: {
type: Object,
},
yUnit: {
type: String,
},
},
setup(props) {
const performanceStore = usePerformanceStore(); const performanceStore = usePerformanceStore();
const freqChartData = computed(() => performanceStore.freqChartData);
const originalFreqChartOptions = computed(() => performanceStore.freqChartOptions);
const minX = computed(() => performanceStore.freqChartXData.minX);
const maxX = computed(() => performanceStore.freqChartXData.maxX);
const xData = computed(() => performanceStore.freqChartXData.xData);
const content = computed(() => performanceStore.freqChartXData.content);
const customizedScaleOption = computed(() => {}); const customizedScaleOption = computed(() => {});
const primeVueSetDataState = ref(null);
const updatedFreqChartOptions = ref(cloneDeep(originalFreqChartOptions.value)); const primeVueSetOptionsState = ref(null);
const customizeOptionsFunc = () => {
// Customize X axis ticks due to different differences between min and max of data group
// Compare page and Performance page share the same logic
const formatToSet = setTimeStringFormatBaseOnTimeDifference(minX.value, maxX.value);
const ticksOfXAxis = mapTimestampToAxisTicksByFormat(xData.value, formatToSet);
customizedScaleOption.value = getCustomizedScaleOption(
knownScaleLineChartOptions, {
customizeOptions: {
content, ticksOfXAxis,
}
});
};
const newTicksCallback = (value, index, values) => {
return value; // 沒有單位,只有數值,因為是取計算數量
};
const updateTicksCallback = () => {
//在這裡額外宣告本圖表的 callback 區分跟其他圖表的 callback避免共用 option 造成不預期的共用與混淆
if (updatedFreqChartOptions.value.scales && updatedFreqChartOptions.value.scales.y) {
updatedFreqChartOptions.value = customizedScaleOption;
updatedFreqChartOptions.value.scales.y.ticks.callback = newTicksCallback;
}
};
watch(originalFreqChartOptions, (newOptions) => {
updatedFreqChartOptions.value = cloneDeep(newOptions);
});
/** /**
* Compare page and Performance have this same function. * Compare page and Performance have this same function.
@@ -102,7 +74,7 @@ export default {
}, },
}, },
}, },
}; };
}; };
/** Compare page and Performance have this same function. /** Compare page and Performance have this same function.
@@ -140,14 +112,91 @@ export default {
}; };
}; };
const getLineChartPrimeVueSetting = (chartData, content) => {
let datasets;
let minX = chartData?.x_axis?.min;
let maxX = chartData?.x_axis?.max;
let maxY = chartData?.y_axis?.max;
let xData;
let primeVueSetData = {};
let primeVueSetOption = {};
const getMoment = (time)=> {
return this.$moment(time).format('YYYY/M/D hh:mm:ss')
};
datasets = chartData.data;
xData = chartData.data.map(item => new Date(item.x).getTime());
// Customize X axis ticks due to different differences between min and max of data group
// Compare page and Performance page share the same logic
const formatToSet = setTimeStringFormatBaseOnTimeDifference(minX, maxX);
const ticksOfXAxis = mapTimestampToAxisTicksByFormat(xData, formatToSet);
const customizedScaleOption = getCustomizedScaleOption(
knownScaleLineChartOptions, {
customizeOptions: {
content, ticksOfXAxis,
}
});
primeVueSetData = {
labels: xData,
datasets: [
{
label: content.title,
data: datasets,
fill: false,
tension: 0, // 貝茲曲線張力
borderColor: '#0099FF',
}
]
};
primeVueSetOption = {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
top: 16,
left: 8,
right: 8,
}
},
plugins: {
legend: false, // 圖例
tooltip: {
displayColors: false,
titleFont: {weight: 'normal'},
callbacks: {
title: function(context) {
return `${content.x}: ${getMoment(context[0].parsed.x)}`;
}
},
},
title: {
display: false,
},
},
scales: customizedScaleOption,
};
primeVueSetOption.scales.y.ticks.precision = 0; // y 軸顯示小數點後 0 位
primeVueSetOption.plugins.tooltip.callbacks.label = function(context) {
return `${content.y}: ${context.parsed.y}`;
};
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
return value;
};
primeVueSetDataState.value = primeVueSetData;
primeVueSetOptionsState.value = primeVueSetOption;
};
onMounted(() => { onMounted(() => {
customizeOptionsFunc(); getLineChartPrimeVueSetting(props.chartData, props.content);
}); });
return { return {
freqChartData, ...props,
updatedFreqChartOptions, primeVueSetDataState,
updateTicksCallback, primeVueSetOptionsState,
}; };
} }
}; };

View File

@@ -119,7 +119,7 @@
<li class="bg-neutral-10 mb-4 p-1 border border-neutral-300 rounded"> <li class="bg-neutral-10 mb-4 p-1 border border-neutral-300 rounded">
<span class="block font-bold text-sm leading-loose text-center my-2">{{ contentData.freq.title }}</span> <span class="block font-bold text-sm leading-loose text-center my-2">{{ contentData.freq.title }}</span>
<!-- <Chart type="line" :data="freqData" :options="freqOptions" class="h-96" /> --> <!-- <Chart type="line" :data="freqData" :options="freqOptions" class="h-96" /> -->
<FreqChart/> <FreqChart v-if="performanceData" :chartData="performanceData?.freq?.cases" :content="contentData?.freq" yUnit="count"/>
</li> </li>
<li class="bg-neutral-10 p-1 border border-neutral-300 rounded"> <li class="bg-neutral-10 p-1 border border-neutral-300 rounded">
<span class="block font-bold text-sm leading-loose text-center my-2">{{ contentData.casesByTask.title }}</span> <span class="block font-bold text-sm leading-loose text-center my-2">{{ contentData.casesByTask.title }}</span>
@@ -152,8 +152,6 @@ import { simpleTimeLabel, followTimeLabel, dateLabel,
} from '@/module/timeLabel.js'; } from '@/module/timeLabel.js';
import FreqChart from './FreqChart.vue'; import FreqChart from './FreqChart.vue';
const myCloneDeep = (obj) => JSON.parse(JSON.stringify(obj));
const knownScaleLineChartOptions = { const knownScaleLineChartOptions = {
x: { x: {
type: 'time', type: 'time',
@@ -219,7 +217,7 @@ export default {
}, },
components: { components: {
StatusBar, StatusBar,
FreqChart FreqChart,
}, },
data() { data() {
return { return {
@@ -341,6 +339,11 @@ export default {
case 'count': // 次數 10 個點 case 'count': // 次數 10 個點
datasets = chartData.data; datasets = chartData.data;
xData = chartData.data.map(item => new Date(item.x).getTime()); xData = chartData.data.map(item => new Date(item.x).getTime());
// special case, freq chart case
if(whichCaller === "freqChartCaller") {
this.setFreqChartXData({ minX, maxX, xData, content});
}
break; break;
} }
@@ -354,12 +357,7 @@ export default {
content, ticksOfXAxis, content, ticksOfXAxis,
} }
}); });
// special case, freq chart case
if(whichCaller === "freqChartCaller") {
this.setFreqChartXData({ minX, maxX, xData, content});
}
primeVueSetData = { primeVueSetData = {
labels: xData, labels: xData,
datasets: [ datasets: [
@@ -794,10 +792,6 @@ export default {
} else { } else {
[this.avgWaitingTimeByEdgeData, this.avgWaitingTimeByEdgeOptions] = [null, null] [this.avgWaitingTimeByEdgeData, this.avgWaitingTimeByEdgeOptions] = [null, null]
} }
[this.freqData, this.freqOptions] = this.getLineChart(this.performanceData.freq.cases, this.contentData.freq, 'count', "freqChartCaller");
this.setFreqChartData(this.freqData);
this.setFreqChartOptions(this.freqOptions);
[this.casesByTaskData, this.casesByTaskOptions] = this.getHorizontalBarChart(this.performanceData.freq.cases_by_task, [this.casesByTaskData, this.casesByTaskOptions] = this.getHorizontalBarChart(this.performanceData.freq.cases_by_task,
this.contentData.casesByTask, true, 'count'); this.contentData.casesByTask, true, 'count');