Skip to content

Commit

Permalink
Internal refactoring of animations and translate value caching.
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasramo committed Jun 3, 2020
1 parent 00a74f2 commit bd3d1e3
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 388 deletions.
281 changes: 151 additions & 130 deletions dist/muuri.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/muuri.min.js

Large diffs are not rendered by default.

281 changes: 151 additions & 130 deletions dist/muuri.module.js

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions src/Animator/Animator.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,22 +145,22 @@ Animator.prototype.start = function (propsFrom, propsTo, options) {
* Stop instance's current animation if running.
*
* @public
* @param {Boolean} [applyCurrentStyles=true]
*/
Animator.prototype.stop = function (applyCurrentStyles) {
Animator.prototype.stop = function () {
if (this._isDestroyed || !this._animation) return;

var element = this._element;
var currentProps = this._props;
var currentValues = this._values;

if (applyCurrentStyles !== false) {
setStyles(element, getCurrentStyles(element, currentProps));
}

this._animation.cancel();
this._animation = this._callback = null;
currentProps.length = currentValues.length = 0;
this._props.length = this._values.length = 0;
};

/**
* Read the current values of the element's animated styles from the DOM.
*
* @public
* @return {Object}
*/
Animator.prototype.getCurrentStyles = function () {
return getCurrentStyles(element, currentProps);
};

/**
Expand Down
4 changes: 1 addition & 3 deletions src/AutoScroller/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
*/

import getStyleAsFloat from '../utils/getStyleAsFloat';
import getTranslateString from '../utils/getTranslateString';
import transformProp from '../utils/transformProp';

var DOC_ELEM = document.documentElement;
var BODY = document.body;
Expand Down Expand Up @@ -121,7 +119,7 @@ export function applyItemScrollSync(item) {
if (!item._drag || !item._isActive) return;
var drag = item._drag;
drag._scrollDiffX = drag._scrollDiffY = 0;
item._element.style[transformProp] = getTranslateString(drag._left, drag._top);
item._setTranslate(drag._left, drag._top);
}

/**
Expand Down
18 changes: 5 additions & 13 deletions src/Grid/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -1374,26 +1374,18 @@ Grid.prototype._onLayoutDataReceived = (function () {
left = layout.slots[i * 2];
top = layout.slots[i * 2 + 1];

// If the left and top values have not changed since the last layout and
// if some other conditions are met, we can skip the item's layout process
// and save some CPU time.
// TODO: Might make more sense to have a single item._layout.isDirty flag
// for example which we would set to true whenever this optimization can
// not be used for the next layout.
if (
left === item._left &&
top === item._top &&
!item._migrate._isActive &&
!item._layout._skipNextAnimation &&
!item._dragRelease.isJustReleased()
) {
// Let's skip the layout process if we can. Possibly avoids a lot of DOM
// operations which saves us some CPU cycles.
if (item._canSkipLayout(left, top)) {
--counter;
continue;
}

// Update the item's position.
item._left = left;
item._top = top;

// Only active non-dragged items need to be moved.
if (item.isActive() && !item.isDragging()) {
itemsToLayout.push(item);
}
Expand Down
42 changes: 42 additions & 0 deletions src/Item/Item.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import addClass from '../utils/addClass';
import createUid from '../utils/createUid';
import getStyle from '../utils/getStyle';
import getStyleAsFloat from '../utils/getStyleAsFloat';
import getTranslateString from '../utils/getTranslateString';
import removeClass from '../utils/removeClass';
import transformProp from '../utils/transformProp';

/**
* Creates a new Item instance for a Grid instance.
Expand Down Expand Up @@ -52,6 +54,8 @@ function Item(grid, element, isActive) {
this._marginRight = 0;
this._marginTop = 0;
this._marginBottom = 0;
this._tX = undefined;
this._tY = undefined;
this._sortData = null;
this._emitter = new Emitter();

Expand Down Expand Up @@ -337,6 +341,44 @@ Item.prototype._removeFromLayout = function () {
this._top = 0;
};

/**
* Check if the layout procedure can be skipped for the item.
*
* @private
* @param {Number} left
* @param {Number} top
* @returns {Boolean}
*/
Item.prototype._canSkipLayout = function (left, top) {
return (
this._left === left &&
this._top === top &&
!this._migrate._isActive &&
!this._layout._skipNextAnimation &&
!this._dragRelease.isJustReleased()
);
};

/**
* Set the provided left and top arguments as the item element's translate
* values in the DOM. This method keeps track of the currently applied
* translate values and skips the update operation if the provided values are
* identical to the currently applied values. Returns `false` if there was no
* need for update and `true` if the translate value was updated.
*
* @private
* @param {Number} left
* @param {Number} top
* @returns {Boolean}
*/
Item.prototype._setTranslate = function (left, top) {
if (this._tX === left && this._tY === top) return false;
this._tX = left;
this._tY = top;
this._element.style[transformProp] = getTranslateString(left, top);
return true;
};

/**
* Destroy item instance.
*
Expand Down
19 changes: 6 additions & 13 deletions src/Item/ItemDrag.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,10 @@ import getOffsetDiff from '../utils/getOffsetDiff';
import getScrollableAncestors from '../utils/getScrollableAncestors';
import getStyle from '../utils/getStyle';
import getTranslate from '../utils/getTranslate';
import getTranslateString from '../utils/getTranslateString';
import hasPassiveEvents from '../utils/hasPassiveEvents';
import isFunction from '../utils/isFunction';
import normalizeArrayIndex from '../utils/normalizeArrayIndex';
import removeClass from '../utils/removeClass';
import transformProp from '../utils/transformProp';

var START_PREDICATE_INACTIVE = 0;
var START_PREDICATE_PENDING = 1;
Expand Down Expand Up @@ -486,7 +484,7 @@ ItemDrag.prototype.stop = function () {
// sure the translate values are adjusted to account for the DOM shift.
if (element.parentNode !== grid._element) {
grid._element.appendChild(element);
element.style[transformProp] = getTranslateString(this._gridX, this._gridY);
item._setTranslate(this._gridX, this._gridY);

// We need to do forced reflow to make sure the dragging class is removed
// gracefully.
Expand Down Expand Up @@ -1096,7 +1094,7 @@ ItemDrag.prototype._finishMigration = function () {
// Adjust the position of the item element if it was moved from a container
// to another.
if (targetContainer !== currentContainer) {
element.style[transformProp] = getTranslateString(translate.x, translate.y);
item._setTranslate(translate.x, translate.y);
}

// Update child element's styles to reflect the current visibility state.
Expand Down Expand Up @@ -1235,9 +1233,7 @@ ItemDrag.prototype._applyStart = function () {
var hasDragContainer = this._container !== grid._element;

if (item.isPositioning()) {
var layoutStyles = {};
layoutStyles[transformProp] = getTranslateString(this._left, this._top);
item._layout.stop(true, layoutStyles);
item._layout.stop(true, this._left, this._top);
}

if (migrate._isActive) {
Expand Down Expand Up @@ -1274,7 +1270,7 @@ ItemDrag.prototype._applyStart = function () {
this._left += this._containerDiffX;
this._top += this._containerDiffY;
this._container.appendChild(element);
element.style[transformProp] = getTranslateString(this._left, this._top);
item._setTranslate(this._left, this._top);
}
}

Expand Down Expand Up @@ -1348,7 +1344,7 @@ ItemDrag.prototype._applyMove = function () {
if (!item._isActive) return;

this._moveDiffX = this._moveDiffY = 0;
item._element.style[transformProp] = getTranslateString(this._left, this._top);
item._setTranslate(this._left, this._top);
this._getGrid()._emit(EVENT_DRAG_MOVE, item, this._dragMoveEvent);
ItemDrag.autoScroller.updateItem(item);
};
Expand Down Expand Up @@ -1427,10 +1423,7 @@ ItemDrag.prototype._applyScroll = function () {
if (!item._isActive) return;

this._scrollDiffX = this._scrollDiffY = 0;
// TODO: Maybe we should have a method for writing the translate value which
// could compare the provided values to current values and ignore the DOM
// write if it's the same value.
item._element.style[transformProp] = getTranslateString(this._left, this._top);
item._setTranslate(this._left, this._top);
this._getGrid()._emit(EVENT_DRAG_SCROLL, item, this._scrollEvent);
};

Expand Down
23 changes: 11 additions & 12 deletions src/Item/ItemDragPlaceholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,8 @@ ItemDragPlaceholder.prototype._onLayoutStart = function (items, isInstant) {
cancelPlaceholderLayoutTick(item._id);

// Snap placeholder to correct position.
var targetStyles = {};
targetStyles[transformProp] = getTranslateString(nextX, nextY);
setStyles(this._element, targetStyles);
this._animation.stop(false);
this._element.style[transformProp] = getTranslateString(nextX, nextY);
this._animation.stop();

// Move placeholder inside correct container after migration.
if (this._didMigrate) {
Expand Down Expand Up @@ -172,24 +170,23 @@ ItemDragPlaceholder.prototype._startAnimation = function () {
var currentY = this._transY;
var nextX = this._nextTransX;
var nextY = this._nextTransY;
var targetStyles = {};

targetStyles[transformProp] = getTranslateString(nextX, nextY);

// If placeholder is already in correct position let's just stop animation
// and be done with it.
if (currentX === nextX && currentY === nextY) {
if (animation.isAnimating()) {
setStyles(this._element, targetStyles);
animation.stop(false);
this._element.style[transformProp] = getTranslateString(nextX, nextY);
animation.stop();
}
return;
}

// Otherwise let's start the animation.
var settings = this._item.getGrid()._settings;
var currentStyles = {};
var targetStyles = {};
currentStyles[transformProp] = getTranslateString(currentX, currentY);
targetStyles[transformProp] = getTranslateString(nextX, nextY);
animation.start(currentStyles, targetStyles, {
duration: settings.layoutDuration,
easing: settings.layoutEasing,
Expand Down Expand Up @@ -330,9 +327,10 @@ ItemDragPlaceholder.prototype.create = function () {
});

// Set initial position.
var left = item._left + item._marginLeft;
var top = item._top + item._marginTop;
element.style[transformProp] = getTranslateString(left, top);
element.style[transformProp] = getTranslateString(
item._left + item._marginLeft,
item._top + item._marginTop
);

// Bind event listeners.
grid.on(EVENT_LAYOUT_START, this._onLayoutStart);
Expand Down Expand Up @@ -371,6 +369,7 @@ ItemDragPlaceholder.prototype.reset = function () {
cancelPlaceholderResizeTick(item._id);

// Reset animation instance.
// TODO: Here we need to apply current styles.
animation.stop();
animation._element = null;

Expand Down
4 changes: 1 addition & 3 deletions src/Item/ItemDragRelease.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import { EVENT_DRAG_RELEASE_START, EVENT_DRAG_RELEASE_END } from '../constants';

import addClass from '../utils/addClass';
import getTranslate from '../utils/getTranslate';
import getTranslateString from '../utils/getTranslateString';
import removeClass from '../utils/removeClass';
import transformProp from '../utils/transformProp';

/**
* The release process handler constructor. Although this might seem as proper
Expand Down Expand Up @@ -139,7 +137,7 @@ ItemDragRelease.prototype._placeToGrid = function (left, top) {
}

container.appendChild(element);
element.style[transformProp] = getTranslateString(left, top);
item._setTranslate(left, top);
didReparent = true;
}

Expand Down
Loading

0 comments on commit bd3d1e3

Please sign in to comment.