Files
lucia-frontend/src/module/setChartData.js
2023-10-25 11:13:37 +08:00

184 lines
5.3 KiB
JavaScript

import getMoment from 'moment';
/**
* 將後端的 chart data 加入最大、最小值,折線圖
* @param {array} baseData 後端給的 10 個時間點
* @param {number} xMax 2022-05-23T18:00:00
* @param {number} xMin 2022-05-23T08:00:00
* @param {number} isPercent 是否以百分比顯示
* @param {number} yMax case
* @param {number} yMin case
* @returns {array} 可直接套入 chart.js 的 data
*/
export function setLineChartData(baseData, xMax, xMin, isPercent, yMax, yMin) {
let data = baseData.map(i=>({x:i.x,y:i.y}))
// y 軸斜率計算請參考 ./public/timeFrameSlope 的圖
// x 值為 0 ~ 11,
// 將三的座標(ax, ay), (bx, by), (cx, cy)命名為 (a, b), (c, d), (e, f)
// 最小值: (f - b)(c - a) = (e - a)(d - b),求 b = (ed - ad - fa - fc) / (e - c - a)
// 最大值: (f - b)(e - c) = (f - d)(e - a),求 f = (be - bc -de + da) / (a - c)
// y 軸最小值
let a = 0;
let b;
let c = 1;
let d = baseData[0].y;
let e = 2;
let f = baseData[1].y;
b = (e*d - a*d - f*a - f*c) / (e - c - a)
if(isPercent) b = b >= 1 ? 1 : b <= 0 ? 0 : b;
else b = b >= yMax ? yMax : b <= yMin ? yMin : b;
// y 軸最大值
let ma = 9;
let mb = baseData[8].y;
let mc = 10;
let md = baseData[9].y;
let me = 11;
let mf;
mf = (mb*me - mb*mc -md*me + md*ma) / (ma - mc);
if(isPercent) mf = mf >= 1 ? 1 : mf <= 0 ? 0 : mf;
else mf = mf >= yMax ? yMax : mf <= yMin ? yMin : mf;
// 添加最小值
data.unshift({
x: xMin,
y: b,
})
// 添加最大值
data.push({
x: xMax,
y: mf,
})
return data;
};
/**
* 將後端的 chart data 加入最大、最小值,長條圖
* @param {array} baseData 後端給的 10 個時間點
* @param {number} xMax 2022-05-23T18:00:00
* @param {number} xMin 2022-05-23T08:00:00
* @returns {array} 可直接套入 chart.js 的 data
*/
export function setBarChartData(baseData) {
let data = baseData.map(i =>{
return {
x: getMoment(i.x).format('YYYY/M/D hh:mm:ss'),
y: i.y
}
})
return data
};
/**
* 將一段時間均分成多段的時間點
* @param {string} startTime 開始時間(ex: 434) 總秒數
* @param {string} endTime 結束時間(ex: 259065) 總秒數
* @param {number} amount 切分成多少段
* @returns {array} 均分成多段的時間 array
*/
export function timeRange(minTime, maxTime, amount) {
// x 軸(時間軸)的範圍是最大-最小,從最小值按照 index 累加間距到最大值
const startTime = minTime;
const endTime = maxTime;
let timeRange = []; // return數據初始化
const timeGap = (endTime - startTime) / (amount - 1); // 切分成多少段
for (let i = 0; i < amount; i++) {
timeRange.push(startTime + timeGap * i);
}
timeRange = timeRange.map(value => Math.round(value));
return timeRange;
};
/**
* 將 y 軸的值分割成跟 x 時間軸一樣的等份,使用統計學 R 語言算出貝茲曲線攻勢
* @param {array} data 切分成多少段
* @param {number} yAmount 切分成多少段
* @param {number} yMax y 最大值
* @returns {array} 均分成多段的時間 array
*/
export function yTimeRange(data, yAmount, yMax) {
const yRange = [];
const yGap = (1/ (yAmount-1));
// 貝茲曲線公式
const threebsr = function (t, a1, a2, a3, a4) {
return (
(1 - t) * (1 - t) * (1 - t) * a1 +
3 * t * (1 - t)* (1 - t) * a2 +
3 * t * t * (1 - t) * a3 +
t * t * t * a4
)
};
for (let j = 0; j < data.length - 1; j++) {
for (let i = 0; i <= 1; i += yGap*11) {
yRange.push(threebsr(i, data[j].y, data[j].y, data[j + 1].y, data[j + 1].y));
}
}
if(yRange.length < yAmount) {
let len = yAmount - yRange.length;
for (let i = 0; i < len; i++) {
yRange.push(yRange[yRange.length - 1]);
}
}
else if(yRange.length > yAmount) {
let len = yRange.length - yAmount;
for(let i = 0; i < len; i++) {
yRange.splice(1, 1);
}
}
return yRange;
};
/**
* 找出選擇的時間點的 index
* @param {array} data xVal
* @param {number} xValue x 值
* @returns {numver} x index
*/
export function getXIndex(data, xValue) {
let closestElement = data[0]; // 假定第一个元素是最接近的
let closestIndex = xValue; // 假定第一个元素的索引是 0
let smallestDifference = Math.abs(xValue - data[0]); // 初始差值设为第一个元素与目标数的差值
for (let i = 0; i < data.length; i++) {
let difference = Math.abs(xValue - data[i]);
if (difference <= smallestDifference) {
closestElement = data[i];
closestIndex = i;
smallestDifference = difference;
}
}
return closestIndex;
};
/**
*
* @param {number} seconds
* @returns {string}
*/
export function formatTime(seconds) {
if(!isNaN(seconds)) {
const remainingSeconds = seconds % 60;
const minutes = (Math.floor(seconds - remainingSeconds) / 60) % 60;
const hours = (Math.floor(seconds / 3600)) % 24;
const days = Math.floor(seconds / (3600 * 24));
let result = '';
if (days > 0) {
result += `${days}d`;
}
if (hours > 0) {
result += `${hours}h`;
}
if (minutes > 0) {
result += `${minutes}m`;
}
result += `${remainingSeconds}s`;
return result.trim(); // 去除最后一个空格
} else return null;
}