Чтобы привлечь внимание пользователей к некоторым событиям, мы можем изменить визуальные свойства иконок, например — цвет или цвет фона. Мы также можем анимировать значок, я не фанат анимации, но иногда это бывает необходимо. В данном примере я покажу вам, как сделать анимацию на примере обычной Ext.button.Button. Все эффекты могут накладываться друг на друга, то есть иконка кнопки может показывать и биение и вращаться одновременно.
Все визуальные эффекты создаются миксинами. Мы должны быть особенно осторожны, что бы не переопределить существующие методы.
Ext.define('app.ux.button.animation.beating.Mixin', {
glyphBeatingTaskRunner: false,
glyphBeatingTaskRunnerInterval: 100,
startBeating: function () {
if(!this.glyphBeatingTaskRunner) {
this.glyphBeatingTaskRunner = new Ext.util.TaskRunner();
if (!this.glyphBeatingTask) {
this.beatingSizeMax = this.btnIconEl.getWidth();
this.glyphSize = this.beatingSizeMin = this.beatingSizeMax * 0.4;
this.beatingSizeStep = (this.beatingSizeMax - this.beatingSizeMin) * 0.1;
this.glyphBeatingTask = this.glyphBeatingTaskRunner.start({
me.updateGlyphSize.call(me);
interval: this.glyphBeatingTaskRunnerInterval
stopBeating: function () {
if (this.glyphBeatingTask) {
this.glyphBeatingTaskRunner.stop(
updateGlyphSize: function () {
this.glyphSize = this.glyphSize + this.beatingSizeStep;
if (this.glyphSize > this.beatingSizeMax || this.glyphSize < this.beatingSizeMin) {
this.beatingSizeStep = this.beatingSizeStep * -1;
this.setGlyphSize(Math.floor(this.glyphSize));
setGlyphSize: function(glyphSize) {
glyphSize = Ext.isNumeric(glyphSize) ? glyphSize: null;
this.btnIconEl.setStyle('font-size', glyphSize + 'px');
Ext.define('app.ux.button.animation.beating.Mixin', {
extend: 'Ext.Mixin',
glyphBeatingTaskRunner: false,
glyphBeatingTask: false,
glyphBeatingTaskRunnerInterval: 100,
startBeating: function () {
var me = this;
if(!this.glyphBeatingTaskRunner) {
this.glyphBeatingTaskRunner = new Ext.util.TaskRunner();
}
if (!this.glyphBeatingTask) {
this.beatingSizeMax = this.btnIconEl.getWidth();
this.glyphSize = this.beatingSizeMin = this.beatingSizeMax * 0.4;
this.beatingSizeStep = (this.beatingSizeMax - this.beatingSizeMin) * 0.1;
}
this.glyphBeatingTask = this.glyphBeatingTaskRunner.start({
run: function () {
me.updateGlyphSize.call(me);
},
interval: this.glyphBeatingTaskRunnerInterval
});
return this;
},
stopBeating: function () {
if (this.glyphBeatingTask) {
this.glyphBeatingTaskRunner.stop(
this.glyphBeatingTask,
true
);
}
return this;
},
updateGlyphSize: function () {
this.glyphSize = this.glyphSize + this.beatingSizeStep;
if (this.glyphSize > this.beatingSizeMax || this.glyphSize < this.beatingSizeMin) {
this.beatingSizeStep = this.beatingSizeStep * -1;
}
this.setGlyphSize(Math.floor(this.glyphSize));
},
setGlyphSize: function(glyphSize) {
glyphSize = Ext.isNumeric(glyphSize) ? glyphSize: null;
this.btnIconEl.setStyle('font-size', glyphSize + 'px');
return this;
}
});
Ext.define('app.ux.button.animation.rotate.Mixin', {
glyphRotateTaskRunner: false,
glyphRotateTaskRunnerInterval: 100,
startRotate: function () {
if (!this.glyphRotateTaskRunner) {
this.glyphRotateTaskRunner = new Ext.util.TaskRunner();
this.glyphRotateTask = this.glyphRotateTaskRunner.start({
interval: this.glyphRotateTaskRunnerInterval
stopRotate: function () {
if (this.glyphRotateTask) {
this.glyphRotateTaskRunner.stop(
rotateGlyph: function () {
this.glyphRotateDeg = this.glyphRotateDeg + this.glyphRotateStep;
if (this.glyphRotateDeg > 360) {
this.setGlyphRotationDeg(Math.floor(this.glyphRotateDeg));
setGlyphRotationDeg: function(glyphRotateDeg) {
glyphRotateDeg = Ext.isNumeric(glyphRotateDeg) ? glyphRotateDeg: null;
this.btnIconEl.setStyle('-webkit-transform', 'rotate(' + glyphRotateDeg + 'deg)');
Ext.define('app.ux.button.animation.rotate.Mixin', {
extend: 'Ext.Mixin',
glyphRotateTaskRunner: false,
glyphRotateTask: false,
glyphRotateTaskRunnerInterval: 100,
glyphRotateDeg: 0,
glyphRotateStep: 10,
startRotate: function () {
var me = this;
if (!this.glyphRotateTaskRunner) {
this.glyphRotateTaskRunner = new Ext.util.TaskRunner();
}
this.glyphRotateTask = this.glyphRotateTaskRunner.start({
run: function () {
me.rotateGlyph.call(me);
},
interval: this.glyphRotateTaskRunnerInterval
});
return this;
},
stopRotate: function () {
if (this.glyphRotateTask) {
this.glyphRotateTaskRunner.stop(
this.glyphRotateTask,
true
);
}
return this;
},
rotateGlyph: function () {
this.glyphRotateDeg = this.glyphRotateDeg + this.glyphRotateStep;
if (this.glyphRotateDeg > 360) {
this.glyphRotateDeg = 0;
}
this.setGlyphRotationDeg(Math.floor(this.glyphRotateDeg));
},
setGlyphRotationDeg: function(glyphRotateDeg) {
glyphRotateDeg = Ext.isNumeric(glyphRotateDeg) ? glyphRotateDeg: null;
this.btnIconEl.setStyle('-webkit-transform', 'rotate(' + glyphRotateDeg + 'deg)');
return this;
}
});
Ext.define('app.ux.button.animation.beating.Mixin', {
extend: 'Ext.Mixin',
glyphBeatingTaskRunner: false,
glyphBeatingTask: false,
glyphBeatingTaskRunnerInterval: 100,
startBeating: function () {
var me = this;
if(!this.glyphBeatingTaskRunner) {
this.glyphBeatingTaskRunner = new Ext.util.TaskRunner();
}
if (!this.glyphBeatingTask) {
this.beatingSizeMax = this.btnIconEl.getWidth();
this.glyphSize = this.beatingSizeMin = this.beatingSizeMax * 0.4;
this.beatingSizeStep = (this.beatingSizeMax - this.beatingSizeMin) * 0.1;
}
this.glyphBeatingTask = this.glyphBeatingTaskRunner.start({
run: function () {
me.updateGlyphSize.call(me);
},
interval: this.glyphBeatingTaskRunnerInterval
});
return this;
},
stopBeating: function () {
if (this.glyphBeatingTask) {
this.glyphBeatingTaskRunner.stop(
this.glyphBeatingTask,
true
);
}
return this;
},
updateGlyphSize: function () {
this.glyphSize = this.glyphSize + this.beatingSizeStep;
if (this.glyphSize > this.beatingSizeMax || this.glyphSize < this.beatingSizeMin) {
this.beatingSizeStep = this.beatingSizeStep * -1;
}
this.setGlyphSize(Math.floor(this.glyphSize));
},
setGlyphSize: function(glyphSize) {
glyphSize = Ext.isNumeric(glyphSize) ? glyphSize: null;
this.btnIconEl.setStyle('font-size', glyphSize + 'px');
return this;
}
});
Ext.define('app.ux.button.animation.rotate.Mixin', {
extend: 'Ext.Mixin',
glyphRotateTaskRunner: false,
glyphRotateTask: false,
glyphRotateTaskRunnerInterval: 100,
glyphRotateDeg: 0,
glyphRotateStep: 10,
startRotate: function () {
var me = this;
if (!this.glyphRotateTaskRunner) {
this.glyphRotateTaskRunner = new Ext.util.TaskRunner();
}
this.glyphRotateTask = this.glyphRotateTaskRunner.start({
run: function () {
me.rotateGlyph.call(me);
},
interval: this.glyphRotateTaskRunnerInterval
});
return this;
},
stopRotate: function () {
if (this.glyphRotateTask) {
this.glyphRotateTaskRunner.stop(
this.glyphRotateTask,
true
);
}
return this;
},
rotateGlyph: function () {
this.glyphRotateDeg = this.glyphRotateDeg + this.glyphRotateStep;
if (this.glyphRotateDeg > 360) {
this.glyphRotateDeg = 0;
}
this.setGlyphRotationDeg(Math.floor(this.glyphRotateDeg));
},
setGlyphRotationDeg: function(glyphRotateDeg) {
glyphRotateDeg = Ext.isNumeric(glyphRotateDeg) ? glyphRotateDeg: null;
this.btnIconEl.setStyle('-webkit-transform', 'rotate(' + glyphRotateDeg + 'deg)');
return this;
}
});
Цвета иконок и цвета фона реализованы в виде расширения класса. Здесь я переопределяю iconTpl из Ext.button.Button
Ext.define('app.ux.button.Button', {
extend: 'Ext.button.Button',
beating: 'app.ux.button.animation.beating.Mixin',
rotate: 'app.ux.button.animation.rotate.Mixin'
glyphBackgroundColor: false,
'<span id="{id}-btnIconEl" data-ref="btnIconEl" role="presentation" unselectable="on" class="{baseIconCls} ' +
'{baseIconCls}-{ui} {iconCls} {glyphCls}{childElCls}" style="' +
'<tpl if="iconUrl">background-image:url({iconUrl});</tpl>' +
'<tpl if="glyphFontFamily">' +
'font-family:{glyphFontFamily};' +
'<tpl if="glyphColor">' +
' color: {glyphColor};' +
'<tpl if="glyphBackgroundColor">' +
' background-color: {glyphBackgroundColor};' +
' font-size: {glyphSize};' +
initComponent: function() {
setGlyphColor: function(rgbColor) {
this.glyphColor = this.isValidRgb(rgbColor) ? rgbColor: null;
this.btnIconEl.setStyle('color', this.glyphColor);
getGlyphColor: function() {
setGlyphBackgroundColor: function(rgbColor) {
this.glyphBackgroundColor = this.isValidRgb(rgbColor) ? rgbColor: null;
this.btnIconEl.setStyle('background-color', this.glyphBackgroundColor);
getGlyphBackgroundColor: function() {
return this.glyphBackgroundColor;
getGlyphSize: function() {
getTemplateArgs: function() {
var templateArgs = this.callParent();
templateArgs.glyphColor = this.glyphColor;
templateArgs.glyphBackgroundColor = this.glyphBackgroundColor;
templateArgs.glyphSize = this.glyphSize;
isValidRgb: function(rgb) {
var isValid = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(rgb);
Ext.define('app.ux.button.Button', {
extend: 'Ext.button.Button',
mixins: {
beating: 'app.ux.button.animation.beating.Mixin',
rotate: 'app.ux.button.animation.rotate.Mixin'
},
glyphColor: false,
glyphBackgroundColor: false,
glyphSize: false,
iconTpl:
'<span id="{id}-btnIconEl" data-ref="btnIconEl" role="presentation" unselectable="on" class="{baseIconCls} ' +
'{baseIconCls}-{ui} {iconCls} {glyphCls}{childElCls}" style="' +
'<tpl if="iconUrl">background-image:url({iconUrl});</tpl>' +
'<tpl if="glyph">' +
'<tpl if="glyphFontFamily">' +
'font-family:{glyphFontFamily};' +
'<tpl if="glyphColor">' +
' color: {glyphColor};' +
'</tpl>' +
'<tpl if="glyphBackgroundColor">' +
' background-color: {glyphBackgroundColor};' +
'</tpl>' +
'<tpl if="glyphSize">' +
' font-size: {glyphSize};' +
'</tpl>' +
'</tpl>' +
'">{glyph}' +
'<tpl else>' +
'">' +
'</tpl>' +
'</span>',
initComponent: function() {
this.callParent();
},
setGlyphColor: function(rgbColor) {
this.glyphColor = this.isValidRgb(rgbColor) ? rgbColor: null;
this.btnIconEl.setStyle('color', this.glyphColor);
return this;
},
getGlyphColor: function() {
return this.glyphColor;
},
setGlyphBackgroundColor: function(rgbColor) {
this.glyphBackgroundColor = this.isValidRgb(rgbColor) ? rgbColor: null;
this.btnIconEl.setStyle('background-color', this.glyphBackgroundColor);
return this;
},
getGlyphBackgroundColor: function() {
return this.glyphBackgroundColor;
},
getGlyphSize: function() {
return this.glyphSize;
},
getTemplateArgs: function() {
var templateArgs = this.callParent();
templateArgs.glyphColor = this.glyphColor;
templateArgs.glyphBackgroundColor = this.glyphBackgroundColor;
templateArgs.glyphSize = this.glyphSize;
return templateArgs;
},
isValidRgb: function(rgb) {
var isValid = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(rgb);
return isValid;
}
});
Ext.define('app.ux.button.Button', {
extend: 'Ext.button.Button',
mixins: {
beating: 'app.ux.button.animation.beating.Mixin',
rotate: 'app.ux.button.animation.rotate.Mixin'
},
glyphColor: false,
glyphBackgroundColor: false,
glyphSize: false,
iconTpl:
'<span id="{id}-btnIconEl" data-ref="btnIconEl" role="presentation" unselectable="on" class="{baseIconCls} ' +
'{baseIconCls}-{ui} {iconCls} {glyphCls}{childElCls}" style="' +
'<tpl if="iconUrl">background-image:url({iconUrl});</tpl>' +
'<tpl if="glyph">' +
'<tpl if="glyphFontFamily">' +
'font-family:{glyphFontFamily};' +
'<tpl if="glyphColor">' +
' color: {glyphColor};' +
'</tpl>' +
'<tpl if="glyphBackgroundColor">' +
' background-color: {glyphBackgroundColor};' +
'</tpl>' +
'<tpl if="glyphSize">' +
' font-size: {glyphSize};' +
'</tpl>' +
'</tpl>' +
'">{glyph}' +
'<tpl else>' +
'">' +
'</tpl>' +
'</span>',
initComponent: function() {
this.callParent();
},
setGlyphColor: function(rgbColor) {
this.glyphColor = this.isValidRgb(rgbColor) ? rgbColor: null;
this.btnIconEl.setStyle('color', this.glyphColor);
return this;
},
getGlyphColor: function() {
return this.glyphColor;
},
setGlyphBackgroundColor: function(rgbColor) {
this.glyphBackgroundColor = this.isValidRgb(rgbColor) ? rgbColor: null;
this.btnIconEl.setStyle('background-color', this.glyphBackgroundColor);
return this;
},
getGlyphBackgroundColor: function() {
return this.glyphBackgroundColor;
},
getGlyphSize: function() {
return this.glyphSize;
},
getTemplateArgs: function() {
var templateArgs = this.callParent();
templateArgs.glyphColor = this.glyphColor;
templateArgs.glyphBackgroundColor = this.glyphBackgroundColor;
templateArgs.glyphSize = this.glyphSize;
return templateArgs;
},
isValidRgb: function(rgb) {
var isValid = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(rgb);
return isValid;
}
});
Fiddle: