1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
/**
* The Color Mixin is an abstract chart functional class providing universal coloring support
* as a mix-in for any concrete chart implementation.
* @name colorMixin
* @memberof dc
* @mixin
* @param {Object} _chart
* @returns {dc.colorMixin}
*/
dc.colorMixin = function (_chart) {
var _colors = d3.scaleOrdinal(dc.config.defaultColors());
var _defaultAccessor = true;
var _colorAccessor = function (d) { return _chart.keyAccessor()(d); };
var _colorCalculator;
/**
* Retrieve current color scale or set a new color scale. This methods accepts any function that
* operates like a d3 scale.
* @method colors
* @memberof dc.colorMixin
* @instance
* @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale}
* @example
* // alternate categorical scale
* chart.colors(d3.scale.category20b());
* // ordinal scale
* chart.colors(d3.scaleOrdinal().range(['red','green','blue']));
* // convenience method, the same as above
* chart.ordinalColors(['red','green','blue']);
* // set a linear scale
* chart.linearColors(["#4575b4", "#ffffbf", "#a50026"]);
* @param {d3.scale} [colorScale=d3.scaleOrdinal(d3.schemeCategory20c)]
* @returns {d3.scale|dc.colorMixin}
*/
_chart.colors = function (colorScale) {
if (!arguments.length) {
return _colors;
}
if (colorScale instanceof Array) {
_colors = d3.scaleQuantize().range(colorScale); // deprecated legacy support, note: this fails for ordinal domains
} else {
_colors = typeof colorScale === 'function' ? colorScale : dc.utils.constant(colorScale);
}
return _chart;
};
/**
* Convenience method to set the color scale to
* {@link https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales d3.scaleOrdinal} with
* range `r`.
* @method ordinalColors
* @memberof dc.colorMixin
* @instance
* @param {Array<String>} r
* @returns {dc.colorMixin}
*/
_chart.ordinalColors = function (r) {
return _chart.colors(d3.scaleOrdinal().range(r));
};
/**
* Convenience method to set the color scale to an Hcl interpolated linear scale with range `r`.
* @method linearColors
* @memberof dc.colorMixin
* @instance
* @param {Array<Number>} r
* @returns {dc.colorMixin}
*/
_chart.linearColors = function (r) {
return _chart.colors(d3.scaleLinear()
.range(r)
.interpolate(d3.interpolateHcl));
};
/**
* Set or the get color accessor function. This function will be used to map a data point in a
* crossfilter group to a color value on the color scale. The default function uses the key
* accessor.
* @method colorAccessor
* @memberof dc.colorMixin
* @instance
* @example
* // default index based color accessor
* .colorAccessor(function (d, i){return i;})
* // color accessor for a multi-value crossfilter reduction
* .colorAccessor(function (d){return d.value.absGain;})
* @param {Function} [colorAccessor]
* @returns {Function|dc.colorMixin}
*/
_chart.colorAccessor = function (colorAccessor) {
if (!arguments.length) {
return _colorAccessor;
}
_colorAccessor = colorAccessor;
_defaultAccessor = false;
return _chart;
};
// what is this?
_chart.defaultColorAccessor = function () {
return _defaultAccessor;
};
/**
* Set or get the current domain for the color mapping function. The domain must be supplied as an
* array.
*
* Note: previously this method accepted a callback function. Instead you may use a custom scale
* set by {@link dc.colorMixin#colors .colors}.
* @method colorDomain
* @memberof dc.colorMixin
* @instance
* @param {Array<String>} [domain]
* @returns {Array<String>|dc.colorMixin}
*/
_chart.colorDomain = function (domain) {
if (!arguments.length) {
return _colors.domain();
}
_colors.domain(domain);
return _chart;
};
/**
* Set the domain by determining the min and max values as retrieved by
* {@link dc.colorMixin#colorAccessor .colorAccessor} over the chart's dataset.
* @method calculateColorDomain
* @memberof dc.colorMixin
* @instance
* @returns {dc.colorMixin}
*/
_chart.calculateColorDomain = function () {
var newDomain = [d3.min(_chart.data(), _chart.colorAccessor()),
d3.max(_chart.data(), _chart.colorAccessor())];
_colors.domain(newDomain);
return _chart;
};
/**
* Get the color for the datum d and counter i. This is used internally by charts to retrieve a color.
* @method getColor
* @memberof dc.colorMixin
* @instance
* @param {*} d
* @param {Number} [i]
* @returns {String}
*/
_chart.getColor = function (d, i) {
return _colorCalculator ? _colorCalculator.call(this, d, i) : _colors(_colorAccessor.call(this, d, i));
};
/**
* Overrides the color selection algorithm, replacing it with a simple function.
*
* Normally colors will be determined by calling the `colorAccessor` to get a value, and then passing that
* value through the `colorScale`.
*
* But sometimes it is difficult to get a color scale to produce the desired effect. The `colorCalculator`
* takes the datum and index and returns a color directly.
* @method colorCalculator
* @memberof dc.colorMixin
* @instance
* @param {*} [colorCalculator]
* @returns {Function|dc.colorMixin}
*/
_chart.colorCalculator = function (colorCalculator) {
if (!arguments.length) {
return _colorCalculator || _chart.getColor;
}
_colorCalculator = colorCalculator;
return _chart;
};
return _chart;
};