diff --git a/src/utils/Scale.js b/src/utils/Scale.js index 15773fb6..039b908b 100644 --- a/src/utils/Scale.js +++ b/src/utils/Scale.js @@ -117,28 +117,12 @@ export function scaleEqual(scaleA, scaleB) { _.isEqual(scaleA.range(), scaleB.range()); } -export function indexOfClosestLeftNumberInList(number, sortedList) { - if (sortedList.length <= 1) { - return 0; - } - - const isDescending = sortedList[0] > sortedList[1]; - // _.sortedIndex works on ascending lists only - // so reverse if working with descending list - const listCopy = isDescending ? sortedList.slice().reverse() : sortedList; - - // Get lower bound of where number falls - let indexForNumber = _.sortedIndex(listCopy, number); - if (isDescending && indexForNumber < sortedList.length) { - indexForNumber += 1; - } else if (!isDescending && indexForNumber > 0) { - indexForNumber -= 1; - } - - return isDescending - ? // If descending, remap indexForNumber to work with descending list - Math.abs(indexForNumber - sortedList.length) - : indexForNumber; +export function indexOfClosestNumberInList(number, list) { + return list.reduce((closestI, current, i) => { + return Math.abs(current - number) < Math.abs(list[closestI] - number) + ? i + : closestI; + }, 0); } export function invertPointScale(scale, rangeValue) { @@ -147,10 +131,21 @@ export function invertPointScale(scale, rangeValue) { // shim until d3.scalePoint.invert() is implemented for real // given a value from the output range, returns the *nearest* corresponding value in the input domain const rangePoints = domain.map(domainValue => scale(domainValue)); - const nearestLeftPointIndex = indexOfClosestLeftNumberInList( - rangeValue, - rangePoints - ); - return domain[nearestLeftPointIndex]; + if (rangePoints.length <= 1) { + return domain[0]; + } + + const isDescending = rangePoints[0] > rangePoints[1]; + + // _.sortedIndex works on ascending lists only + // so reverse if working with descending list + if (isDescending) { + domain.reverse(); + rangePoints.reverse(); + } + + const nearestPointIndex = indexOfClosestNumberInList(rangeValue, rangePoints); + + return domain[nearestPointIndex]; } diff --git a/tests/jsdom/spec/utils.Axis.spec.js b/tests/jsdom/spec/utils.Axis.spec.js index 8b0c54b8..d5ae4839 100644 --- a/tests/jsdom/spec/utils.Axis.spec.js +++ b/tests/jsdom/spec/utils.Axis.spec.js @@ -183,7 +183,7 @@ describe("Axis utils", () => { outerX: 50, outerY: 0, xScale: scale, - xValue: "a" + xValue: "b" }); }); @@ -213,7 +213,7 @@ describe("Axis utils", () => { outerX: 0, outerY: 50, yScale: scale, - yValue: "a" + yValue: "b" }); }); }); diff --git a/tests/jsdom/spec/utils.Scale.spec.js b/tests/jsdom/spec/utils.Scale.spec.js index e8dc3fdf..46803d57 100644 --- a/tests/jsdom/spec/utils.Scale.spec.js +++ b/tests/jsdom/spec/utils.Scale.spec.js @@ -10,7 +10,7 @@ import { initScale, isValidScale, invertPointScale, - indexOfClosestLeftNumberInList + indexOfClosestNumberInList } from "../../../src/utils/Scale"; describe("Scale utils", () => { @@ -83,10 +83,10 @@ describe("Scale utils", () => { }); }); - describe("indexOfClosestLeftNumberInList", () => { - it("returns index of left closest to the number in the array", () => { - expect(indexOfClosestLeftNumberInList(1.5, [5, 4, 3, 2, 1])).to.equal(3); - expect(indexOfClosestLeftNumberInList(1.5, [1, 2, 3, 4, 5])).to.equal(0); + describe("indexOfClosestNumberInList", () => { + it("returns index of closest to the number in the array", () => { + expect(indexOfClosestNumberInList(1.5, [5, 4, 3, 2, 1])).to.equal(3); + expect(indexOfClosestNumberInList(1.5, [1, 2, 3, 4, 5])).to.equal(0); }); });