|
| 1 | +import {range as sequence, bisectRight} from 'd3-array'; |
| 2 | +import {scaleOrdinal as ordinal} from 'd3-scale'; |
| 3 | + |
| 4 | +export default function band() { |
| 5 | + var scale = ordinal().unknown(undefined), |
| 6 | + domain = scale.domain, |
| 7 | + ordinalRange = scale.range, |
| 8 | + range = [0, 1], |
| 9 | + step, |
| 10 | + bandwidth, |
| 11 | + round = false, |
| 12 | + paddingInner = 0, |
| 13 | + paddingOuter = 0, |
| 14 | + align = 0.5; |
| 15 | + |
| 16 | + delete scale.unknown; |
| 17 | + |
| 18 | + function rescale() { |
| 19 | + var n = domain().length, |
| 20 | + reverse = range[1] < range[0], |
| 21 | + start = range[reverse - 0], |
| 22 | + stop = range[1 - reverse]; |
| 23 | + step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2); |
| 24 | + if (round) step = Math.floor(step); |
| 25 | + start += (stop - start - step * (n - paddingInner)) * align; |
| 26 | + bandwidth = step * (1 - paddingInner); |
| 27 | + if (round) start = Math.round(start), bandwidth = Math.round(bandwidth); |
| 28 | + var values = sequence(n).map(function(i) { return start + step * i; }); |
| 29 | + return ordinalRange(reverse ? values.reverse() : values); |
| 30 | + } |
| 31 | + |
| 32 | + scale.domain = function(_) { |
| 33 | + return arguments.length ? (domain(_), rescale()) : domain(); |
| 34 | + }; |
| 35 | + |
| 36 | + scale.range = function(_) { |
| 37 | + return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice(); |
| 38 | + }; |
| 39 | + |
| 40 | + scale.rangeRound = function(_) { |
| 41 | + return range = [+_[0], +_[1]], round = true, rescale(); |
| 42 | + }; |
| 43 | + |
| 44 | + scale.bandwidth = function() { |
| 45 | + return bandwidth; |
| 46 | + }; |
| 47 | + |
| 48 | + scale.step = function() { |
| 49 | + return step; |
| 50 | + }; |
| 51 | + |
| 52 | + scale.round = function(_) { |
| 53 | + return arguments.length ? (round = !!_, rescale()) : round; |
| 54 | + }; |
| 55 | + |
| 56 | + scale.padding = function(_) { |
| 57 | + return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner; |
| 58 | + }; |
| 59 | + |
| 60 | + scale.paddingInner = function(_) { |
| 61 | + return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner; |
| 62 | + }; |
| 63 | + |
| 64 | + scale.paddingOuter = function(_) { |
| 65 | + return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter; |
| 66 | + }; |
| 67 | + |
| 68 | + scale.align = function(_) { |
| 69 | + return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align; |
| 70 | + }; |
| 71 | + |
| 72 | + scale.invertExtent = function(r0, r1) { |
| 73 | + var lo = +r0, |
| 74 | + hi = arguments.length > 1 ? +r1 : lo, |
| 75 | + reverse = range[1] < range[0], |
| 76 | + values = reverse ? ordinalRange().reverse() : ordinalRange(), |
| 77 | + n = values.length - 1, a, b, t; |
| 78 | + |
| 79 | + // order range inputs, bail if outside of scale range |
| 80 | + if (hi < lo) t = lo, lo = hi, hi = t; |
| 81 | + if (hi < values[0] || lo > range[1-reverse]) return undefined; |
| 82 | + |
| 83 | + // binary search to index into scale range |
| 84 | + a = Math.max(0, bisectRight(values, lo) - 1); |
| 85 | + b = lo===hi ? a : bisectRight(values, hi) - 1; |
| 86 | + |
| 87 | + // increment index a if lo is within padding gap |
| 88 | + if (lo - values[a] > bandwidth + 1e-10) ++a; |
| 89 | + |
| 90 | + if (reverse) t = a, a = n - b, b = n - t; // map + swap |
| 91 | + return (a > b) ? undefined : domain().slice(a, b+1); |
| 92 | + }; |
| 93 | + |
| 94 | + scale.copy = function() { |
| 95 | + return band() |
| 96 | + .domain(domain()) |
| 97 | + .range(range) |
| 98 | + .round(round) |
| 99 | + .paddingInner(paddingInner) |
| 100 | + .paddingOuter(paddingOuter) |
| 101 | + .align(align); |
| 102 | + }; |
| 103 | + |
| 104 | + return rescale(); |
| 105 | +} |
| 106 | + |
| 107 | +function pointish(scale) { |
| 108 | + var copy = scale.copy; |
| 109 | + |
| 110 | + scale.padding = scale.paddingOuter; |
| 111 | + delete scale.paddingInner; |
| 112 | + delete scale.paddingOuter; |
| 113 | + |
| 114 | + scale.copy = function() { |
| 115 | + return pointish(copy()); |
| 116 | + }; |
| 117 | + |
| 118 | + return scale; |
| 119 | +} |
| 120 | + |
| 121 | +export function point() { |
| 122 | + return pointish(band().paddingInner(1)); |
| 123 | +} |
0 commit comments