diff options
| author | stefanorigano <sri@odoo.com> | 2016-11-03 13:21:44 +0100 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2016-11-22 17:15:33 +0100 |
| commit | d6cf236b4bb84d4e7e86dd412d71efcdfcb35263 (patch) | |
| tree | 38b1207d15971e03ae20b761fc78ed74bb15b612 /addons/website/static | |
| parent | 0e08e653cd47e6ef00cf041d774ddec4b83431c1 (diff) | |
[REF] website: refactor parallax snippet
This commit is a refactoring of the 's_parallax' snippet. Note that it
is compatible with previous parallax snippet (old snippets are just
transformed into the brand new one on page load). Note that scroll
speed are changed by this implementation though.
This solves several issues:
- Bg image went easily off of the frame if scroll speed was too fast
- The 'scroll speed' effect was visually inconsistent across different
devices.
- If the Bg image was smaller than the frame (condition which occurs
often in a responsive environment), then the image was totally
offset.
- Since the previous implementation use background-position property
to perform the effect, It was not possible to define an image
focus point.
This implementation solves the previous issues introducing a safe-area
that limit the effect range. It's calculated dynamically, according to
the current screen size and the 'speed' option.
The effect if now achieved thanks to the translation of a DOM element
instead of background-position changes. This allows to solve the last
mentionned problem and improve performance.
The implementation rely on the new animation methods of the snippets
Animation class.
As this use the "requestAnimationFrame" function, the snippet knows
the right time to repaint itself, instead of using the "scroll" event
which is triggered too many times and thus occurs between painting
frames. This change greatly improved performances (CPU/painting usage
many times smaller).
Diffstat (limited to 'addons/website/static')
3 files changed, 94 insertions, 49 deletions
diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js index 6a8a0257627..e4dd19e03db 100644 --- a/addons/website/static/src/js/website.snippets.animation.js +++ b/addons/website/static/src/js/website.snippets.animation.js @@ -314,52 +314,71 @@ animation.registry.slider = animation.Class.extend({ animation.registry.parallax = animation.Class.extend({ selector: ".parallax", - start: function () { - _.defer((function () { this.set_values(); }).bind(this)); - $(window).on("scroll.animation_parallax", _.throttle(this.on_scroll.bind(this), 10)) - .on("resize.animation_parallax", _.debounce(this.set_values.bind(this), 500)); - - return this._super.apply(this, arguments); + this._super.apply(this, arguments); + this._rebuild(); + $(window).on("resize.animation_parallax", _.debounce(this._rebuild.bind(this), 500)); }, stop: function () { + this._super.apply(this, arguments); $(window).off(".animation_parallax"); }, - - set_values: function () { - var self = this; - this.speed = parseFloat(self.$target.attr("data-scroll-background-ratio") || 0); - this.offset = 0; - - if (this.speed === 1 || this.$target.css("background-image") === "none") { - this.$target.css("background-attachment", "fixed").css("background-position", "0px 0px"); + _rebuild: function () { + // Add/find bg DOM element to hold the parallax bg (support old v10.0 parallax) + if (!this.$bg || !this.$bg.length) { + this.$bg = this.$("> .s_parallax_bg"); + if (!this.$bg.length) { + this.$bg = $("<span/>", {"class": "s_parallax_bg"}).prependTo(this.$target); + } + } + var urlTarget = this.$target.css("background-image"); + if (urlTarget !== "none") { + this.$bg.css("background-image", urlTarget); + } + this.$target.css("background-image", "none"); + + // Get parallax speed + this.speed = parseFloat(this.$target.attr("data-scroll-background-ratio") || 0); + + // Reset offset if parallax effect will not be performed and leave + this.$target.toggleClass("s_parallax_is_fixed", this.speed === 1); + if (this.speed === 0 || this.speed === 1) { + this.$bg.css({ + transform: "", + top: "", + bottom: "" + }); return; } - this.$target.css("background-attachment", "scroll"); - - var img = new Image(); - img.onload = function () { - var offset = 0; - var padding = parseInt($(document.body).css("padding-top")); - if (self.speed > 1) { - var inner_offset = - self.$target.outerHeight() + this.height / this.width * document.body.clientWidth; - var outer_offset = self.$target.offset().top - (document.body.clientHeight - self.$target.outerHeight()) - padding; - offset = - outer_offset * self.speed + inner_offset; - } else { - offset = - self.$target.offset().top * self.speed; - } - self.offset = offset > 0 ? 0 : offset; - self.on_scroll(); - }; - img.src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)/g, ""); - }, + // Initialize parallax data according to snippet and viewport dimensions + this.viewport = document.body.clientHeight - $('#wrapwrap').position().top; + this.visible_area = [this.$target.offset().top]; + this.visible_area.push(this.visible_area[0] + this.$target.innerHeight() + this.viewport); + this.ratio = this.speed * (this.viewport / 10); - on_scroll: function () { - if (this.speed === 1) return; - var top = this.offset + window.scrollY * this.speed; - this.$target.css("background-position", "0px " + top + "px"); + // Provide a "safe-area" to limit parallax + this.$bg.css({ + top: -this.ratio, + bottom: -this.ratio + }); }, + on_scroll: function (scrollOffset) { + if (this.speed === 0 || this.speed === 1) return; + + // Perform translate if the element is visible only + var vpEndOffset = scrollOffset + this.viewport; + if (vpEndOffset >= this.visible_area[0] && vpEndOffset <= this.visible_area[1]) { + this.$bg.css("transform", "translateY(" + _getNormalizedPosition.call(this, vpEndOffset) + "px)"); + } + + function _getNormalizedPosition(pos) { + // Normalize scroll in a 1 to 0 range + var r = (pos - this.visible_area[1]) / (this.visible_area[0] - this.visible_area[1]); + // Normalize accordingly to current options + return Math.round(this.ratio * (2 * r - 1)); + } + } }); animation.registry.share = animation.Class.extend({ diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index 4fbb79dd89e..94bb408b9ac 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -299,34 +299,34 @@ options.registry.parallax = options.Class.extend({ this.grid.size = 8; return this.grid; }, - on_resize: function () { - this._refresh(); - }, - _refresh: function () { - this.$target.data("snippet-view").set_values(); - }, start: function () { this._super.apply(this, arguments); if (!this.$target.data("snippet-view")) { this.$target.data("snippet-view", new animation.registry.parallax(this.$target)); } - this.scroll(); - this._refresh_callback = this._refresh.bind(this); - this.buildingBlock.$el.on("snippet-dropped snippet-activated", this._refresh_callback); - this.$target.on('snippet-option-change snippet-option-preview', this._refresh_callback); + this._toggle_refresh_callback(true); + }, + on_focus: function () { + this._super.apply(this, arguments); + this._update_target_to_bg(); + }, + on_resize: function () { + this._super.apply(this, arguments); + this._refresh(); }, scroll: function (type, value) { this.$target.attr("data-scroll-background-ratio", value); this._refresh(); }, set_active: function () { + this._super.apply(this, arguments); this.$el.find('[data-scroll]').removeClass("active") .filter('[data-scroll="' + (this.$target.attr('data-scroll-background-ratio') || 0) + '"]').addClass("active"); }, clean_for_save: function () { this._super.apply(this, arguments); - this.$target.css("background-position", '').css("background-attachment", ''); + this._toggle_refresh_callback(false); }, on_move: function () { this._super.apply(this, arguments); @@ -334,8 +334,23 @@ options.registry.parallax = options.Class.extend({ }, on_remove: function () { this._super.apply(this, arguments); - this.$target.off("snippet-option-change snippet-option-preview", this._refresh_callback); - this.buildingBlock.$el.off("snippet-dropped snippet-activated", this._refresh_callback); + this._toggle_refresh_callback(false); + }, + _update_target_to_bg: function () { + this.editor.styles.background.$target = this.$target.data("snippet-view").$bg; + this.editor.styles.background.set_active(); + this.editor.styles.background_position.$target = this.$target.data("snippet-view").$bg; + this.editor.styles.background_position.set_active(); + }, + _refresh: function () { + _.defer((function () { + this.$target.data("snippet-view")._rebuild(); + this._update_target_to_bg(); + }).bind(this)); + }, + _toggle_refresh_callback: function (on) { + this.$target[on ? "on" : "off"]("snippet-option-change snippet-option-preview", this._refresh_callback); + this.buildingBlock.$el[on ? "on" : "off"]("snippet-dropped snippet-activated", this._refresh_callback); }, }); diff --git a/addons/website/static/src/less/website.snippets.less b/addons/website/static/src/less/website.snippets.less index 7b941acda2f..1a290e65767 100644 --- a/addons/website/static/src/less/website.snippets.less +++ b/addons/website/static/src/less/website.snippets.less @@ -402,6 +402,17 @@ div.carousel { margin-bottom: 32px; } } + + > .s_parallax_bg { + .o-position-absolute(0, 0, 0, 0); + background-size: cover; + background-attachment: scroll; + pointer-events: none; + z-index: -1; + } + &.s_parallax_is_fixed > .s_parallax_bg { + background-attachment: fixed; + } } .s_parallax { |
