Как стать автором
Обновить

Canvas Indicator — альтернатива для AjaxLoad.gif

Время на прочтение 3 мин
Количество просмотров 2.9K
Многие наверняка используют индикаторы процесса, например, когда передаете/получаете какие-нибудь данные через AJAX.

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

Делать специальный GIF под каждую ситуацию довольно глупо. Поэтому правильное решение — использовать Canvas.



В первые же минуты, я наткнулся на этот JavaScript модуль, с помощью которого можно хоть загенерироваться подобными индикаторами:


Но проблему это не решило, не с технической конечно стороны, а с дизайнерской. Человек, занимающийся этими вопросами настаивал, чтобы по кругу бегали не кружочки, а палочки, как тут:


Изначально я наткнулся на эту библиотеку, но в ней реализовано много функций, которые я даже не планировал использовать. Поиски пришлось продолжить.

В итоге я наткнулся на одну запись, которая почти решала мою проблему.

Убрав лишнее, добавив нужное, я с удовольствием поделюсь решением с вами.

Пример использования. В нужном месте, ставим тег canvas:

<canvas id="loader"></canvas>


И создаем экземпляр класса CanvasIndicator:
new CanvasIndicator(document.getElementById("loader"),{
        bars:11,
        innerRadius:4,
        size:[2,5],
        rgb:[255,255,255],
        fps:10
    });


Как видно, конструктор CanvasIndicator принимает два параметра: первый обязательно — холст, где собственно и будет происходить действие. Второй параметр опционален — это объект, свойства которого являются конфигурацией индикатора.

Подробнее о свойствах:

bars — количество блоков
innerRadius — внутренний радиус
size — массив, где первый элемент — это ширина блока, а второй — его высота
rgb — цвет индикатора, задается массивом из трех элементов, где Red, Green, Blue — соответственно
fps — количество кадров в секунду, чем больше значение, тем быстрее крутится индикатор

Ну и непосредственно код библиотеки CanvasIndicator.js

function CanvasIndicator(el, opt) {
    this.ctx = el.getContext("2d");
    this.currentOffset = 0;
    var defaults = {
        bars: 11,
        innerRadius: 4,
        size: [2, 5],
        rgb: [255, 255, 255],
        fps: 10
    }
    if (typeof(opt) == 'object') {
        defaults.bars = opt.bars ? opt.bars : defaults.bars;
        defaults.innerRadius = opt.innerRadius ? opt.innerRadius : defaults.innerRadius;
        defaults.size = opt.size ? opt.size : defaults.size;
        defaults.rgb = opt.rgb ? opt.rgb : defaults.rgb;
        defaults.fps = opt.fps ? opt.fps : defaults.fps;
    }
    this.opt = defaults;
    this.w = this.opt.size[1] + this.opt.innerRadius;
    el.setAttribute("width", this.w * 2);
    el.setAttribute("height", this.w * 2);
    (function nextAnimation(obj) {
        obj.currentOffset = (obj.currentOffset + 1) % obj.opt.bars;
        obj.draw(obj.currentOffset);
        setTimeout(function () {
            nextAnimation(obj);
        }, 1000 / obj.opt.fps);
    })(this);

}
CanvasIndicator.prototype.makeRGBA = function () {
    return "rgba(" + [].slice.call(arguments, 0).join(",") + ")";
}
CanvasIndicator.prototype.drawBlock = function (barNo) {
    this.ctx.fillStyle = this.makeRGBA(this.opt.rgb[0], this.opt.rgb[1], this.opt.rgb[2], (this.opt.bars + 1 - barNo) / (this.opt.bars + 1));
    this.ctx.fillRect(-this.opt.size[0] / 2, 0, this.opt.size[0], this.opt.size[1]);
}
CanvasIndicator.prototype.calculatePosition = function (barNo) {
    angle = 2 * barNo * Math.PI / this.opt.bars;
    return {
        y: (this.opt.innerRadius * Math.cos(-angle)),
        x: (this.opt.innerRadius * Math.sin(-angle)),
        angle: angle
    };
}
CanvasIndicator.prototype.draw = function (offset) {
    this.clearFrame();
    this.ctx.save();
    this.ctx.translate(this.w, this.w);
    for (var i = 0; i < this.opt.bars; i++) {
        var curbar = (offset + i) % this.opt.bars,
            pos = this.calculatePosition(curbar);
        this.ctx.save();
        this.ctx.translate(pos.x, pos.y);
        this.ctx.rotate(pos.angle);
        this.drawBlock(i);
        this.ctx.restore();
    }
    this.ctx.restore();
}
CanvasIndicator.prototype.clearFrame = function () {
    this.ctx.clearRect(0, 0, this.ctx.canvas.clientWidth, this.ctx.canvas.clientHeight);
}


Посмотреть пример можно здесь.
Скачать библиотеку можно тут
Теги:
Хабы:
+47
Комментарии 74
Комментарии Комментарии 74

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн