Визуальные эффекты иконок (глифов)

Чтобы привлечь внимание пользователей к некоторым событиям, мы можем изменить визуальные свойства иконок, например — цвет или цвет фона. Мы также можем анимировать значок, я не фанат анимации, но иногда это бывает необходимо. В данном примере я покажу вам, как сделать анимацию на примере обычной Ext.button.Button. Все эффекты могут накладываться друг на друга, то есть иконка кнопки может показывать и биение и вращаться одновременно.

Все визуальные эффекты создаются миксинами. Мы должны быть особенно осторожны, что бы не переопределить существующие методы.

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',

    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:

Добавить комментарий

Ваш адрес email не будет опубликован.