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; }