Bug 1406285 - Part 3: Implement summary graph base. r=gl
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 18 Jan 2018 10:40:51 +0900
changeset 454259 ad4a9cbf32d40ac0c62d86e0d0d94b9f05ce7bfd
parent 454258 67a986bb3a23f15e9ad318fba50fc75556fe0ca9
child 454260 bbe12d4a23d941924202b87c5409f9436f77020f
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgl
bugs1406285
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1406285 - Part 3: Implement summary graph base. r=gl MozReview-Commit-ID: KMbUvJPDuNM
devtools/client/inspector/animation/components/AnimationItem.js
devtools/client/inspector/animation/components/AnimationList.js
devtools/client/inspector/animation/components/AnimationListContainer.js
devtools/client/inspector/animation/components/AnimationListHeader.js
devtools/client/inspector/animation/components/AnimationTimelineTickList.js
devtools/client/inspector/animation/components/graph/SummaryGraph.js
devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
devtools/client/inspector/animation/components/graph/moz.build
devtools/client/inspector/animation/components/moz.build
devtools/client/themes/animation.css
--- a/devtools/client/inspector/animation/components/AnimationItem.js
+++ b/devtools/client/inspector/animation/components/AnimationItem.js
@@ -4,50 +4,59 @@
 
 "use strict";
 
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const AnimationTarget = createFactory(require("./AnimationTarget"));
+const SummaryGraph = createFactory(require("./graph/SummaryGraph"));
 
 class AnimationItem extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
+      timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const {
       animation,
       emitEventForTest,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
+      timeScale,
     } = this.props;
 
     return dom.li(
       {
         className: "animation-item"
       },
       AnimationTarget(
         {
           animation,
           emitEventForTest,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           setSelectedNode,
         }
+      ),
+      SummaryGraph(
+        {
+          animation,
+          timeScale,
+        }
       )
     );
   }
 }
 
 module.exports = AnimationItem;
--- a/devtools/client/inspector/animation/components/AnimationList.js
+++ b/devtools/client/inspector/animation/components/AnimationList.js
@@ -14,42 +14,45 @@ class AnimationList extends PureComponen
   static get propTypes() {
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
+      timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const {
       animations,
       emitEventForTest,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
+      timeScale,
     } = this.props;
 
     return dom.ul(
       {
         className: "animation-list"
       },
       animations.map(animation =>
         AnimationItem(
           {
             animation,
             emitEventForTest,
             getNodeFromActor,
             onHideBoxModelHighlighter,
             onShowBoxModelHighlighterForNode,
             setSelectedNode,
+            timeScale,
           }
         )
       )
     );
   }
 }
 
 module.exports = AnimationList;
--- a/devtools/client/inspector/animation/components/AnimationListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimationListContainer.js
@@ -7,16 +7,18 @@
 const { createFactory, PureComponent } =
   require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 
 const AnimationList = createFactory(require("./AnimationList"));
 const AnimationListHeader = createFactory(require("./AnimationListHeader"));
 
+const TimeScale = require("../utils/timescale");
+
 class AnimationListContainer extends PureComponent {
   static get propTypes() {
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
@@ -28,33 +30,35 @@ class AnimationListContainer extends Pur
     const {
       animations,
       emitEventForTest,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
     } = this.props;
+    const timeScale = new TimeScale(animations);
 
     return dom.div(
       {
         className: "animation-list-container"
       },
       AnimationListHeader(
         {
-          animations
+          timeScale,
         }
       ),
       AnimationList(
         {
           animations,
           emitEventForTest,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           setSelectedNode,
+          timeScale,
         }
       )
     );
   }
 }
 
 module.exports = AnimationListContainer;
--- a/devtools/client/inspector/animation/components/AnimationListHeader.js
+++ b/devtools/client/inspector/animation/components/AnimationListHeader.js
@@ -9,29 +9,29 @@ const { createFactory, PureComponent } =
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 
 const AnimationTimelineTickList = createFactory(require("./AnimationTimelineTickList"));
 
 class AnimationListHeader extends PureComponent {
   static get propTypes() {
     return {
-      animations: PropTypes.arrayOf(PropTypes.object).isRequired,
+      timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
-    const { animations } = this.props;
+    const { timeScale } = this.props;
 
     return dom.div(
       {
         className: "animation-list-header devtools-toolbar"
       },
       AnimationTimelineTickList(
         {
-          animations
+          timeScale
         }
       )
     );
   }
 }
 
 module.exports = AnimationListHeader;
--- a/devtools/client/inspector/animation/components/AnimationTimelineTickList.js
+++ b/devtools/client/inspector/animation/components/AnimationTimelineTickList.js
@@ -8,27 +8,26 @@ const { createFactory, PureComponent } =
   require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 
 const AnimationTimelineTickItem = createFactory(require("./AnimationTimelineTickItem"));
 
-const TimeScale = require("../utils/timescale");
 const { findOptimalTimeInterval } = require("../utils/utils");
 
 // The minimum spacing between 2 time graduation headers in the timeline (px).
 const TIME_GRADUATION_MIN_SPACING = 40;
 
 class AnimationTimelineTickList extends PureComponent {
   static get propTypes() {
     return {
-      animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       sidebarWidth: PropTypes.number.isRequired,
+      timeScale: PropTypes.object.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
       tickList: [],
@@ -56,18 +55,17 @@ class AnimationTimelineTickList extends 
         return true;
       }
     }
 
     return false;
   }
 
   updateTickList() {
-    const { animations } = this.props;
-    const timeScale = new TimeScale(animations);
+    const { timeScale } = this.props;
     const tickListEl = ReactDOM.findDOMNode(this);
     const width = tickListEl.offsetWidth;
     const animationDuration = timeScale.getDuration();
     const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
     const intervalLength = findOptimalTimeInterval(minTimeInterval);
     const intervalWidth = intervalLength * width / animationDuration;
     const tickCount = width / intervalWidth;
     const intervalPositionPercentage = 100 * intervalWidth / width;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/graph/SummaryGraph.js
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const SummaryGraphPath = createFactory(require("./SummaryGraphPath"));
+
+class SummaryGraph extends PureComponent {
+  static get propTypes() {
+    return {
+      animation: PropTypes.object.isRequired,
+      timeScale: PropTypes.object.isRequired,
+    };
+  }
+
+  render() {
+    const {
+      animation,
+      timeScale,
+    } = this.props;
+
+    return dom.div(
+      {
+        className: "animation-summary-graph",
+      },
+      SummaryGraphPath(
+        {
+          animation,
+          timeScale,
+        }
+      )
+    );
+  }
+}
+
+module.exports = SummaryGraph;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+class SummaryGraphPath extends PureComponent {
+  static get propTypes() {
+    return {
+      animation: PropTypes.object.isRequired,
+      timeScale: PropTypes.object.isRequired,
+    };
+  }
+
+  render() {
+    const {
+      animation,
+      timeScale,
+    } = this.props;
+
+    const totalDisplayedDuration = animation.state.playbackRate * timeScale.getDuration();
+    const startTime = timeScale.minStartTime;
+
+    return dom.svg(
+      {
+        className: "animation-summary-graph-path",
+        preserveAspectRatio: "none",
+        viewBox: `${ startTime } -1 ${ totalDisplayedDuration } 1`
+      }
+    );
+  }
+}
+
+module.exports = SummaryGraphPath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/graph/moz.build
@@ -0,0 +1,8 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DevToolsModules(
+    'SummaryGraph.js',
+    'SummaryGraphPath.js'
+)
--- a/devtools/client/inspector/animation/components/moz.build
+++ b/devtools/client/inspector/animation/components/moz.build
@@ -1,12 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+DIRS += [
+    'graph'
+]
+
 DevToolsModules(
     'AnimationItem.js',
     'AnimationList.js',
     'AnimationListContainer.js',
     'AnimationListHeader.js',
     'AnimationTarget.js',
     'AnimationTimelineTickItem.js',
     'AnimationTimelineTickList.js',
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Animation-inspector specific theme variables */
 
 :root {
   --animation-even-background-color: rgba(0, 0, 0, 0.05);
   --command-pick-image: url(chrome://devtools/skin/images/command-pick.svg);
+  --graph-right-offset: 10px;
   --sidebar-width: 200px;
 }
 
 :root.theme-dark {
   --animation-even-background-color: rgba(255, 255, 255, 0.05);
 }
 
 :root.theme-firebug {
@@ -22,19 +23,19 @@
 .animation-list-header {
   display: flex;
   justify-content: flex-end;
   padding: 0;
 }
 
 /* Animation Timeline Tick List */
 .animation-timeline-tick-list {
-  margin-right: 10px;
+  margin-right: var(--graph-right-offset);
   position: relative;
-  width: calc(100% - var(--sidebar-width) - 10px);
+  width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
 }
 
 .animation-timeline-tick-item {
   border-left: 0.5px solid rgba(128, 136, 144, .5);
   height: 100vh;
   position: absolute;
 }
 
@@ -42,16 +43,17 @@
 .animation-list {
   list-style-type: none;
   margin-top: 0;
   padding: 0;
 }
 
 /* Animation Item */
 .animation-item {
+  display: flex;
   height: 30px;
 }
 
 .animation-item:nth-child(2n+1) {
   background-color: var(--animation-even-background-color);
 }
 
 /* Animation Target */
@@ -62,16 +64,27 @@
   padding-left: 4px;
   width: var(--sidebar-width);
 }
 
 .animation-target .tag-name {
   cursor: default;
 }
 
+/* Summary Graph */
+.animation-summary-graph {
+  height: 100%;
+  width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
+}
+
+.animation-summary-graph-path {
+  height: 100%;
+  width: 100%;
+}
+
 /* No Animation Panel */
 .animation-error-message {
   overflow: auto;
 }
 
 .animation-error-message > p {
   white-space: pre;
 }