d3 / d3-interpolate

Interpolate numbers, colors, strings, arrays, objects, whatever!
https://d3js.org/d3-interpolate
ISC License
494 stars 69 forks source link

d3.interpolate should special-case number-like objects? #24

Closed mbostock closed 8 years ago

mbostock commented 8 years ago

Related d3/d3#2878. The old behavior of d3.interpolate was:

  1. If b is a color, interpolateRgb is used.
  2. If b is a string, interpolateString is used.
  3. If b is an array, interpolateArray is used.
  4. If b is an object and not coercible to a number, interpolateObject is used.
  5. Otherwise, interpolateNumber is used.

Note the “and not coercible to a number” rule in step 4. The new algorithm does not treat objects that are coercible to numbers specially:

  1. If b is null, undefined or a boolean, use the constant b.
  2. If b is a number, use interpolateNumber.
  3. If b is a color or a string coercible to a color, use interpolateRgb.
  4. If b is a string, use interpolateString.
  5. If b is an array, use interpolateArray.
  6. Use interpolateObject.

A ramification of this is that d3.interpolate no longer supports interpolating dates: dates are treated as generic objects, and since they do not have any enumerable properties, the resulting interpolator returns the empty object.

I see two non-exclusive options:

  1. After step 5, check if b is a date using instanceof Date, and if so, use a new d3.interpolateDate instead of d3.interpolateObject.
  2. After step 5, check if b is coercible to a number using !isNaN(b), and if so, use d3.interpolateNumber instead of d3.interpolateObject.

Note that if we only do the second option, then the resulting interpolator will return numbers rather than Date instances. In practice, this is typically fine because all methods in D3 that accept dates should create a Date instance from a number if they are given a number. However, it might be cleaner to handle dates specially, since the Date is a first-class type in JavaScript.

mbostock commented 8 years ago

Related comment: d3.interpolateDate should probably reuse the returned date instance, for performance, like d3.interpolateObject and d3.interpolateArray do.