微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

您如何安全地格式化/圆轴标签,以免标签出现两次

如何解决您如何安全地格式化/圆轴标签,以免标签出现两次

我正在编写一个有两个调整轴的自定义图表。 我想向轴显示四舍五入的数字,例如

输入 输出
[950,2050,3000,4500] ["1K","2K","3K","5K"]

问题在于数字可能非常接近:

输入 输出
[950,1100,1200,1300] ["1K","1K","1K"]

当然,这是天真的方法,而且很糟糕。

我想要类似的东西:

输入 输出
[950,1300] ["950","1.1K","1.2K","1.3K"]

有没有解决上述问题的库?

编辑:

这是我的解决方案(在应有的地方加热后作为问题的一部分添加):

我不知道它是否是最佳的,或者它是否会因某些测试用例而中断。你能找到更好的解决方案吗(比如更少的行,更快,更简洁?)

const numberFormat = n =>  n.toLocaleString(
  "en-US",{ minimumFractionDigits: 0 }
);
const SUFFIXES = ["","K","M","B","T"];

const getPrevSuffix = (suffix) => {
  return SUFFIXES[SUFFIXES.indexOf(suffix) - 1] || "";
};

const getSuffix = (value) => {
  const naive = numberFormat(excelRoundPositive(value,-digits(value)));
  const thousands = naive.match(/,.../g)?.length;
  const postfix = SUFFIXES[thousands || 0] ?? "T";
  return postfix;
};
const pows = {
  undefined: 1,null: 1,"": 1,K: 1000,k: 1000,M: 1000000,m: 1000000,B: 1000000000,b: 1000000000,T: 1000000000000,t: 1000000000000
};

export const excelRound = (value,power = 1) => {
  const pow = Math.pow(10,power);
  return Math.round(value * pow) / pow;
};

export const excelRoundPositive = (value,power) => {
  if (value === 0) return 0;
  if (value < 0) return -excelRoundPositive(-value,power);
  let pow = power;
  while (excelRound(value,pow) === 0) {
    pow += 1;
  }
  return excelRound(value,pow);
};

const digits = (value) => {
  if (value !== 0) return Math.floor(Math.log10(Math.abs(value)));
  return 0;
};

/**
 * Zero gets formatted as `0`
 * Negative numbers get formatted as positives,with a minus sign
 * Numbers get formatted with X decimals,where X = max(decimal of suffix)
 * is this dYnAmIc ProGrAMmInG
 */
export const formatInContext = (value,context) => {
  const suffix = getSuffix(value);
  const ctxNoZeros = context.filter((a) => a);
  const formatted = ctxNoZeros.map((v) =>
    formatInContextGreedy(v,ctxNoZeros)
  );
  const maxDecimals = Math.max(
    ...formatted.filter(([d,s]) => s === suffix).map(([d,s]) => d)
  );
  const rounded = excelRoundPositive(value / pows[suffix],maxDecimals);
  if (Math.abs(rounded) >= 1)
    return `${excelRoundPositive(value / pows[suffix],maxDecimals)}${suffix}`;
  return `${1000 * rounded}${getPrevSuffix(suffix)}`;
};

const formatInContextGreedy = (
  value,context = [],decimals = -Math.min(2,digits(value)) // This is,round up to hundreds,if value has enough digits
) => {
  const suffix = getSuffix(value);
  const currentRounding = excelRoundPositive(value / pows[suffix],decimals);
  const isAnyWithSameRounding = context
    .filter((x) => x !== value && getSuffix(x) === suffix)
    .some(
      (v) => excelRoundPositive(v / pows[suffix],decimals) === currentRounding
    );
  if (!isAnyWithSameRounding) return [decimals,suffix];
  return formatInContextGreedy(value,context,decimals + 1);
};


describe("Format Ticks Number That Should Not collide",() => {
  test.each`
    value               | context                               | result
    ${0}                | ${[0,101,1428,1904,2380,2856]}   | ${"0"}
    ${476}              | ${[476,952,2856]} | ${"500"}
    ${10}               | ${[10,2856]}  | ${"10"}
    ${1001}             | ${[0,1000,1001,1234,2000,2100]}  | ${"1.001K"}
    ${1234}             | ${[0,2100]}  | ${"1.234K"}
    ${1000}             | ${[0,2100]}  | ${"1K"}
    ${2000}             | ${[0,2100]}  | ${"2K"}
    ${2100}             | ${[0,2100]}  | ${"2.1K"}
    ${27.3}             | ${[27.3,29,30.3,31.1]}             | ${"27"}
    ${2100000000000000} | ${[2100000000000000]}                 | ${"2100T"}
    ${-1}               | ${[-1]}                               | ${"-1"}
    ${950}              | ${[950,1300]}            | ${"1K"}
    ${950}              | ${[950,1300]}            | ${"950"}
    ${959}              | ${[950,1040,1300]}            | ${"960"}
    ${951}              | ${[900,920,950,951,990]}          | ${"951"}
    ${841}              | ${[841,990]}                    | ${"800"}
    ${951}              | ${[841,990]}                    | ${"950"}
    ${990}              | ${[841,990]}                    | ${"990"}
    ${950}              | ${[950,1300]}            | ${"950"}
    ${274}              | ${[274,548,822,1105]}              | ${"300"}
    ${274}              | ${[0,274,1096,1370]}     | ${"300"}
    ${1152}             | ${[0,384,768,1152]}                | ${"1K"}
    ${1152}             | ${[384,1152]}                   | ${"1K"}
  `(
    "Convert $value when found in $context to $result",({ value,result }) => {
      expect(formatInContext(value,context)).toBe(result);
    }
  );
});

谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?