/** * @class Ext.draw.modifier.Target * @extends Ext.draw.modifier.Modifier * * This is the destination (top) modifier that has to be put at * the top of the modifier stack. * * The Target modifier figures out which updaters have to be called * for the changed set of attributes and makes the sprite and its instances (if any) * call them. */Ext.define('Ext.draw.modifier.Target', { requires: ['Ext.draw.Matrix'], extend: 'Ext.draw.modifier.Modifier', alias: 'modifier.target', statics: { /** * @private */ uniqueId: 0 }, prepareAttributes: function(attr) { if (this._lower) { this._lower.prepareAttributes(attr); } attr.attributeId = 'attribute-' + Ext.draw.modifier.Target.uniqueId++; if (!attr.hasOwnProperty('canvasAttributes')) { attr.bbox = { plain: { dirty: true }, transform: { dirty: true } }; attr.dirty = true; /* Maps updaters that have to be called to the attributes that triggered the update. It is basically a reversed `triggers` map (see Ext.draw.sprite.AttributeDefinition), but only for those attributes that have changed. Pending updaters are called by the Ext.draw.sprite.Sprite.callUpdaters method. The 'canvas' updater is a special kind of updater that is not actually a function but a flag indicating that the attribute should be applied directly to a canvas context. */ attr.pendingUpdaters = {}; /* Holds the attributes that triggered the canvas update (attr.pendingUpdaters.canvas). Canvas attributes are applied directly to a canvas context by the sprite.useAttributes method. */ attr.canvasAttributes = {}; attr.matrix = new Ext.draw.Matrix(); attr.inverseMatrix = new Ext.draw.Matrix(); } }, /** * @private * Applies changes to sprite/instance attributes and determines which updaters * have to be called as a result of attributes change. * @param {Object} attr The source attributes. * @param {Object} changes The modifier changes. */ applyChanges: function(attr, changes) { Ext.apply(attr, changes); // eslint-disable-next-line vars-on-top var sprite = this.getSprite(), pendingUpdaters = attr.pendingUpdaters, triggers = sprite.self.def.getTriggers(), updaters, instances, instance, name, hasChanges, canvasAttributes, i, j, ln; for (name in changes) { hasChanges = true; if ((updaters = triggers[name])) { sprite.scheduleUpdaters(attr, updaters, [name]); } if (attr.template && changes.removeFromInstance && changes.removeFromInstance[name]) { delete attr[name]; } } if (!hasChanges) { return; } // This can prevent sub objects to set duplicated attributes to context. if (pendingUpdaters.canvas) { canvasAttributes = pendingUpdaters.canvas; delete pendingUpdaters.canvas; for (i = 0, ln = canvasAttributes.length; i < ln; i++) { name = canvasAttributes[i]; attr.canvasAttributes[name] = attr[name]; } } // If the attributes of an instancing sprite template are being modified here, // then spread the pending updaters to the instances (template's children). if (attr.hasOwnProperty('children')) { instances = attr.children; for (i = 0, ln = instances.length; i < ln; i++) { instance = instances[i]; Ext.apply(instance.pendingUpdaters, pendingUpdaters); if (canvasAttributes) { for (j = 0; j < canvasAttributes.length; j++) { name = canvasAttributes[j]; instance.canvasAttributes[name] = instance[name]; } } sprite.callUpdaters(instance); } } sprite.setDirty(true); sprite.callUpdaters(attr); }, popUp: function(attr, changes) { this.applyChanges(attr, changes); }, pushDown: function(attr, changes) { // Modifier chain looks like this: // sprite.modifiers.target <---> postFx <---> sprite.modifiers.animation <---> preFx // There can be any number of postFx and preFx modifiers, the difference between them // is that: // `preFx` modifier changes are animated. // `postFx` modifier changes are not. // preFx modifiers include Highlight (Draw) and Callout (Charts). // There are no postFx modifiers at the moment. if (this._lower) { // Without any postFx modifiers, `lower` is going to be Animation. changes = this._lower.pushDown(attr, changes); } this.applyChanges(attr, changes); return changes; }});