299 lines
7.7 KiB
Vue
299 lines
7.7 KiB
Vue
<template>
|
|
<Chart
|
|
type="line"
|
|
:data="primeVueSetDataState"
|
|
:options="primeVueSetOptionsState"
|
|
class="h-96"
|
|
/>
|
|
</template>
|
|
|
|
<script setup>
|
|
// The Lucia project.
|
|
// Copyright 2024-2026 DSP, inc. All rights reserved.
|
|
// Authors:
|
|
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
|
|
// imacat.yang@dsp.im (imacat), 2023/9/23
|
|
/**
|
|
* @module views/Discover/Performance/FreqChart
|
|
* Frequency chart component displaying activity
|
|
* occurrence data with Chart.js bar charts.
|
|
*/
|
|
|
|
import { ref, onMounted } from "vue";
|
|
import {
|
|
setTimeStringFormatBaseOnTimeDifference,
|
|
mapTimestampToAxisTicksByFormat,
|
|
} from "@/module/timeLabel.js";
|
|
|
|
const knownScaleLineChartOptions = {
|
|
x: {
|
|
type: "time",
|
|
title: {
|
|
display: true,
|
|
color: "#334155",
|
|
font: {
|
|
size: 12,
|
|
lineHeight: 2,
|
|
},
|
|
},
|
|
time: {
|
|
displayFormats: {
|
|
second: "h:mm:ss", // ex: 1:11:11
|
|
minute: "M/d h:mm", // ex: 1/1 1:11
|
|
hour: "M/d h:mm", // ex: 1/1 1:11
|
|
day: "M/d h", // ex: 1/1 1
|
|
month: "y/M/d", // ex: 1911/1/1
|
|
},
|
|
},
|
|
ticks: {
|
|
display: true,
|
|
maxRotation: 0, // Do not rotate labels (range: 0~50)
|
|
color: "#64748b",
|
|
source: "labels", // Dynamically display label count proportionally
|
|
},
|
|
border: {
|
|
color: "#64748b",
|
|
},
|
|
grid: {
|
|
tickLength: 0, // Prevent grid lines from extending beyond the axis
|
|
},
|
|
},
|
|
y: {
|
|
beginAtZero: true, // Scale includes 0
|
|
title: {
|
|
display: true,
|
|
color: "#334155",
|
|
font: {
|
|
size: 12,
|
|
lineHeight: 2,
|
|
},
|
|
},
|
|
ticks: {
|
|
color: "#64748b",
|
|
padding: 8,
|
|
},
|
|
grid: {
|
|
color: "#64748b",
|
|
},
|
|
border: {
|
|
display: false, // Hide the extra border line on the left side
|
|
},
|
|
},
|
|
};
|
|
|
|
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 } },
|
|
) => {
|
|
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) {
|
|
// Customize x-axis time ticks based on different intervals
|
|
return ticksOfXAxis[index];
|
|
},
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
/** Compare page and Performance have this same function.
|
|
* Customizes a base tooltip object using the content data.
|
|
* The object order is known to be: x, then title, then 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,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Builds the PrimeVue line chart data and options configuration.
|
|
* @param {object} chartData - The chart data from the API.
|
|
* @param {object} content - The axis label content.
|
|
* @param {string} pageName - 'Compare' or page identifier.
|
|
*/
|
|
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 = {};
|
|
|
|
// Consider the dimension of chartData.data
|
|
// When handling the Compare page case
|
|
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, // Bezier curve tension
|
|
borderColor: colorPrimary,
|
|
pointBackgroundColor: colorPrimary,
|
|
},
|
|
{
|
|
label: chartData.data[1].label,
|
|
data: datasetsSecondary,
|
|
fill: false,
|
|
tension: 0, // Bezier curve tension
|
|
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, // Bezier curve tension
|
|
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, // Legend
|
|
tooltip: {
|
|
displayColors: true,
|
|
titleFont: { weight: "normal" },
|
|
callbacks: {
|
|
label: function (tooltipItem) {
|
|
// Get the data
|
|
const label = tooltipItem.dataset.label || "";
|
|
|
|
// Build the tooltip label with dataset color indicator
|
|
return `${label}: ${tooltipItem.parsed.y}`; // Use Unicode block to represent color
|
|
},
|
|
},
|
|
},
|
|
title: {
|
|
display: false,
|
|
},
|
|
},
|
|
scales: customizedScaleOption,
|
|
};
|
|
|
|
primeVueSetOption.scales.y.ticks.precision = 0; // Show 0 decimal places on y-axis
|
|
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
|
return value; // Y-axis ticks here have no time unit suffix
|
|
};
|
|
primeVueSetDataState.value = primeVueSetData;
|
|
primeVueSetOptionsState.value = primeVueSetOption;
|
|
};
|
|
|
|
onMounted(() => {
|
|
getLineChartPrimeVueSetting(props.chartData, props.content, props.pageName);
|
|
});
|
|
</script>
|