Browse Source

Volume controls for video

master
morethanwords 4 years ago
parent
commit
ae8f0755b7
  1. 10
      src/lib/logger.ts
  2. 126
      src/lib/mediaPlayer.ts
  3. 4
      src/scss/partials/_chatBubble.scss
  4. 186
      src/scss/partials/_ckin.scss
  5. 2
      src/scss/partials/_rightSidebar.scss

10
src/lib/logger.ts

@ -16,7 +16,7 @@ export function logger(prefix: string, level = LogLevels.log | LogLevels.warn | @@ -16,7 +16,7 @@ export function logger(prefix: string, level = LogLevels.log | LogLevels.warn |
level = LogLevels.error;
}
level = LogLevels.log | LogLevels.warn | LogLevels.error | LogLevels.debug
//level = LogLevels.log | LogLevels.warn | LogLevels.error | LogLevels.debug
function Log(...args: any[]) {
return level & LogLevels.log && console.log(dT(), '[' + prefix + ']:', ...args);
@ -38,13 +38,13 @@ export function logger(prefix: string, level = LogLevels.log | LogLevels.warn | @@ -38,13 +38,13 @@ export function logger(prefix: string, level = LogLevels.log | LogLevels.warn |
return level & LogLevels.log && console.trace(dT(), '[' + prefix + ']:', ...args);
};
Log.debug = function(...args: any[]) {
/* Log.debug = function(...args: any[]) {
return level & LogLevels.debug && console.log(dT(), '[' + prefix + ']:', ...args);
};
}; */
/* Log.debug = function(...args: any[]) {
Log.debug = function(...args: any[]) {
return level & LogLevels.debug && console.debug(dT(), '[' + prefix + ']:', ...args);
}; */
};
return Log;
};

126
src/lib/mediaPlayer.ts

@ -1,9 +1,11 @@ @@ -1,9 +1,11 @@
import { cancelEvent } from "./utils";
export class ProgressLine {
public container: HTMLDivElement;
protected filled: HTMLDivElement;
protected seek: HTMLInputElement;
protected duration = 100;
protected duration = 1;
protected mousedown = false;
private events: Partial<{
@ -13,22 +15,26 @@ export class ProgressLine { @@ -13,22 +15,26 @@ export class ProgressLine {
onScrub: (scrubTime: number) => void
}> = {};
constructor() {
constructor(initialValue = 0) {
this.container = document.createElement('div');
this.container.classList.add('media-progress');
this.container.classList.add('progress-line');
this.filled = document.createElement('div');
this.filled.classList.add('media-progress__filled');
this.filled.classList.add('progress-line__filled');
const seek = this.seek = document.createElement('input');
seek.classList.add('media-progress__seek');
seek.value = '0';
seek.classList.add('progress-line__seek');
seek.value = '' + initialValue;
seek.setAttribute('min', '0');
seek.setAttribute('max', '0');
//seek.setAttribute('max', '0');
seek.type = 'range';
seek.step = '0.1';
seek.max = '' + (this.duration * 1000);
if(initialValue > 0) {
this.setProgress(initialValue);
}
//this.setListeners();
this.container.append(this.filled, seek);
@ -45,28 +51,37 @@ export class ProgressLine { @@ -45,28 +51,37 @@ export class ProgressLine {
onMouseDown = (e: MouseEvent) => {
this.scrub(e);
this.mousedown = true;
this.events?.onMouseDown(e);
this.events?.onMouseDown && this.events.onMouseDown(e);
};
onMouseUp = (e: MouseEvent) => {
this.mousedown = false;
this.events?.onMouseUp(e);
this.events?.onMouseUp && this.events.onMouseUp(e);
};
protected setListeners() {
public setListeners() {
this.container.addEventListener('mousemove', this.onMouseMove);
this.container.addEventListener('mousedown', this.onMouseDown);
this.container.addEventListener('mouseup', this.onMouseUp);
}
protected scrub(e: MouseEvent) {
const scrubTime = e.offsetX / this.container.offsetWidth * this.duration;
public setProgress(scrubTime: number) {
this.setFilled(scrubTime);
this.seek.value = '' + (scrubTime * 1000);
}
public setFilled(scrubTime: number) {
let scaleX = scrubTime / this.duration;
scaleX = Math.max(0, Math.min(1, scaleX));
this.filled.style.transform = 'scaleX(' + scaleX + ')';
}
//this.events?.onScrub(scrubTime);
protected scrub(e: MouseEvent) {
const scrubTime = e.offsetX / this.container.offsetWidth * this.duration;
this.setFilled(scrubTime);
this.events?.onScrub && this.events.onScrub(scrubTime);
return scrubTime;
}
@ -90,7 +105,7 @@ export class MediaProgressLine extends ProgressLine { @@ -90,7 +105,7 @@ export class MediaProgressLine extends ProgressLine {
if(streamable) {
this.filledLoad = document.createElement('div');
this.filledLoad.classList.add('media-progress__filled', 'media-progress__loaded');
this.filledLoad.classList.add('progress-line__filled', 'progress-line__loaded');
this.container.prepend(this.filledLoad);
//this.setLoadProgress();
}
@ -197,15 +212,13 @@ export class MediaProgressLine extends ProgressLine { @@ -197,15 +212,13 @@ export class MediaProgressLine extends ProgressLine {
}
}
protected setProgress() {
public setProgress() {
const currentTime = this.media.currentTime;
const scaleX = (currentTime / this.duration);
this.filled.style.transform = 'scaleX(' + scaleX + ')';
this.seek.value = '' + currentTime * 1000;
super.setProgress(currentTime);
}
protected setListeners() {
public setListeners() {
super.setListeners();
this.media.addEventListener('ended', this.onEnded);
this.media.addEventListener('play', this.onPlay);
@ -230,6 +243,7 @@ export class MediaProgressLine extends ProgressLine { @@ -230,6 +243,7 @@ export class MediaProgressLine extends ProgressLine {
}
}
let lastVolume = 1, muted = !lastVolume;
export default class VideoPlayer {
public wrapper: HTMLDivElement;
public progress: MediaProgressLine;
@ -275,6 +289,65 @@ export default class VideoPlayer { @@ -275,6 +289,65 @@ export default class VideoPlayer {
var timeDuration = player.querySelector('#time-duration') as HTMLElement;
timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();
const volumeDiv = document.createElement('div');
volumeDiv.classList.add('player-volume');
volumeDiv.innerHTML = `
<svg class="player-volume__icon" focusable="false" viewBox="0 0 24 24" aria-hidden="true"></svg>
`;
const volumeSvg = volumeDiv.firstElementChild as SVGSVGElement;
volumeSvg.addEventListener('click', (e) => {
cancelEvent(e);
if(!lastVolume) {
muted = true;
lastVolume = 1;
}
const realVolume = !muted ? 0 : lastVolume;
setVolume(realVolume);
volumeProgress.setProgress(realVolume);
muted = !muted;
});
const setVolume = (volume: number) => {
let d: string;
if(volume > .5) {
d = `M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z`;
} else if(!volume) {
d = `M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z`;
} else if(volume > 0 && volume < .25) {
d = `M7 9v6h4l5 5V4l-5 5H7z`;
} else {
d = `M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z`;
}
try {
volumeSvg.innerHTML = `<path d="${d}"></path>`;
} catch(err) {}
video.volume = volume;
};
const fakeVolume = muted ? 0 : lastVolume;
video.volume = fakeVolume;
setVolume(fakeVolume);
const volumeProgress = new ProgressLine(muted ? 0 : fakeVolume);
volumeProgress.setListeners();
volumeProgress.setHandlers({
onScrub: currentTime => {
const value = Math.max(Math.min(currentTime, 1), 0);
console.log('scrub', currentTime, value);
setVolume(lastVolume = value);
}
});
volumeDiv.append(volumeProgress.container);
const leftControls = player.querySelector('.left-controls');
leftControls.insertBefore(volumeDiv, timeElapsed.parentElement);
Array.from(toggle).forEach((button) => {
return button.addEventListener('click', () => {
this.togglePlay();
@ -402,9 +475,8 @@ export default class VideoPlayer { @@ -402,9 +475,8 @@ export default class VideoPlayer {
private buildControls() {
const skin = this.skin;
const html: string[] = [];
if(skin === 'default') {
html.push(`
return `
<button class="${skin}__button--big toggle tgico-largeplay" title="Toggle Play"></button>
<div class="${skin}__gradient-bottom ckin__controls"></div>
<div class="${skin}__controls ckin__controls">
@ -421,14 +493,14 @@ export default class VideoPlayer { @@ -421,14 +493,14 @@ export default class VideoPlayer {
<button class="${skin}__button fullscreen tgico-fullscreen" title="Full Screen"></button>
</div>
</div>
</div>`);
</div>`;
} else if(skin === 'circle') {
html.push('<svg class="progress-ring" width="200px" height="200px">',
'<circle class="progress-ring__circle" stroke="white" stroke-opacity="0.3" stroke-width="3.5" cx="100" cy="100" r="93" fill="transparent" transform="rotate(-90, 100, 100)"/>',
'</svg>');
return `
<svg class="progress-ring" width="200px" height="200px">
<circle class="progress-ring__circle" stroke="white" stroke-opacity="0.3" stroke-width="3.5" cx="100" cy="100" r="93" fill="transparent" transform="rotate(-90, 100, 100)"/>
</svg>
`;
}
return html.join('');
}
public updateButton(toggle: NodeListOf<HTMLElement>) {

4
src/scss/partials/_chatBubble.scss

@ -754,7 +754,7 @@ $bubble-margin: .25rem; @@ -754,7 +754,7 @@ $bubble-margin: .25rem;
}
}
.media-progress {
.progress-line {
/* width: calc(100% + 50px); */
width: 191px;
margin: 9px 0 9px;
@ -1202,7 +1202,7 @@ $bubble-margin: .25rem; @@ -1202,7 +1202,7 @@ $bubble-margin: .25rem;
}
.message.audio-message {
.media-progress {
.progress-line {
&__seek {
background: rgba(193, 207, 220, 0.39);
}

186
src/scss/partials/_ckin.scss

@ -1,6 +1,27 @@ @@ -1,6 +1,27 @@
.ckin {
&__player {
letter-spacing: 0.02em;
&.ckin__fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0 !important;
display: -ms-flexbox;
display: flex;
video {
max-height: none;
max-width: none;
object-fit: contain;
}
}
}
&__overlay {
@ -16,27 +37,6 @@ @@ -16,27 +37,6 @@
}
}
.ckin__player.ckin__fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0 !important;
display: -ms-flexbox;
display: flex;
video {
max-height: none;
max-width: none;
object-fit: contain;
}
}
.default {
border: 0 solid rgba(0, 0, 0, 0.2);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
@ -120,73 +120,105 @@ @@ -120,73 +120,105 @@
direction: ltr;
border-radius: 0 0 5px 5px;
z-index: 6;
.progress-line {
margin: 0 16px;
height: 5px;
background: rgba(255, 255, 255, 0.38);
border-radius: 4px;
overflow: visible;
&__filled {
background: #63a2e3;
transform-origin: left;
border-radius: 4px;
height: 5px;
transform: scaleX(0);
}
&__loaded {
background: rgba(255, 255, 255, 0.38);
left: 11px;
width: calc(100% - 11px);
}
}
}
}
.default__gradient-bottom {
height: 49px;
// padding-top: 49px;
padding-top: 93px;
bottom: 0;
z-index: 2;
background-position: bottom;
width: 100%;
position: absolute;
background-repeat: repeat-x;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==);
transition: all .3s;
pointer-events: none;
}
&__gradient-bottom {
height: 49px;
// padding-top: 49px;
padding-top: 93px;
bottom: 0;
z-index: 2;
background-position: bottom;
width: 100%;
position: absolute;
background-repeat: repeat-x;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==);
transition: all .3s;
pointer-events: none;
}
.default.is-playing .default__gradient-bottom {
transform: translateY(50px);
}
&.is-playing {
.default__gradient-bottom {
transform: translateY(50px);
}
html.no-touch .default.is-playing:hover .default__gradient-bottom {
transform: translateY(0px);
}
html.no-touch &:hover {
.default__gradient-bottom {
transform: translateY(0px);
}
.default.is-playing:before {
opacity: 0;
visibility: hidden;
transform: translate(-50%, -50%) scale(1.3);
}
.default__controls {
transform: translateY(0);
}
}
.default.is-playing .default__button--big {
opacity: 0;
visibility: hidden;
}
&:before {
opacity: 0;
visibility: hidden;
transform: translate(-50%, -50%) scale(1.3);
}
.default.is-playing .default__controls {
transform: translateY(52px);
}
.default__button--big {
opacity: 0;
visibility: hidden;
}
html.no-touch .default.is-playing:hover .default__controls {
transform: translateY(0);
}
.default__controls {
transform: translateY(52px);
}
}
.default {
.media-progress {
margin: 0 16px;
height: 5px;
transition: height 0.3s;
background: rgba(255, 255, 255, 0.38);
border-radius: 4px;
overflow: visible;
&__filled {
background: #63a2e3;
transform-origin: left;
border-radius: 4px;
height: 5px;
transform: scaleX(0);
.player-volume {
margin: -3px 12px 0 16px;
display: flex;
align-items: center;
&__icon {
fill: #fff;
width: 24px;
height: 24px;
margin-right: 8px;
cursor: pointer;
}
&__loaded {
background: rgba(255, 255, 255, 0.38);
left: 11px;
width: calc(100% - 11px);
.progress-line {
margin: 0;
width: 50px;
&__filled {
background: #fff;
}
input[type=range]::-webkit-slider-thumb {
height: 15px;
width: 15px;
border-radius: 16px;
background: #fff;
}
}
}
}
@ -200,7 +232,7 @@ video::-webkit-media-controls-enclosure { @@ -200,7 +232,7 @@ video::-webkit-media-controls-enclosure {
display: none !important;
}
.media-progress {
.progress-line {
position: relative;
cursor: pointer;

2
src/scss/partials/_rightSidebar.scss

@ -466,7 +466,7 @@ @@ -466,7 +466,7 @@
}
}
.media-progress {
.progress-line {
margin: 11px 0 8px;
&__filled {

Loading…
Cancel
Save