前端js 计算小工具

概要

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

小结

提供小小得计算内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值