Decomplexify Chart.core.controller.eventHandler

Refactor redundant code, use local variables and introduce a new helper to compare arrays (Chart.helpers.arrayEquals).
This commit is contained in:
Simon Brunel 2016-05-22 00:21:59 +02:00
parent d584afb543
commit 7f71990a40
2 changed files with 99 additions and 95 deletions

View File

@ -388,6 +388,20 @@ module.exports = function(Chart) {
return elementsArray;
},
getElementsAtEventForMode: function(e, mode) {
var me = this;
switch (mode) {
case 'single':
return me.getElementAtEvent(e);
case 'label':
return me.getElementsAtEvent(e);
case 'dataset':
return me.getDatasetAtEvent(e);
default:
return e;
}
},
getDatasetAtEvent: function(e) {
var elementsArray = this.getElementAtEvent(e);
@ -484,140 +498,106 @@ module.exports = function(Chart) {
this.eventHandler(evt);
});
},
updateHoverStyle: function(elements, mode, enabled) {
var method = enabled? 'setHoverStyle' : 'removeHoverStyle';
var element, i, ilen;
switch (mode) {
case 'single':
elements = [ elements[0] ];
break;
case 'label':
case 'dataset':
// elements = elements;
break;
default:
// unsupported mode
return;
}
for (i=0, ilen=elements.length; i<ilen; ++i) {
element = elements[i];
if (element) {
this.getDatasetMeta(element._datasetIndex).controller[method](element);
}
}
},
eventHandler: function eventHandler(e) {
this.lastActive = this.lastActive || [];
this.lastTooltipActive = this.lastTooltipActive || [];
var me = this;
var tooltip = me.tooltip;
var options = me.options || {};
var hoverOptions = options.hover;
var tooltipsOptions = options.tooltips;
me.lastActive = me.lastActive || [];
me.lastTooltipActive = me.lastTooltipActive || [];
// Find Active Elements for hover and tooltips
if (e.type === 'mouseout') {
this.active = [];
this.tooltipActive = [];
me.active = [];
me.tooltipActive = [];
} else {
var _this = this;
var getItemsForMode = function(mode) {
switch (mode) {
case 'single':
return _this.getElementAtEvent(e);
case 'label':
return _this.getElementsAtEvent(e);
case 'dataset':
return _this.getDatasetAtEvent(e);
default:
return e;
}
};
this.active = getItemsForMode(this.options.hover.mode);
this.tooltipActive = getItemsForMode(this.options.tooltips.mode);
me.active = me.getElementsAtEventForMode(e, hoverOptions.mode);
me.tooltipActive = me.getElementsAtEventForMode(e, tooltipsOptions.mode);
}
// On Hover hook
if (this.options.hover.onHover) {
this.options.hover.onHover.call(this, this.active);
if (hoverOptions.onHover) {
hoverOptions.onHover.call(me, me.active);
}
if (e.type === 'mouseup' || e.type === 'click') {
if (this.options.onClick) {
this.options.onClick.call(this, e, this.active);
if (options.onClick) {
options.onClick.call(me, e, me.active);
}
if (this.legend && this.legend.handleEvent) {
this.legend.handleEvent(e);
if (me.legend && me.legend.handleEvent) {
me.legend.handleEvent(e);
}
}
// Remove styling for last active (even if it may still be active)
if (this.lastActive.length) {
var lastActive;
switch (this.options.hover.mode) {
case 'single':
lastActive = this.lastActive[0];
this.getDatasetMeta(lastActive._datasetIndex).controller.removeHoverStyle(lastActive, lastActive._datasetIndex, lastActive._index);
break;
case 'label':
case 'dataset':
for (var i = 0; i < this.lastActive.length; i++) {
lastActive = this.lastActive[i];
if (lastActive)
this.getDatasetMeta(lastActive._datasetIndex).controller.removeHoverStyle(lastActive, lastActive._datasetIndex, lastActive._index);
}
break;
default:
// Don't change anything
}
if (me.lastActive.length) {
me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
}
// Built in hover styling
if (this.active.length && this.options.hover.mode) {
var active;
switch (this.options.hover.mode) {
case 'single':
active = this.active[0];
this.getDatasetMeta(active._datasetIndex).controller.setHoverStyle(active);
break;
case 'label':
case 'dataset':
for (var j = 0; j < this.active.length; j++) {
active = this.active[j];
if (active)
this.getDatasetMeta(active._datasetIndex).controller.setHoverStyle(active);
}
break;
default:
// Don't change anything
}
if (me.active.length && hoverOptions.mode) {
me.updateHoverStyle(me.active, hoverOptions.mode, true);
}
var tooltip = this.tooltip;
// Built in Tooltips
if (this.options.tooltips.enabled || this.options.tooltips.custom) {
// The usual updates
if (tooltipsOptions.enabled || tooltipsOptions.custom) {
tooltip.initialize();
tooltip._active = this.tooltipActive;
tooltip._active = me.tooltipActive;
tooltip.update(true);
}
// Hover animations
tooltip.pivot();
if (!this.animating) {
var changed;
helpers.each(this.active, function(element, index) {
if (element !== this.lastActive[index]) {
changed = true;
}
}, this);
helpers.each(this.tooltipActive, function(element, index) {
if (element !== this.lastTooltipActive[index]) {
changed = true;
}
}, this);
if (!me.animating) {
// If entering, leaving, or changing elements, animate the change via pivot
if ((this.lastActive.length !== this.active.length) ||
(this.lastTooltipActive.length !== this.tooltipActive.length) ||
changed) {
if (!helpers.arrayEquals(me.active, me.lastActive) ||
!helpers.arrayEquals(me.tooltipActive, me.lastTooltipActive)) {
this.stop();
me.stop();
if (this.options.tooltips.enabled || this.options.tooltips.custom) {
if (tooltipsOptions.enabled || tooltipsOptions.custom) {
tooltip.update(true);
}
// We only need to render at this point. Updating will cause scales to be recomputed generating flicker & using more
// memory than necessary.
this.render(this.options.hover.animationDuration, true);
// We only need to render at this point. Updating will cause scales to be
// recomputed generating flicker & using more memory than necessary.
me.render(hoverOptions.animationDuration, true);
}
}
// Remember Last Actives
this.lastActive = this.active;
this.lastTooltipActive = this.tooltipActive;
return this;
me.lastActive = me.active;
me.lastTooltipActive = me.tooltipActive;
return me;
}
});
};

View File

@ -925,6 +925,30 @@ module.exports = function(Chart) {
}
return Array.isArray(obj);
};
//! @see http://stackoverflow.com/a/14853974
helpers.arrayEquals = function(a0, a1) {
var i, ilen, v0, v1;
if (!a0 || !a1 || a0.length != a1.length) {
return false;
}
for (i = 0, ilen=a0.length; i < ilen; ++i) {
v0 = a0[i];
v1 = a1[i];
if (v0 instanceof Array && v1 instanceof Array) {
if (!helpers.arrayEquals(v0, v1)) {
return false;
}
} else if (v0 != v1) {
// NOTE: two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
};
helpers.pushAllIfDefined = function(element, array) {
if (typeof element === "undefined") {
return;