/** * @class Ext.chart.interactions.Abstract * * Defines a common abstract parent class for all interactions. * */Ext.define('Ext.chart.interactions.Abstract', { xtype: 'interaction', mixins: { observable: 'Ext.mixin.Observable' }, config: { /** * @cfg {Object} gesture * Maps gestures that should be used for starting/maintaining/ending the interaction * to corresponding class methods. * @private */ gestures: { tap: 'onGesture' }, /** * @cfg {Ext.chart.AbstractChart} chart The chart that the interaction is bound. */ chart: null, /** * @cfg {Boolean} enabled 'true' if the interaction is enabled. */ enabled: true }, /** * Android device is emerging too many events so if we re-render every frame it will * take forever to finish a frame. * This throttle technique will limit the timespan between two frames. */ throttleGap: 0, stopAnimationBeforeSync: false, constructor: function(config) { var me = this, id; config = config || {}; if ('id' in config) { id = config.id; } else if ('id' in me.config) { id = me.config.id; } else { id = me.getId(); } me.setId(id); me.mixins.observable.constructor.call(me, config); }, updateChart: function(newChart, oldChart) { var me = this; if (oldChart === newChart) { return; } if (oldChart) { oldChart.unregister(me); me.removeChartListener(oldChart); } if (newChart) { newChart.register(me); me.addChartListener(); } }, updateEnabled: function(enabled) { var me = this, chart = me.getChart(); if (chart) { if (enabled) { me.addChartListener(); } else { me.removeChartListener(chart); } } }, /** * @method * @protected * Placeholder method. */ onGesture: Ext.emptyFn, /** * @protected * Find and return a single series item corresponding to the given event, * or null if no matching item is found. * @param {Event} e * @return {Object} the item object or null if none found. */ getItemForEvent: function(e) { var me = this, chart = me.getChart(), chartXY = chart.getEventXY(e); return chart.getItemForPoint(chartXY[0], chartXY[1]); }, /** * Find and return all series items corresponding to the given event. * @param {Event} e * @return {Array} array of matching item objects * @private * @deprecated 6.5.2 This method is deprecated */ getItemsForEvent: function(e) { var me = this, chart = me.getChart(), chartXY = chart.getEventXY(e); return chart.getItemsForPoint(chartXY[0], chartXY[1]); }, /** * @private */ addChartListener: function() { var me = this, chart = me.getChart(), gestures = me.getGestures(), gesture; if (!me.getEnabled()) { return; } function insertGesture(name, fn) { chart.addElementListener( name, // wrap the handler so it does not fire if the event is locked // by another interaction me.listeners[name] = function(e) { var locks = me.getLocks(), result; if (me.getEnabled() && (!(name in locks) || locks[name] === me)) { result = (Ext.isFunction(fn) ? fn : me[fn]).apply(this, arguments); if (result === false && e && e.stopPropagation) { e.stopPropagation(); } return result; } }, me ); } me.listeners = me.listeners || {}; for (gesture in gestures) { insertGesture(gesture, gestures[gesture]); } }, removeChartListener: function(chart) { var me = this, gestures = me.getGestures(), gesture; function removeGesture(name) { var fn = me.listeners[name]; if (fn) { chart.removeElementListener(name, fn); delete me.listeners[name]; } } if (me.listeners) { for (gesture in gestures) { removeGesture(gesture); } } }, lockEvents: function() { var me = this, locks = me.getLocks(), args = Array.prototype.slice.call(arguments), i = args.length; while (i--) { locks[args[i]] = me; } }, unlockEvents: function() { var locks = this.getLocks(), args = Array.prototype.slice.call(arguments), i = args.length; while (i--) { delete locks[args[i]]; } }, getLocks: function() { var chart = this.getChart(); return chart.lockedEvents || (chart.lockedEvents = {}); }, doSync: function() { var me = this, chart = me.getChart(); if (me.syncTimer) { Ext.undefer(me.syncTimer); me.syncTimer = null; } if (me.stopAnimationBeforeSync) { chart.animationSuspendCount++; } chart.redraw(); if (me.stopAnimationBeforeSync) { chart.animationSuspendCount--; } me.syncThrottle = Date.now() + me.throttleGap; }, sync: function() { var me = this; if (me.throttleGap && Ext.frameStartTime < me.syncThrottle) { if (me.syncTimer) { return; } me.syncTimer = Ext.defer(function() { me.doSync(); }, me.throttleGap); } else { me.doSync(); } }, getItemId: function() { return this.getId(); }, isXType: function(xtype) { return xtype === 'interaction'; }, destroy: function() { var me = this; me.setChart(null); delete me.listeners; me.callParent(); } }, function() { if (Ext.os.is.Android4) { this.prototype.throttleGap = 40; }});