transform.js

// Copyright 2014 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Utility methods to deal with CSS3 transforms programmatically.
 */

goog.provide('goog.style.transform');

goog.require('goog.functions');
goog.require('goog.math.Coordinate');
goog.require('goog.style');
goog.require('goog.userAgent');
goog.require('goog.userAgent.product.isVersion');


/**
 * Whether CSS3 transform translate() is supported. IE 9 supports 2D transforms
 * and IE 10 supports 3D transforms. IE 8 supports neither.
 * @return {boolean} Whether the current environment supports CSS3 transforms.
 */
goog.style.transform.isSupported = goog.functions.cacheReturnValue(function() {
  return !goog.userAgent.IE || goog.userAgent.product.isVersion(9);
});


/**
 * Whether CSS3 transform translate3d() is supported. If the current browser
 * supports this transform strategy.
 * @return {boolean} Whether the current environment supports CSS3 transforms.
 */
goog.style.transform.is3dSupported =
    goog.functions.cacheReturnValue(function() {
  return goog.userAgent.WEBKIT ||
      (goog.userAgent.GECKO && goog.userAgent.product.isVersion(10)) ||
      (goog.userAgent.IE && goog.userAgent.product.isVersion(10));
});


/**
 * Returns the x,y translation component of any CSS transforms applied to the
 * element, in pixels.
 *
 * @param {!Element} element The element to get the translation of.
 * @return {!goog.math.Coordinate} The CSS translation of the element in px.
 */
goog.style.transform.getTranslation = function(element) {
  var transform = goog.style.getComputedTransform(element);
  var matrixConstructor = goog.style.transform.matrixConstructor_();
  if (transform && matrixConstructor) {
    var matrix = new matrixConstructor(transform);
    if (matrix) {
      return new goog.math.Coordinate(matrix.m41, matrix.m42);
    }
  }
  return new goog.math.Coordinate(0, 0);
};


/**
 * Translates an element's position using the CSS3 transform property.
 * @param {Element} element The element to translate.
 * @param {number} x The horizontal translation.
 * @param {number} y The vertical translation.
 * @return {boolean} Whether the CSS translation was set.
 */
goog.style.transform.setTranslation = function(element, x, y) {
  if (!goog.style.transform.isSupported()) {
    return false;
  }
  // TODO(user): After http://crbug.com/324107 is fixed, it will be faster to
  // use something like: translation = new CSSMatrix().translate(x, y, 0);
  var translation = goog.style.transform.is3dSupported() ?
      'translate3d(' + x + 'px,' + y + 'px,' + '0px)' :
      'translate(' + x + 'px,' + y + 'px)';
  goog.style.setStyle(element, 'transform', translation);
  return true;
};


/**
 * Gets the constructor for a CSSMatrix object.
 * @return {function(new:CSSMatrix, string)?} A constructor for a CSSMatrix
 *     object (or null).
 * @private
 */
goog.style.transform.matrixConstructor_ =
    goog.functions.cacheReturnValue(function() {
  // TODO(user): Unless these are accessed from the default namespace the
  // compiler will rename them. A better way is to use goog.global and prevent
  // renaming.
  if (typeof WebKitCSSMatrix !== undefined) {
    return WebKitCSSMatrix;
  }
  if (typeof MSCSSMatrix !== undefined) {
    return MSCSSMatrix;
  }
  if (typeof CSSMatrix !== undefined) {
    return CSSMatrix;
  }
  return null;
});