Nice Numbering

by dirtyd77

HTML

Open console

Babel + JSX

const base = 10;
const mantissas = [5, 2.5, 2, 1];
const base_factor = 1;
const min_tick_interval = 4;
const max_tick_interval = 9;

// will use immutable range in implementation
let ticks = [];
for (let i = min_tick_interval; i <= max_tick_interval; i++){
	ticks.push(i);
}

function get_interval_step (data_high, data_low) {
	let range = data_high - data_low;
	let interval_step_candidates = ticks.map((tick) => get_ticks(range, tick));
  let {step} = interval_step_candidates.reduce((acc, candidate) => acc.minDiff < candidate.minDiff ? acc : candidate);
  console.log('ideal step:', step);
  return step;
}

function get_ticks (range, tick_interval) {
  let ideal_interval = get_ideal_interval(range, tick_interval);
  let interval_exponent = Math.floor(log(ideal_interval / base_factor, base));
	let ideal_magnitude = Math.pow(base, interval_exponent) * base_factor;
  let ideal_mantissa = ideal_interval / ideal_magnitude;
    
  let differences = mantissas.map((mantissa) => {
      return Math.abs(tick_interval - (range / (mantissa * ideal_magnitude)))
  });
  
  let minDiff = Math.min.apply(null, differences);
  let minDiffIndex = differences.indexOf(minDiff);
  let best_mantissa = mantissas[minDiffIndex];
  let step = best_mantissa * ideal_magnitude;
    
  return {
  	minDiff: minDiff,
  	step
  };
}

function log (x, base = Math.E) {
  return Math.log(x) / Math.log(base);
}

function get_ideal_interval (range, tick_num) {
  return range / tick_num;
}


const highPrice = 180000;
const lowPrice = -180000;
get_interval_step(highPrice, lowPrice);