Bug 1406285 - Part 13: Implement tooltip. r?gl draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 18 Jan 2018 13:03:57 +0900
changeset 721942 d8b85be2d288dec1742d2c7132d3a718ac28938c
parent 721941 e228f84e1e7034485b54910d036e21aaabcb22f2
child 721943 cbd8a13f94144b46deda8a7b8d16854e88ddec25
push id96003
push userbmo:dakatsuka@mozilla.com
push dateThu, 18 Jan 2018 05:23:36 +0000
reviewersgl
bugs1406285
milestone59.0a1
Bug 1406285 - Part 13: Implement tooltip. r?gl MozReview-Commit-ID: 3Icr9lJUQhl
devtools/client/inspector/animation/components/graph/SummaryGraph.js
devtools/client/inspector/animation/utils/l10n.js
--- a/devtools/client/inspector/animation/components/graph/SummaryGraph.js
+++ b/devtools/client/inspector/animation/components/graph/SummaryGraph.js
@@ -8,35 +8,134 @@ const { createFactory, PureComponent } =
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const AnimationName = createFactory(require("./AnimationName"));
 const DelaySign = createFactory(require("./DelaySign"));
 const EndDelaySign = createFactory(require("./EndDelaySign"));
 const SummaryGraphPath = createFactory(require("./SummaryGraphPath"));
 
+const { getFormatStr, getStr, numberWithDecimals } = require("../../utils/l10n");
+
 class SummaryGraph extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
+  getTitleText(state) {
+    const getTime =
+      time => getFormatStr("player.timeLabel", numberWithDecimals(time / 1000, 2));
+
+    let text = "";
+
+    // Adding the name.
+    text += getFormattedTitle(state);
+    text += "\n";
+
+    // Adding the delay.
+    if (state.delay) {
+      text += getStr("player.animationDelayLabel") + " ";
+      text += getTime(state.delay);
+      text += "\n";
+    }
+
+    // Adding the duration.
+    text += getStr("player.animationDurationLabel") + " ";
+    text += getTime(state.duration);
+    text += "\n";
+
+    // Adding the endDelay.
+    if (state.endDelay) {
+      text += getStr("player.animationEndDelayLabel") + " ";
+      text += getTime(state.endDelay);
+      text += "\n";
+    }
+
+    // Adding the iteration count (the infinite symbol, or an integer).
+    if (state.iterationCount !== 1) {
+      text += getStr("player.animationIterationCountLabel") + " ";
+      text += state.iterationCount || getStr("player.infiniteIterationCountText");
+      text += "\n";
+    }
+
+    // Adding the iteration start.
+    if (state.iterationStart !== 0) {
+      const iterationStartTime = state.iterationStart * state.duration / 1000;
+      text += getFormatStr("player.animationIterationStartLabel",
+                           state.iterationStart,
+                           numberWithDecimals(iterationStartTime, 2));
+      text += "\n";
+    }
+
+    // Adding the easing if it is not "linear".
+    if (state.easing && state.easing !== "linear") {
+      text += getStr("player.animationOverallEasingLabel") + " ";
+      text += state.easing;
+      text += "\n";
+    }
+
+    // Adding the fill mode.
+    if (state.fill && state.fill !== "none") {
+      text += getStr("player.animationFillLabel") + " ";
+      text += state.fill;
+      text += "\n";
+    }
+
+    // Adding the direction mode if it is not "normal".
+    if (state.direction && state.direction !== "normal") {
+      text += getStr("player.animationDirectionLabel") + " ";
+      text += state.direction;
+      text += "\n";
+    }
+
+    // Adding the playback rate if it's different than 1.
+    if (state.playbackRate !== 1) {
+      text += getStr("player.animationRateLabel") + " ";
+      text += state.playbackRate;
+      text += "\n";
+    }
+
+    // Adding the animation-timing-function
+    // if it is not "ease" which is default value for CSS Animations.
+    if (state.animationTimingFunction && state.animationTimingFunction !== "ease") {
+      text += getStr("player.animationTimingFunctionLabel") + " ";
+      text += state.animationTimingFunction;
+      text += "\n";
+    }
+
+    // Adding a note that the animation is running on the compositor thread if
+    // needed.
+    if (state.propertyState) {
+      if (state.propertyState.every(propState => propState.runningOnCompositor)) {
+        text += getStr("player.allPropertiesOnCompositorTooltip");
+      } else if (state.propertyState.some(propState => propState.runningOnCompositor)) {
+        text += getStr("player.somePropertiesOnCompositorTooltip");
+      }
+    } else if (state.isRunningOnCompositor) {
+      text += getStr("player.runningOnCompositorTooltip");
+    }
+
+    return text;
+  }
+
   render() {
     const {
       animation,
       simulateAnimation,
       timeScale,
     } = this.props;
 
     return dom.div(
       {
         className: "animation-summary-graph",
+        title: this.getTitleText(animation.state),
       },
       SummaryGraphPath(
         {
           animation,
           simulateAnimation,
           timeScale,
         }
       ),
@@ -65,9 +164,34 @@ class SummaryGraph extends PureComponent
           }
         )
       :
       null
     );
   }
 }
 
+/**
+ * Get a formatted title for this animation. This will be either:
+ * "%S", "%S : CSS Transition", "%S : CSS Animation",
+ * "%S : Script Animation", or "Script Animation", depending
+ * if the server provides the type, what type it is and if the animation
+ * has a name.
+ *
+ * @param {Object} state
+ */
+function getFormattedTitle(state) {
+  // Older servers don't send a type, and only know about
+  // CSSAnimations and CSSTransitions, so it's safe to use
+  // just the name.
+  if (!state.type) {
+    return state.name;
+  }
+
+  // Script-generated animations may not have a name.
+  if (state.type === "scriptanimation" && !state.name) {
+    return getStr("timeline.scriptanimation.unnamedLabel");
+  }
+
+  return getFormatStr(`timeline.${state.type}.nameLabel`, state.name);
+}
+
 module.exports = SummaryGraph;
--- a/devtools/client/inspector/animation/utils/l10n.js
+++ b/devtools/client/inspector/animation/utils/l10n.js
@@ -5,9 +5,11 @@
 "use strict";
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const L10N =
   new LocalizationHelper("devtools/client/locales/animationinspector.properties");
 
 module.exports = {
   getFormatStr: (...args) => L10N.getFormatStr(...args),
+  getStr: (...args) => L10N.getStr(...args),
+  numberWithDecimals: (...args) => L10N.numberWithDecimals(...args),
 };