return Object.keys(scales).filter(key => scales[key].axis === axis).shift();
}
-function optionKeys(optionNames) {
- return isArray(optionNames) ? optionNames : Object.keys(optionNames);
-}
-
-function optionKey(key, active) {
- return active ? 'hover' + _capitalize(key) : key;
-}
-
-function isDirectUpdateMode(mode) {
- return mode === 'reset' || mode === 'none';
-}
+const optionKeys = (optionNames) => isArray(optionNames) ? optionNames : Object.keys(optionNames);
+const optionKey = (key, active) => active ? 'hover' + _capitalize(key) : key;
+const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none';
+const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached);
+const freezeIfShared = (values, shared) => shared ? Object.freeze(values) : values;
export default class DatasetController {
mode = mode || 'default';
const me = this;
const active = mode === 'active';
- const cached = me._cachedDataOpts;
+ const cache = me._cachedDataOpts;
+ const cached = cache[mode];
const sharing = me.enableOptionSharing;
- if (cached[mode]) {
- return cached[mode];
+ if (cached) {
+ return cloneIfNotShared(cached, sharing);
}
const info = {cacheable: !active};
// We cache options by `mode`, which can be 'active' for example. This enables us
// to have the 'active' element options and 'default' options to switch between
// when interacting.
- cached[mode] = sharing ? Object.freeze(values) : values;
+ cache[mode] = freezeIfShared(values, sharing);
}
return values;
});
});
+ describe('resolveDataElementOptions', function() {
+ it('should cache options when possible', function() {
+ const chart = acquireChart({
+ type: 'line',
+ data: {
+ datasets: [{
+ data: [1, 2, 3],
+ }]
+ },
+ });
+
+ const controller = chart.getDatasetMeta(0).controller;
+
+ expect(controller.enableOptionSharing).toBeTrue();
+
+ const opts0 = controller.resolveDataElementOptions(0);
+ const opts1 = controller.resolveDataElementOptions(1);
+
+ expect(opts0 === opts1).toBeTrue();
+ expect(opts0.$shared).toBeTrue();
+ expect(Object.isFrozen(opts0)).toBeTrue();
+ });
+
+ it('should not cache options when option sharing is disabled', function() {
+ const chart = acquireChart({
+ type: 'radar',
+ data: {
+ datasets: [{
+ data: [1, 2, 3],
+ }]
+ },
+ });
+
+ const controller = chart.getDatasetMeta(0).controller;
+
+ expect(controller.enableOptionSharing).toBeFalse();
+
+ const opts0 = controller.resolveDataElementOptions(0);
+ const opts1 = controller.resolveDataElementOptions(1);
+
+ expect(opts0 === opts1).toBeFalse();
+ expect(opts0.$shared).not.toBeTrue();
+ expect(Object.isFrozen(opts0)).toBeFalse();
+ });
+
+ it('should not cache options when functions are used', function() {
+ const chart = acquireChart({
+ type: 'line',
+ data: {
+ datasets: [{
+ data: [1, 2, 3],
+ backgroundColor: () => 'red'
+ }]
+ },
+ });
+
+ const controller = chart.getDatasetMeta(0).controller;
+
+ const opts0 = controller.resolveDataElementOptions(0);
+ const opts1 = controller.resolveDataElementOptions(1);
+
+ expect(opts0 === opts1).toBeFalse();
+ expect(opts0.$shared).not.toBeTrue();
+ expect(Object.isFrozen(opts0)).toBeFalse();
+ });
+ });
+
describe('_resolveAnimations', function() {
it('should resolve to empty Animations when globally disabled', function() {
const chart = acquireChart({