- 1 :
/**
- 2 :
* @file time-tooltip.js
- 3 :
*/
- 4 :
import Component from '../../component';
- 5 :
import * as Dom from '../../utils/dom.js';
- 6 :
import {formatTime} from '../../utils/time.js';
- 7 :
import * as Fn from '../../utils/fn.js';
- 8 :
- 9 :
/**
- 10 :
* Time tooltips display a time above the progress bar.
- 11 :
*
- 12 :
* @extends Component
- 13 :
*/
- 14 :
class TimeTooltip extends Component {
- 15 :
- 16 :
/**
- 17 :
* Creates an instance of this class.
- 18 :
*
- 19 :
* @param {Player} player
- 20 :
* The {@link Player} that this class should be attached to.
- 21 :
*
- 22 :
* @param {Object} [options]
- 23 :
* The key/value store of player options.
- 24 :
*/
- 25 :
constructor(player, options) {
- 26 :
super(player, options);
- 27 :
this.update = Fn.throttle(Fn.bind_(this, this.update), Fn.UPDATE_REFRESH_INTERVAL);
- 28 :
}
- 29 :
- 30 :
/**
- 31 :
* Create the time tooltip DOM element
- 32 :
*
- 33 :
* @return {Element}
- 34 :
* The element that was created.
- 35 :
*/
- 36 :
createEl() {
- 37 :
return super.createEl('div', {
- 38 :
className: 'vjs-time-tooltip'
- 39 :
}, {
- 40 :
'aria-hidden': 'true'
- 41 :
});
- 42 :
}
- 43 :
- 44 :
/**
- 45 :
* Updates the position of the time tooltip relative to the `SeekBar`.
- 46 :
*
- 47 :
* @param {Object} seekBarRect
- 48 :
* The `ClientRect` for the {@link SeekBar} element.
- 49 :
*
- 50 :
* @param {number} seekBarPoint
- 51 :
* A number from 0 to 1, representing a horizontal reference point
- 52 :
* from the left edge of the {@link SeekBar}
- 53 :
*/
- 54 :
update(seekBarRect, seekBarPoint, content) {
- 55 :
const tooltipRect = Dom.findPosition(this.el_);
- 56 :
const playerRect = Dom.getBoundingClientRect(this.player_.el());
- 57 :
const seekBarPointPx = seekBarRect.width * seekBarPoint;
- 58 :
- 59 :
// do nothing if either rect isn't available
- 60 :
// for example, if the player isn't in the DOM for testing
- 61 :
if (!playerRect || !tooltipRect) {
- 62 :
return;
- 63 :
}
- 64 :
- 65 :
// This is the space left of the `seekBarPoint` available within the bounds
- 66 :
// of the player. We calculate any gap between the left edge of the player
- 67 :
// and the left edge of the `SeekBar` and add the number of pixels in the
- 68 :
// `SeekBar` before hitting the `seekBarPoint`
- 69 :
const spaceLeftOfPoint = (seekBarRect.left - playerRect.left) + seekBarPointPx;
- 70 :
- 71 :
// This is the space right of the `seekBarPoint` available within the bounds
- 72 :
// of the player. We calculate the number of pixels from the `seekBarPoint`
- 73 :
// to the right edge of the `SeekBar` and add to that any gap between the
- 74 :
// right edge of the `SeekBar` and the player.
- 75 :
const spaceRightOfPoint = (seekBarRect.width - seekBarPointPx) +
- 76 :
(playerRect.right - seekBarRect.right);
- 77 :
- 78 :
// This is the number of pixels by which the tooltip will need to be pulled
- 79 :
// further to the right to center it over the `seekBarPoint`.
- 80 :
let pullTooltipBy = tooltipRect.width / 2;
- 81 :
- 82 :
// Adjust the `pullTooltipBy` distance to the left or right depending on
- 83 :
// the results of the space calculations above.
- 84 :
if (spaceLeftOfPoint < pullTooltipBy) {
- 85 :
pullTooltipBy += pullTooltipBy - spaceLeftOfPoint;
- 86 :
} else if (spaceRightOfPoint < pullTooltipBy) {
- 87 :
pullTooltipBy = spaceRightOfPoint;
- 88 :
}
- 89 :
- 90 :
// Due to the imprecision of decimal/ratio based calculations and varying
- 91 :
// rounding behaviors, there are cases where the spacing adjustment is off
- 92 :
// by a pixel or two. This adds insurance to these calculations.
- 93 :
if (pullTooltipBy < 0) {
- 94 :
pullTooltipBy = 0;
- 95 :
} else if (pullTooltipBy > tooltipRect.width) {
- 96 :
pullTooltipBy = tooltipRect.width;
- 97 :
}
- 98 :
- 99 :
// prevent small width fluctuations within 0.4px from
- 100 :
// changing the value below.
- 101 :
// This really helps for live to prevent the play
- 102 :
// progress time tooltip from jittering
- 103 :
pullTooltipBy = Math.round(pullTooltipBy);
- 104 :
- 105 :
this.el_.style.right = `-${pullTooltipBy}px`;
- 106 :
this.write(content);
- 107 :
}
- 108 :
- 109 :
/**
- 110 :
* Write the time to the tooltip DOM element.
- 111 :
*
- 112 :
* @param {string} content
- 113 :
* The formatted time for the tooltip.
- 114 :
*/
- 115 :
write(content) {
- 116 :
Dom.textContent(this.el_, content);
- 117 :
}
- 118 :
- 119 :
/**
- 120 :
* Updates the position of the time tooltip relative to the `SeekBar`.
- 121 :
*
- 122 :
* @param {Object} seekBarRect
- 123 :
* The `ClientRect` for the {@link SeekBar} element.
- 124 :
*
- 125 :
* @param {number} seekBarPoint
- 126 :
* A number from 0 to 1, representing a horizontal reference point
- 127 :
* from the left edge of the {@link SeekBar}
- 128 :
*
- 129 :
* @param {number} time
- 130 :
* The time to update the tooltip to, not used during live playback
- 131 :
*
- 132 :
* @param {Function} cb
- 133 :
* A function that will be called during the request animation frame
- 134 :
* for tooltips that need to do additional animations from the default
- 135 :
*/
- 136 :
updateTime(seekBarRect, seekBarPoint, time, cb) {
- 137 :
this.requestNamedAnimationFrame('TimeTooltip#updateTime', () => {
- 138 :
let content;
- 139 :
const duration = this.player_.duration();
- 140 :
- 141 :
if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {
- 142 :
const liveWindow = this.player_.liveTracker.liveWindow();
- 143 :
const secondsBehind = liveWindow - (seekBarPoint * liveWindow);
- 144 :
- 145 :
content = (secondsBehind < 1 ? '' : '-') + formatTime(secondsBehind, liveWindow);
- 146 :
} else {
- 147 :
content = formatTime(time, duration);
- 148 :
}
- 149 :
- 150 :
this.update(seekBarRect, seekBarPoint, content);
- 151 :
if (cb) {
- 152 :
cb();
- 153 :
}
- 154 :
});
- 155 :
}
- 156 :
}
- 157 :
- 158 :
Component.registerComponent('TimeTooltip', TimeTooltip);
- 159 :
export default TimeTooltip;