CurrentTimeScrubber.js (4225B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); 8 const { 9 createRef, 10 PureComponent, 11 } = require("resource://devtools/client/shared/vendor/react.mjs"); 12 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 13 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 14 15 class CurrentTimeScrubber extends PureComponent { 16 static get propTypes() { 17 return { 18 addAnimationsCurrentTimeListener: PropTypes.func.isRequired, 19 direction: PropTypes.string.isRequired, 20 removeAnimationsCurrentTimeListener: PropTypes.func.isRequired, 21 setAnimationsCurrentTime: PropTypes.func.isRequired, 22 timeScale: PropTypes.object.isRequired, 23 }; 24 } 25 26 constructor(props) { 27 super(props); 28 29 this._ref = createRef(); 30 31 const { addAnimationsCurrentTimeListener } = props; 32 this.onCurrentTimeUpdated = this.onCurrentTimeUpdated.bind(this); 33 this.onMouseDown = this.onMouseDown.bind(this); 34 this.onMouseMove = this.onMouseMove.bind(this); 35 this.onMouseUp = this.onMouseUp.bind(this); 36 37 addAnimationsCurrentTimeListener(this.onCurrentTimeUpdated); 38 } 39 40 componentDidMount() { 41 const current = this._ref.current; 42 current.addEventListener("mousedown", this.onMouseDown); 43 this._scrubber = current.querySelector(".current-time-scrubber"); 44 } 45 46 componentWillUnmount() { 47 const { removeAnimationsCurrentTimeListener } = this.props; 48 removeAnimationsCurrentTimeListener(this.onCurrentTimeUpdated); 49 } 50 51 onCurrentTimeUpdated(currentTime) { 52 const { timeScale } = this.props; 53 54 const position = currentTime / timeScale.getDuration(); 55 // onCurrentTimeUpdated is bound to requestAnimationFrame. 56 // As to update the component too frequently has performance issue if React controlled, 57 // update raw component directly. See Bug 1699039. 58 this._scrubber.style.marginInlineStart = `${position * 100}%`; 59 } 60 61 onMouseDown(event) { 62 event.stopPropagation(); 63 const current = this._ref.current; 64 this.controllerArea = current.getBoundingClientRect(); 65 this.listenerTarget = DevToolsUtils.getTopWindow(current.ownerGlobal); 66 this.listenerTarget.addEventListener("mousemove", this.onMouseMove); 67 this.listenerTarget.addEventListener("mouseup", this.onMouseUp); 68 this.decorationTarget = current.closest(".animation-list-container"); 69 this.decorationTarget.classList.add("active-scrubber"); 70 71 this.updateAnimationsCurrentTime(event.pageX, true); 72 } 73 74 onMouseMove(event) { 75 event.stopPropagation(); 76 this.isMouseMoved = true; 77 this.updateAnimationsCurrentTime(event.pageX); 78 } 79 80 onMouseUp(event) { 81 event.stopPropagation(); 82 83 if (this.isMouseMoved) { 84 this.updateAnimationsCurrentTime(event.pageX, true); 85 this.isMouseMoved = null; 86 } 87 88 this.uninstallListeners(); 89 } 90 91 uninstallListeners() { 92 this.listenerTarget.removeEventListener("mousemove", this.onMouseMove); 93 this.listenerTarget.removeEventListener("mouseup", this.onMouseUp); 94 this.listenerTarget = null; 95 this.decorationTarget.classList.remove("active-scrubber"); 96 this.decorationTarget = null; 97 this.controllerArea = null; 98 } 99 100 updateAnimationsCurrentTime(pageX, needRefresh) { 101 const { direction, setAnimationsCurrentTime, timeScale } = this.props; 102 103 let progressRate = 104 (pageX - this.controllerArea.x) / this.controllerArea.width; 105 106 if (progressRate < 0.0) { 107 progressRate = 0.0; 108 } else if (progressRate > 1.0) { 109 progressRate = 1.0; 110 } 111 112 const time = 113 direction === "ltr" 114 ? progressRate * timeScale.getDuration() 115 : (1 - progressRate) * timeScale.getDuration(); 116 117 setAnimationsCurrentTime(time, needRefresh); 118 } 119 120 render() { 121 return dom.div( 122 { 123 className: "current-time-scrubber-area", 124 ref: this._ref, 125 }, 126 dom.div({ className: "indication-bar current-time-scrubber" }) 127 ); 128 } 129 } 130 131 module.exports = CurrentTimeScrubber;