概要
前端js 计算小工具
整体架构流程
一个前端计算小小代码
技术细节
/**
* 将逻辑视图坐标转换为屏幕坐标
* @param {number} logicalValue - 逻辑视图 X 或 Y 坐标值
* @param {number} screenMax - UI窗口最大宽度或高度
* @param {number} logicalMax - 逻辑最大值
* @param {number} logicalMin - 逻辑最小值
* @param {boolean} [reverse=false] - 是否取反
* @returns {number} 屏幕坐标
*/
function logicalToScreen(logicalValue, screenMax, logicalMax, logicalMin, reverse = false) {
// 边界检查
logicalValue = Math.max(Math.min(logicalValue, logicalMax), logicalMin);
// 计算偏移量
const offset = logicalMin < 0 ? Math.abs(logicalMin) : logicalMin > 0 ? -logicalMin : 0;
const adjustedMax = logicalMax + offset;
const adjustedValue = logicalValue + offset;
// 取反处理
const finalValue = reverse ? adjustedMax - adjustedValue : adjustedValue;
// 计算并返回屏幕坐标
return (screenMax / adjustedMax) * finalValue;
}
/**
* 将屏幕坐标转换为逻辑视图坐标
* @param {number} screenValue - 屏幕坐标 X 或 Y
* @param {number} screenMax - UI窗口最大宽度或高度
* @param {number} logicalMax - 逻辑最大值
* @param {number} logicalMin - 逻辑最小值
* @param {boolean} [reverse=true] - 是否取反
* @returns {number} 逻辑视图坐标
*/
function screenToLogical(screenValue, screenMax, logicalMax, logicalMin, reverse = true) {
// 边界检查
screenValue = Math.max(Math.min(screenValue, screenMax), 0);
// 计算步长和逻辑坐标
const range = Math.abs(logicalMax - logicalMin);
const step = range / screenMax;
return reverse ? logicalMax - screenValue * step : logicalMin + screenValue * step;
}
/**
* 在数组中查找最接近目标值的元素
* @param {number[]} arr - 目标数组
* @param {number} target - 目标值
* @returns {Object} 包含最接近值和索引的对象
*/
function findClosestNumber(arr, target) {
let closestIndex = 0;
let minDiff = Number.MAX_VALUE;
for (let i = 0; i < arr.length; i++) {
const currentDiff = Math.abs(arr[i] - target);
if (currentDiff < minDiff || (currentDiff === minDiff && arr[i] > arr[closestIndex])) {
closestIndex = i;
minDiff = currentDiff;
}
}
return { number: arr[closestIndex], index: closestIndex };
}
/**
* 计算合适的Y轴范围
* @param {number} min - 最小值
* @param {number} max - 最大值
* @param {number} splitCount - 等分数量
* @returns {Object} 包含范围信息的对象
*/
function getCurrentExtent(min, max, splitCount) {
const minRow = Math.max(Math.floor(splitCount) - 2, 2);
const maxRow = Math.floor(splitCount) + 2;
const results = [];
for (let row = minRow; row < maxRow; row++) {
results.push(calculateStandard(min, max, row));
}
return getBestExtent(results);
}
/**
* 计算标准化范围
* @param {number} max - 最大值
* @param {number} min - 最小值
* @param {number} splitCount - 分割数量
* @returns {Object} 标准化后的范围信息
*/
function calculateStandard(max, min, splitCount) {
const originalMax = max;
const originalMin = min;
const step = (originalMax - originalMin) / splitCount;
// 计算数量级
const magnitude = Math.pow(10, Math.floor(Math.log10(step)));
const normalizedStep = Number((step / magnitude).toFixed(6));
// 标准化步长
let adjustedStep = normalizedStep <= 0.05 ? 0.05 :
normalizedStep <= 0.1 ? 0.1 :
normalizedStep <= 0.2 ? 0.2 :
normalizedStep <= 0.25 ? 0.25 :
normalizedStep <= 0.5 ? 0.5 : 1;
adjustedStep *= magnitude;
// 调整最小值
let adjustedMin = originalMin;
if (Math.floor(originalMin / adjustedStep) !== originalMin / adjustedStep) {
adjustedMin = originalMin < 0 ?
-Math.ceil(Math.abs(originalMin) / adjustedStep) * adjustedStep :
Math.floor(originalMin / adjustedStep) * adjustedStep;
}
// 调整最大值
let adjustedMax = originalMax;
if (Math.floor(originalMax / adjustedStep) !== originalMax / adjustedStep) {
adjustedMax = Math.floor(originalMax / adjustedStep + 1) * adjustedStep;
}
// 确保分割数量
let actualSplitCount = (adjustedMax - adjustedMin) / adjustedStep;
if (actualSplitCount < splitCount) {
const extra = splitCount - actualSplitCount;
actualSplitCount = splitCount;
adjustedMax += adjustedStep * Math.ceil(extra / 2);
adjustedMin -= adjustedStep * Math.floor(extra / 2);
}
return { SplitCount: Math.floor(actualSplitCount), Max: adjustedMax, Min: adjustedMin };
}
/**
* 从结果列表中选择最佳范围
* @param {Object[]} results - 范围结果列表
* @returns {Object} 最佳范围信息
*/
function getBestExtent(results) {
let best = results[0];
for (let i = 1; i < results.length; i++) {
if (results[i].Max - results[i].Min < best.Max - best.Min) {
best = results[i];
}
}
// 生成刻度列表
const step = (best.Max - best.Min) / best.SplitCount;
const ticks = [];
for (let i = 0; i <= best.SplitCount; i++) {
ticks.push(best.Min + step * i);
}
return { ...best, List: ticks };
}
/**
* 计算谱图Y轴分割数量
* @param {number} height - 图形高度
* @returns {number} 分割数量
*/
function getRowCount(height) {
let maxCount = 9;
while (height / maxCount <= 30 && maxCount > 1) {
maxCount--;
}
return Math.floor(maxCount);
}
export default {
logicalToScreen,
screenToLogical,
findClosestNumber,
getCurrentExtent,
getRowCount
};
小结
提供小小得计算内容
1562

被折叠的 条评论
为什么被折叠?



