Файл: tyde/www/web/js/components/parallax.js
Строк: 367
<?php
/*! UIkit 2.24.3 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */
(function(addon) {
    var component;
    if (window.UIkit) {
        component = addon(UIkit);
    }
    if (typeof define == "function" && define.amd) {
        define("uikit-parallax", ["uikit"], function(){
            return component || addon(UIkit);
        });
    }
})(function(UI){
    "use strict";
    var parallaxes      = [],
        supports3d      = false,
        scrolltop       = 0,
        wh              = window.innerHeight,
        checkParallaxes = function() {
            scrolltop = UI.$win.scrollTop();
            window.requestAnimationFrame(function(){
                for (var i=0; i < parallaxes.length; i++) {
                    parallaxes[i].process();
                }
            });
        };
    UI.component('parallax', {
        defaults: {
            velocity : 0.5,
            target   : false,
            viewport : false,
            media    : false
        },
        boot: function() {
            supports3d = (function(){
                var el = document.createElement('div'),
                    has3d,
                    transforms = {
                        'WebkitTransform':'-webkit-transform',
                        'MSTransform':'-ms-transform',
                        'MozTransform':'-moz-transform',
                        'Transform':'transform'
                    };
                // Add it to the body to get the computed style.
                document.body.insertBefore(el, null);
                for (var t in transforms) {
                    if (el.style[t] !== undefined) {
                        el.style[t] = "translate3d(1px,1px,1px)";
                        has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
                    }
                }
                document.body.removeChild(el);
                return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
            })();
            // listen to scroll and resize
            UI.$doc.on("scrolling.uk.document", checkParallaxes);
            UI.$win.on("load resize orientationchange", UI.Utils.debounce(function(){
                wh = window.innerHeight;
                checkParallaxes();
            }, 50));
            // init code
            UI.ready(function(context) {
                UI.$('[data-uk-parallax]', context).each(function() {
                    var parallax = UI.$(this);
                    if (!parallax.data("parallax")) {
                        UI.parallax(parallax, UI.Utils.options(parallax.attr("data-uk-parallax")));
                    }
                });
            });
        },
        init: function() {
            this.base     = this.options.target ? UI.$(this.options.target) : this.element;
            this.props    = {};
            this.velocity = (this.options.velocity || 1);
            var reserved  = ['target','velocity','viewport','plugins','media'];
            Object.keys(this.options).forEach(function(prop){
                if (reserved.indexOf(prop) !== -1) {
                    return;
                }
                var start, end, dir, diff, startend = String(this.options[prop]).split(',');
                if (prop.match(/color/i)) {
                    start = startend[1] ? startend[0] : this._getStartValue(prop),
                    end   = startend[1] ? startend[1] : startend[0];
                    if (!start) {
                        start = 'rgba(255,255,255,0)';
                    }
                } else {
                    start = parseFloat(startend[1] ? startend[0] : this._getStartValue(prop)),
                    end   = parseFloat(startend[1] ? startend[1] : startend[0]);
                    diff  = (start < end ? (end-start):(start-end));
                    dir   = (start < end ? 1:-1);
                }
                this.props[prop] = { 'start': start, 'end': end, 'dir': dir, 'diff': diff };
            }.bind(this));
            parallaxes.push(this);
        },
        process: function() {
            if (this.options.media) {
                switch(typeof(this.options.media)) {
                    case 'number':
                        if (window.innerWidth < this.options.media) {
                            return false;
                        }
                        break;
                    case 'string':
                        if (window.matchMedia && !window.matchMedia(this.options.media).matches) {
                            return false;
                        }
                        break;
                }
            }
            var percent = this.percentageInViewport();
            if (this.options.viewport !== false) {
                percent = (this.options.viewport === 0) ? 1 : percent / this.options.viewport;
            }
            this.update(percent);
        },
        percentageInViewport: function() {
            var top     = this.base.offset().top,
                height  = this.base.outerHeight(),
                distance, percentage, percent;
            if (top > (scrolltop + wh)) {
                percent = 0;
            } else if ((top + height) < scrolltop) {
                percent = 1;
            } else {
                if ((top + height) < wh) {
                    percent = (scrolltop < wh ? scrolltop : scrolltop - wh) / (top+height);
                } else {
                    distance   = (scrolltop + wh) - top;
                    percentage = Math.round(distance / ((wh + height) / 100));
                    percent    = percentage/100;
                }
            }
            return percent;
        },
        update: function(percent) {
            var $this      = this,
                css        = {'transform':''},
                compercent = percent * (1 - (this.velocity - (this.velocity * percent))),
                opts, val;
            if (compercent < 0) compercent = 0;
            if (compercent > 1) compercent = 1;
            if (this._percent !== undefined && this._percent == compercent) {
                return;
            }
            Object.keys(this.props).forEach(function(prop) {
                opts = this.props[prop];
                if (percent === 0) {
                    val = opts.start;
                } else if(percent === 1) {
                    val = opts.end;
                } else if(opts.diff !== undefined) {
                    val = opts.start + (opts.diff * compercent * opts.dir);
                }
                if ((prop == 'bg' || prop == 'bgp') && !this._bgcover) {
                    this._bgcover = initBgImageParallax(this, prop, opts);
                }
                switch(prop) {
                    // transforms
                    case "x":
                        css.transform += supports3d ? ' translate3d('+val+'px, 0, 0)':' translateX('+val+'px)';
                        break;
                    case "xp":
                        css.transform += supports3d ? ' translate3d('+val+'%, 0, 0)':' translateX('+val+'%)';
                        break;
                    case "y":
                        css.transform += supports3d ? ' translate3d(0, '+val+'px, 0)':' translateY('+val+'px)';
                        break;
                    case "yp":
                        css.transform += supports3d ? ' translate3d(0, '+val+'%, 0)':' translateY('+val+'%)';
                        break;
                    case "rotate":
                        css.transform += ' rotate('+val+'deg)';
                        break;
                    case "scale":
                        css.transform += ' scale('+val+')';
                        break;
                    // bg image
                    case "bg":
                        // don't move if image height is too small
                        // if ($this.element.data('bgsize') && ($this.element.data('bgsize').h + val - window.innerHeight) < 0) {
                        //     break;
                        // }
                        css['background-position'] = '50% '+val+'px';
                        break;
                    case "bgp":
                        css['background-position'] = '50% '+val+'%';
                        break;
                    // color
                    case "color":
                    case "background-color":
                    case "border-color":
                        css[prop] = calcColor(opts.start, opts.end, compercent);
                        break;
                    default:
                        css[prop] = val;
                        break;
                }
            }.bind(this));
            this.element.css(css);
            this._percent = compercent;
        },
        _getStartValue: function(prop) {
            var value = 0;
            switch(prop) {
                case 'scale':
                    value = 1;
                    break;
                default:
                    value = this.element.css(prop);
            }
            return (value || 0);
        }
    });
    // helper
    function initBgImageParallax(obj, prop, opts) {
        var img = new Image(), url, element, size, check, ratio, width, height;
        element = obj.element.css({'background-size': 'cover',  'background-repeat': 'no-repeat'});
        url     = element.css('background-image').replace(/^url(/g, '').replace(/)$/g, '').replace(/("|')/g, '');
        check   = function() {
            var w = element.width(), h = element.height(), extra = (prop=='bg') ? opts.diff : (opts.diff/100) * h;
            h += extra;
            w += Math.ceil(extra * ratio);
            if (w-extra > size.w && h < size.h) {
                return obj.element.css({'background-size': ''});
            }
            // if element height < parent height (gap underneath)
            if ((w / ratio) < h) {
                width  = Math.ceil(h * ratio);
                height = h;
                if (h > window.innerHeight) {
                    width  = width * 1.2;
                    height = height * 1.2;
                }
            // element width < parent width (gap to right)
            } else {
                width  = w;
                height = Math.ceil(w / ratio);
            }
            element.css({'background-size': (width+'px '+height+'px')}).data('bgsize', {w:width,h:height});
        };
        img.onerror = function(){
            // image url doesn't exist
        };
        img.onload = function(){
            size  = {w:img.width, h:img.height};
            ratio = img.width / img.height;
            UI.$win.on("load resize orientationchange", UI.Utils.debounce(function(){
                check();
            }, 50));
            check();
        };
        img.src = url;
        return true;
    }
    // Some named colors to work with, added by Bradley Ayers
    // From Interface by Stefan Petre
    // http://interface.eyecon.ro/
    var colors = {
        'black': [0,0,0,1],
        'blue': [0,0,255,1],
        'brown': [165,42,42,1],
        'cyan': [0,255,255,1],
        'fuchsia': [255,0,255,1],
        'gold': [255,215,0,1],
        'green': [0,128,0,1],
        'indigo': [75,0,130,1],
        'khaki': [240,230,140,1],
        'lime': [0,255,0,1],
        'magenta': [255,0,255,1],
        'maroon': [128,0,0,1],
        'navy': [0,0,128,1],
        'olive': [128,128,0,1],
        'orange': [255,165,0,1],
        'pink': [255,192,203,1],
        'purple': [128,0,128,1],
        'violet': [128,0,128,1],
        'red': [255,0,0,1],
        'silver': [192,192,192,1],
        'white': [255,255,255,1],
        'yellow': [255,255,0,1],
        'transparent': [255,255,255,0]
    };
    function calcColor(start, end, pos) {
        start = parseColor(start);
        end   = parseColor(end);
        pos   = pos || 0;
        return calculateColor(start, end, pos);
    }
    /**!
     * @preserve Color animation 1.6.0
     * http://www.bitstorm.org/jquery/color-animation/
     * Copyright 2011, 2013 Edwin Martin <edwin@bitstorm.org>
     * Released under the MIT and GPL licenses.
     */
    // Calculate an in-between color. Returns "#aabbcc"-like string.
    function calculateColor(begin, end, pos) {
        var color = 'rgba('
                + parseInt((begin[0] + pos * (end[0] - begin[0])), 10) + ','
                + parseInt((begin[1] + pos * (end[1] - begin[1])), 10) + ','
                + parseInt((begin[2] + pos * (end[2] - begin[2])), 10) + ','
                + (begin && end ? parseFloat(begin[3] + pos * (end[3] - begin[3])) : 1);
        color += ')';
        return color;
    }
    // Parse an CSS-syntax color. Outputs an array [r, g, b]
    function parseColor(color) {
        var match, quadruplet;
        // Match #aabbcc
        if (match = /#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/.exec(color)) {
            quadruplet = [parseInt(match[1], 16), parseInt(match[2], 16), parseInt(match[3], 16), 1];
            // Match #abc
        } else if (match = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/.exec(color)) {
            quadruplet = [parseInt(match[1], 16) * 17, parseInt(match[2], 16) * 17, parseInt(match[3], 16) * 17, 1];
            // Match rgb(n, n, n)
        } else if (match = /rgb(s*([0-9]{1,3})s*,s*([0-9]{1,3})s*,s*([0-9]{1,3})s*)/.exec(color)) {
            quadruplet = [parseInt(match[1]), parseInt(match[2]), parseInt(match[3]), 1];
        } else if (match = /rgba(s*([0-9]{1,3})s*,s*([0-9]{1,3})s*,s*([0-9]{1,3})s*,s*([0-9.]*)s*)/.exec(color)) {
            quadruplet = [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10),parseFloat(match[4])];
            // No browser returns rgb(n%, n%, n%), so little reason to support this format.
        } else {
            quadruplet = colors[color] || [255,255,255,0];
        }
        return quadruplet;
    }
    return UI.parallax;
});
?>