Giter Site home page Giter Site logo

Comments (2)

vallsv avatar vallsv commented on June 5, 2024

I did some work around.

Here is an implementation outside of the lib.

It is probably very specific use case, but if you would like to provide on your side a shiftUnit and something like getUnitPlace, it would be very useful to reduce the size of such code.

If you like that idea, i can create a pull request.

const PREFIX = {
  '<tera>': 12,
  '<giga>': 9,
  '<mega>': 6,
  '<kilo>': 3,
  '<1>': 0,
  '<milli>': -3,
  '<micro>': -6,
  '<nano>': -9
};

const PLACES_TO_PREFIX = {};

for (const [key, value] of Object.entries(PREFIX)) {
  PLACES_TO_PREFIX[value] = key;
}

/**
 * Returns a quantity with a unit inside a readable range of values
 *
 * The prefix of the unit (n/u/k/M) is picked to make the value
 * in the range 0.1 .. 999
 */
export function toHumanReadableUnit(quantity) {
  if (quantity.scalar === 0) {
    return quantity;
  }

  function getNextDeltaPlace(q) {
    const v = q.scalar;
    if (v > 200) {
      return 3;
    }
    if (v < 0.3) {
      return -3;
    }
    return 0;
  }

  function getUnitWithNewPrefix(q, prefix) {
    function cleanup(elemString) {
      if (elemString === undefined) return '';
      if (elemString === '<1>') return '';
      return elemString.substring(1, elemString.length - 1);
    }
    let n = '';
    for (let ni = 0; ni < q.numerator.length; ni += 1) {
      const elem = q.numerator[ni];
      if (ni === 0) {
        const notPrefix = PREFIX[elem] === undefined;
        n += cleanup(prefix) + (notPrefix ? cleanup(elem) : '');
      } else {
        n += cleanup(elem);
      }
    }
    let d = '';
    for (let di = 0; di < q.denominator.length; di += 1) {
      const elem = q.denominator[di];
      d += cleanup(elem);
    }
    if (d === '') {
      return n;
    }
    if (n === '') {
      return `1/${d}`;
    }
    return `${n}/${d}`;
  }

  function getCurrentPlace(q) {
    return PREFIX[q.numerator[0]] || 0;
  }

  function shiftUnit(q, deltaPlace) {
    const place = getCurrentPlace(q) + deltaPlace;
    const prefixNumerator = PLACES_TO_PREFIX[place];
    if (prefixNumerator === undefined) {
      return q;
    }
    const unit = getUnitWithNewPrefix(quantity, prefixNumerator);
    return q.to(unit);
  }

  let current = quantity;
  for (let i = 0; i < 10; i += 1) {
    const deltaPlace = getNextDeltaPlace(current);
    if (deltaPlace === 0) {
      break;
    }
    current = shiftUnit(current, deltaPlace);
  }

  // Check if we loose a bit of digits
  const fixed = current.scalar.toFixed(2);
  if (
    fixed.length === 4 &&
    fixed.substring(0, 2) === '0.' &&
    fixed.substring(3, 4) !== '0'
  ) {
    return shiftUnit(current, -3);
  }
  return current;
}
import Qty from 'js-quantities';
import { toHumanReadableUnit } from 'helpers/QtyHelper';

describe('Qty helper', () => {
  test('check already normalized', async () => {
    const q = Qty('10 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('10 mm');
  });
  test('check with smaller unit than expected', async () => {
    const q = Qty('1000 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('1 m');
  });
  test('check with bigger unit than expected', async () => {
    const q = Qty('0.02 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('20 um');
  });
  test('check with smaller unit than expected', async () => {
    const q = Qty('0.0222 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('22.2 um');
  });
  test('check with more than 2 precision digit', async () => {
    const q = Qty('0.222 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('222 um');
  });
  test('check with a value bigger than 200', async () => {
    const q = Qty('0.500 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('0.5 mm');
  });
  test('check above rounding error', async () => {
    const q = Qty('0.995 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('995 um');
  });
  test('check under rounding error', async () => {
    const q = Qty('0.996 mm');
    const result = toHumanReadableUnit(q);
    expect(result.toPrec(0.1).toString()).toEqual('1 mm');
  });
});

from js-quantities.

adrfantini avatar adrfantini commented on June 5, 2024

Duplicate of #87 ?

from js-quantities.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.