184 lines
5.3 KiB
JavaScript
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;
|
|
}
|