Migrate all Vue components from Options API to <script setup>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<Chart type="line" :data="primeVueSetDataState" :options="primeVueSetOptionsState" class="h-96" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import {
|
||||
setTimeStringFormatBaseOnTimeDifference,
|
||||
@@ -65,220 +65,208 @@ y: {
|
||||
},
|
||||
};
|
||||
|
||||
// 試著把 chart 獨立成一個 vue component
|
||||
// 企圖防止 PrimeVue 誤用其他圖表 option 值的 bug
|
||||
export default {
|
||||
props: {
|
||||
chartData: {
|
||||
type: Object,
|
||||
const props = defineProps({
|
||||
chartData: {
|
||||
type: Object,
|
||||
},
|
||||
content: {
|
||||
type: Object,
|
||||
},
|
||||
yUnit: {
|
||||
type: String,
|
||||
},
|
||||
pageName: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
|
||||
const primeVueSetDataState = ref(null);
|
||||
const primeVueSetOptionsState = ref(null);
|
||||
const colorPrimary = ref('#0099FF');
|
||||
const colorSecondary = ref('#FFAA44');
|
||||
|
||||
/**
|
||||
* Compare page and Performance have this same function.
|
||||
* @param whichScaleObj PrimeVue scale option object to reference to
|
||||
* @param customizeOptions
|
||||
* @param customizeOptions.content
|
||||
* @param customizeOptions.ticksOfXAxis
|
||||
*/
|
||||
const getCustomizedScaleOption = (whichScaleObj, {customizeOptions: {
|
||||
content,
|
||||
ticksOfXAxis,
|
||||
},
|
||||
content: {
|
||||
type: Object,
|
||||
},
|
||||
yUnit: {
|
||||
type: String,
|
||||
},
|
||||
pageName: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
|
||||
const primeVueSetDataState = ref(null);
|
||||
const primeVueSetOptionsState = ref(null);
|
||||
const colorPrimary = ref('#0099FF');
|
||||
const colorSecondary = ref('#FFAA44');
|
||||
|
||||
/**
|
||||
* Compare page and Performance have this same function.
|
||||
* @param whichScaleObj PrimeVue scale option object to reference to
|
||||
* @param customizeOptions
|
||||
* @param customizeOptions.content
|
||||
* @param customizeOptions.ticksOfXAxis
|
||||
*/
|
||||
const getCustomizedScaleOption = (whichScaleObj, {customizeOptions: {
|
||||
content,
|
||||
ticksOfXAxis,
|
||||
},
|
||||
}) => {
|
||||
let resultScaleObj;
|
||||
resultScaleObj = customizeScaleChartOptionTitleByContent(whichScaleObj, content);
|
||||
resultScaleObj = customizeScaleChartOptionTicks(resultScaleObj, ticksOfXAxis);
|
||||
return resultScaleObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare page and Performance have this same function.
|
||||
* @param {object} scaleObjectToAlter this object follows the format of prive vue chart
|
||||
* @param {Array<string>} ticksOfXAxis For example, ['05/06', '05,07', '05/08']
|
||||
* or ['08:03:01', '08:11:18', '09:03:41', ], and so on.
|
||||
*/
|
||||
const customizeScaleChartOptionTicks = (scaleObjectToAlter, ticksOfXAxis) => {
|
||||
return {
|
||||
...scaleObjectToAlter,
|
||||
x: {
|
||||
...scaleObjectToAlter.x,
|
||||
ticks: {
|
||||
...scaleObjectToAlter.x.ticks,
|
||||
callback: function(value, index) {
|
||||
// 根據不同的級距客製化 x 軸的時間刻度
|
||||
return ticksOfXAxis[index];
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/** Compare page and Performance have this same function.
|
||||
* 在一個基本的物件上加以客製化這個物件,客製化的參照來源是 content 的內容
|
||||
* 之所以有辦法這樣撰寫,是因為我們知道物件的順序是先 x 再 title 再 text
|
||||
* This function alters the title property of known scales object of Chart option
|
||||
* This is based on the fact that we know the order must be x -> title -> text.
|
||||
* @param {object} whichScaleObj PrimeVue scale option object to reference to
|
||||
* @param content whose property includes x and y and stand for titles
|
||||
*
|
||||
* @returns { object } an object modified with two titles
|
||||
*/
|
||||
const customizeScaleChartOptionTitleByContent = (whichScaleObj, content) => {
|
||||
if (!content) {
|
||||
// Early return
|
||||
return whichScaleObj;
|
||||
}
|
||||
|
||||
return {
|
||||
...whichScaleObj,
|
||||
x: {
|
||||
...whichScaleObj.x,
|
||||
title: {
|
||||
...whichScaleObj.x.title,
|
||||
text: content.x
|
||||
}
|
||||
},
|
||||
y: {
|
||||
...whichScaleObj.y,
|
||||
title: {
|
||||
...whichScaleObj.y.title,
|
||||
text: content.y
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const getLineChartPrimeVueSetting = (chartData, content, pageName) => {
|
||||
let datasetsArr;
|
||||
let datasets;
|
||||
let datasetsPrimary; // For Compare page case
|
||||
let datasetsSecondary; // For Compare page case
|
||||
const minX = chartData?.x_axis?.min;
|
||||
const maxX = chartData?.x_axis?.max;
|
||||
let xData;
|
||||
let primeVueSetData = {};
|
||||
let primeVueSetOption = {};
|
||||
|
||||
// 考慮 chartData.data 的dimension
|
||||
// 當我們遇到了 Compare 頁面的案例
|
||||
if(pageName === "Compare"){
|
||||
datasetsPrimary = chartData.data[0].data;
|
||||
datasetsSecondary = chartData.data[1].data;
|
||||
|
||||
datasetsArr = [
|
||||
{
|
||||
label: chartData.data[0].label,
|
||||
data: datasetsPrimary,
|
||||
fill: false,
|
||||
tension: 0, // 貝茲曲線張力
|
||||
borderColor: colorPrimary,
|
||||
pointBackgroundColor: colorPrimary,
|
||||
},
|
||||
{
|
||||
label: chartData.data[1].label,
|
||||
data: datasetsSecondary,
|
||||
fill: false,
|
||||
tension: 0, // 貝茲曲線張力
|
||||
borderColor: colorSecondary,
|
||||
pointBackgroundColor: colorSecondary,
|
||||
}
|
||||
];
|
||||
xData = chartData.data[0].data.map(item => new Date(item.x).getTime());
|
||||
} else {
|
||||
datasets = chartData.data;
|
||||
datasetsArr = [
|
||||
{
|
||||
label: content.title,
|
||||
data: datasets,
|
||||
fill: false,
|
||||
tension: 0, // 貝茲曲線張力
|
||||
borderColor: '#0099FF',
|
||||
}
|
||||
];
|
||||
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: datasetsArr,
|
||||
};
|
||||
primeVueSetOption = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 16,
|
||||
left: 8,
|
||||
right: 8,
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: false, // 圖例
|
||||
tooltip: {
|
||||
displayColors: true,
|
||||
titleFont: {weight: 'normal'},
|
||||
callbacks: {
|
||||
label: function(tooltipItem) {
|
||||
// 取得數據
|
||||
const label = tooltipItem.dataset.label || '';
|
||||
|
||||
// 建立一個小方塊顯示顏色
|
||||
return `${label}: ${tooltipItem.parsed.y}`; // 使用 Unicode 方塊表示顏色
|
||||
},
|
||||
},
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: customizedScaleOption,
|
||||
};
|
||||
|
||||
primeVueSetOption.scales.y.ticks.precision = 0; // y 軸顯示小數點後 0 位
|
||||
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
||||
return value; //這裡的Y軸刻度沒有後綴代表時間的英文字母
|
||||
};
|
||||
primeVueSetDataState.value = primeVueSetData;
|
||||
primeVueSetOptionsState.value = primeVueSetOption;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getLineChartPrimeVueSetting(props.chartData, props.content, props.pageName);
|
||||
});
|
||||
|
||||
return {
|
||||
...props,
|
||||
primeVueSetDataState,
|
||||
primeVueSetOptionsState,
|
||||
};
|
||||
}
|
||||
}) => {
|
||||
let resultScaleObj;
|
||||
resultScaleObj = customizeScaleChartOptionTitleByContent(whichScaleObj, content);
|
||||
resultScaleObj = customizeScaleChartOptionTicks(resultScaleObj, ticksOfXAxis);
|
||||
return resultScaleObj;
|
||||
};
|
||||
</script>
|
||||
|
||||
/**
|
||||
* Compare page and Performance have this same function.
|
||||
* @param {object} scaleObjectToAlter this object follows the format of prive vue chart
|
||||
* @param {Array<string>} ticksOfXAxis For example, ['05/06', '05,07', '05/08']
|
||||
* or ['08:03:01', '08:11:18', '09:03:41', ], and so on.
|
||||
*/
|
||||
const customizeScaleChartOptionTicks = (scaleObjectToAlter, ticksOfXAxis) => {
|
||||
return {
|
||||
...scaleObjectToAlter,
|
||||
x: {
|
||||
...scaleObjectToAlter.x,
|
||||
ticks: {
|
||||
...scaleObjectToAlter.x.ticks,
|
||||
callback: function(value, index) {
|
||||
// 根據不同的級距客製化 x 軸的時間刻度
|
||||
return ticksOfXAxis[index];
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/** Compare page and Performance have this same function.
|
||||
* 在一個基本的物件上加以客製化這個物件,客製化的參照來源是 content 的內容
|
||||
* 之所以有辦法這樣撰寫,是因為我們知道物件的順序是先 x 再 title 再 text
|
||||
* This function alters the title property of known scales object of Chart option
|
||||
* This is based on the fact that we know the order must be x -> title -> text.
|
||||
* @param {object} whichScaleObj PrimeVue scale option object to reference to
|
||||
* @param content whose property includes x and y and stand for titles
|
||||
*
|
||||
* @returns { object } an object modified with two titles
|
||||
*/
|
||||
const customizeScaleChartOptionTitleByContent = (whichScaleObj, content) => {
|
||||
if (!content) {
|
||||
// Early return
|
||||
return whichScaleObj;
|
||||
}
|
||||
|
||||
return {
|
||||
...whichScaleObj,
|
||||
x: {
|
||||
...whichScaleObj.x,
|
||||
title: {
|
||||
...whichScaleObj.x.title,
|
||||
text: content.x
|
||||
}
|
||||
},
|
||||
y: {
|
||||
...whichScaleObj.y,
|
||||
title: {
|
||||
...whichScaleObj.y.title,
|
||||
text: content.y
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const getLineChartPrimeVueSetting = (chartData, content, pageName) => {
|
||||
let datasetsArr;
|
||||
let datasets;
|
||||
let datasetsPrimary; // For Compare page case
|
||||
let datasetsSecondary; // For Compare page case
|
||||
const minX = chartData?.x_axis?.min;
|
||||
const maxX = chartData?.x_axis?.max;
|
||||
let xData;
|
||||
let primeVueSetData = {};
|
||||
let primeVueSetOption = {};
|
||||
|
||||
// 考慮 chartData.data 的dimension
|
||||
// 當我們遇到了 Compare 頁面的案例
|
||||
if(pageName === "Compare"){
|
||||
datasetsPrimary = chartData.data[0].data;
|
||||
datasetsSecondary = chartData.data[1].data;
|
||||
|
||||
datasetsArr = [
|
||||
{
|
||||
label: chartData.data[0].label,
|
||||
data: datasetsPrimary,
|
||||
fill: false,
|
||||
tension: 0, // 貝茲曲線張力
|
||||
borderColor: colorPrimary,
|
||||
pointBackgroundColor: colorPrimary,
|
||||
},
|
||||
{
|
||||
label: chartData.data[1].label,
|
||||
data: datasetsSecondary,
|
||||
fill: false,
|
||||
tension: 0, // 貝茲曲線張力
|
||||
borderColor: colorSecondary,
|
||||
pointBackgroundColor: colorSecondary,
|
||||
}
|
||||
];
|
||||
xData = chartData.data[0].data.map(item => new Date(item.x).getTime());
|
||||
} else {
|
||||
datasets = chartData.data;
|
||||
datasetsArr = [
|
||||
{
|
||||
label: content.title,
|
||||
data: datasets,
|
||||
fill: false,
|
||||
tension: 0, // 貝茲曲線張力
|
||||
borderColor: '#0099FF',
|
||||
}
|
||||
];
|
||||
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: datasetsArr,
|
||||
};
|
||||
primeVueSetOption = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 16,
|
||||
left: 8,
|
||||
right: 8,
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: false, // 圖例
|
||||
tooltip: {
|
||||
displayColors: true,
|
||||
titleFont: {weight: 'normal'},
|
||||
callbacks: {
|
||||
label: function(tooltipItem) {
|
||||
// 取得數據
|
||||
const label = tooltipItem.dataset.label || '';
|
||||
|
||||
// 建立一個小方塊顯示顏色
|
||||
return `${label}: ${tooltipItem.parsed.y}`; // 使用 Unicode 方塊表示顏色
|
||||
},
|
||||
},
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: customizedScaleOption,
|
||||
};
|
||||
|
||||
primeVueSetOption.scales.y.ticks.precision = 0; // y 軸顯示小數點後 0 位
|
||||
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
||||
return value; //這裡的Y軸刻度沒有後綴代表時間的英文字母
|
||||
};
|
||||
primeVueSetDataState.value = primeVueSetData;
|
||||
primeVueSetOptionsState.value = primeVueSetOption;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getLineChartPrimeVueSetting(props.chartData, props.content, props.pageName);
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user