Показать сообщение отдельно
  #2 (permalink)  
Старый 03.12.2015, 09:14
Профессор
Отправить личное сообщение для tsigel Посмотреть профиль Найти все сообщения от tsigel
 
Регистрация: 12.12.2012
Сообщений: 1,398

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="35" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="99" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="62" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="22" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="72" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="12" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="82" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="55" width="300" height="300"></canvas>
<canvas class="canvas" data-color="lightblue" data-bg-color="#222" data-percent="45" width="300" height="300"></canvas>

<script>

    /**
     * @class Circle
     * @constructor
     */
    var Circle = function (canvas, callback) {

        /**
         * @type {HTMLCanvasElement}
         * @private
         */
        this._canvas = canvas;
        /**
         * @type {CanvasRenderingContext2D}
         * @private
         */
        this._ctx = canvas.getContext('2d');
        /**
         * @type {number}
         * @private
         */
        this._animateSpeed = 20;
        /**
         * @type {number}
         * @private
         */
        this._endProgress = Number(this._canvas.getAttribute('data-percent'));
        /**
         * @type {string}
         * @private
         */
        this._bgColor = this._canvas.getAttribute('data-bg-color');
        /**
         * @type {string}
         * @private
         */
        this._color = this._canvas.getAttribute('data-color');
        /**
         * @type {Array<function>}
         * @private
         */
        this._onReadyCallbacks = [];
        /**
         * @type {boolean}
         * @private
         */
        this._isReady = false;
        /**
         * @type {function}
         * @private
         */
        this._onEndAnimation = callback;
        /**
         * @type {number}
         * @private
         */
        this._radius = this._canvas.width / 2 - 3;
        /**
         * @type {number}
         * @private
         */
        this._width = this._canvas.width;
        /**
         * @type {number}
         * @private
         */
        this._height = this._canvas.height;

        this._onScroll = this._onScroll.bind(this);

        this._initialize();

    };

    /**
     * @lends Circle#
     */
    Circle.prototype = {

        setReady: function () {
            this._isReady = true;
            this._onReadyCallbacks.forEach(function (callback) {
                callback.call(this);
            }, this);
            this._onReadyCallbacks = [];
        },

        /**
         * @param {function} callback
         * @private
         */
        _onReady: function (callback) {
            if (this._isReady) {
                callback.call(this);
            } else {
                this._onReadyCallbacks.push(callback);
            }
        },

        /**
         * @returns {boolean}
         * @private
         */
        _isVisible: function () {
            var scroll = this._getScrollTop();
            var offset = this._canvas.offsetTop;
            return (scroll < offset) && (scroll + innerHeight > offset + this._canvas.height);
        },

        /**
         * @returns {number}
         * @private
         */
        _getScrollTop: function () {
            return document.body.scrollTop || document.documentElement.scrollTop;
        },

        /**
         * @private
         */
        _animate: function () {

            var time = this._endProgress * this._animateSpeed;

            Circle._animate({
                duration: time,
                step: this._redraw.bind(this),
                complete: this._onEndAnimation
            });

            window.removeEventListener('scroll', this._onScroll, false);

        },

        /**
         * @private
         */
        _clear: function () {
            this._canvas.width = this._canvas.width;
        },

        /**
         * @param {number} progress
         * @private
         */
        _draw: function (progress) {

            var angleStart = - Math.PI / 2;
            var angleEnd = angleStart + (2 * Math.PI * this._endProgress / 100) * progress;

            this._ctx.beginPath();
            this._ctx.strokeStyle = this._bgColor;
            this._ctx.lineWidth = 4;
            this._ctx.arc(this._width / 2, this._height / 2, this._radius, 0, Math.PI * 2, false);
            this._ctx.stroke();

            this._ctx.beginPath();
            this._ctx.strokeStyle = this._color;
            this._ctx.lineWidth = 4;
            this._ctx.arc(this._width / 2, this._height / 2, this._radius, angleStart, angleEnd, false);
            this._ctx.stroke();

            this._ctx.fillStyle = this._color;
            this._ctx.font = "45px bebas";
            var text = Math.floor(this._endProgress * progress) + "%";
            var text_width = this._ctx.measureText(text).width;
            this._ctx.fillText(text, this._width / 2 - text_width / 2, this._height / 2 + 15);
        },

        /**
         * @param {number} progress
         * @private
         */
        _redraw: function (progress) {
            this._clear();
            this._draw(progress);
        },

        _setHandlers: function () {
            window.addEventListener('scroll', this._onScroll, false);
        },

        _onScroll: function () {
            if (this._isVisible()) {
                this._animate();
            }
        },

        /**
         * @private
         */
        _initialize: function () {

            this._onReady(function () {

                if (this._isVisible()) {
                    this._animate();
                } else {
                    this._setHandlers();
                }

            });

            this._draw(0);

        }

    };

    /**
     * @param {Object} options
     * @param {function} options.step
     * @param {number} options.duration
     * @param {function} options.complete
     * @param {function} [options.timeFunction]
     * @private
     * @static
     */
    Circle._animate = function (options) {
        var start = Date.now(); // сохранить время начала

        requestAnimationFrame(function tick() {
            var timePassed = Date.now() - start;
            var progress = timePassed / options.duration;
            var timeFunction = options.timeFunction || function (progress) {
                        return progress;
                    };
            progress = progress > 1 ? 1 : progress;

            options.step(timeFunction(progress));

            if (progress === 1) {
                options.complete();
            } else {
                requestAnimationFrame(tick);
            }

        });
    };

    window.onload = function () {

        var canvases = Array.prototype.slice.call(document.querySelectorAll('.canvas'));
        var circles = [];
        var animateEndCount = 0;
        var onEnd = function () {
            animateEndCount++;
            if (circles[animateEndCount]) {
                circles[animateEndCount].setReady();
            }
        };

        canvases.forEach(function (canvas) {
            circles.push(new Circle(canvas, onEnd));
        });

        circles[0].setReady();

    };


</script>

</body>
</html>

Последний раз редактировалось tsigel, 03.12.2015 в 09:56.
Ответить с цитированием