): void {
if (_changedProperties.has("_clip")) {
this.pause();
this.setSegmentPosition();
this._audio[0].currentTime = this._clip.startTime;
}
if (_changedProperties.has("_seekingTime")) {
if (this._seekingTime) {
this._audio[0].currentTime = this._seekingTime;
}
}
}
play(): void {
this._audio[0].play();
}
pause(): void {
this._audio[0].pause();
}
private updatePosition(event: MouseEvent): void {
const cursorPosition =
event.clientX -
(this._sliderNode.getBoundingClientRect().left +
document.documentElement.scrollLeft);
const seconds = this.getSecondsFromPosition(cursorPosition);
switch (this._action) {
case ACTIONS.StretchLeft: {
let startTime;
if (seconds > 0) {
if (seconds > this._clip.endTime - this.minDuration) {
startTime = this._clip.endTime - this.minDuration;
} else {
startTime = seconds;
}
} else {
startTime = 0;
}
this._clip = {
startTime,
endTime: this._clip.endTime,
};
break;
}
case ACTIONS.StretchRight: {
let endTime;
if (seconds < this._audioDuration) {
if (seconds < this._clip.startTime + this.minDuration) {
endTime = this._clip.startTime + this.minDuration;
} else {
endTime = seconds;
}
} else {
endTime = this._audioDuration;
}
this._clip = {
startTime: this._clip.startTime,
endTime,
};
break;
}
case ACTIONS.Seek: {
if (seconds < this._clip.startTime) {
this._seekingTime = this._clip.startTime;
} else if (seconds > this._clip.endTime) {
this._seekingTime = this._clip.endTime;
} else {
this._seekingTime = seconds;
}
break;
}
default:
break;
}
}
goTo(event: MouseEvent): void {
const cursorPosition =
event.clientX -
(this._sliderNode.getBoundingClientRect().left +
document.documentElement.scrollLeft);
const seconds = this.getSecondsFromPosition(cursorPosition);
this._audio[0].currentTime = seconds;
}
setVolume(event: InputEvent): void {
this._volume = parseFloat((event.target as HTMLInputElement).value);
this._audio[0].volume = this._volume;
}
setCurrentTime(currentTime: number): void {
const seekingTimePosition = this.getPositionFromSeconds(currentTime);
const startTimePosition = this.getPositionFromSeconds(this._clip.startTime);
const seekingTimeSegmentPosition = seekingTimePosition - startTimePosition;
const seekingTimePercentage =
(seekingTimeSegmentPosition / this._segmentContentNode.clientWidth) *
this._segmentContentNode.clientWidth;
this._progressNode.style.transform = `translateX(${seekingTimeSegmentPosition}px)`;
this._seekingNode.style.transform = `scaleX(${seekingTimePercentage})`;
}
setAction(action: ACTIONS): void {
switch (action) {
case ACTIONS.StretchLeft:
case ACTIONS.StretchRight:
document.body.style.cursor = "grabbing";
break;
default:
document.body.style.cursor = "default";
break;
}
this._action = action;
}
private secondsToHHMMSS(seconds: number): string {
return new Date(seconds * 1000).toISOString().substr(11, 8);
}
static styles = css`
.slider-wrapper {
position: relative;
width: 100%;
background-color: #0f172a;
}
.slider {
position: absolute;
z-index: 10;
top: 0;
left: 0;
display: flex;
align-items: center;
height: 100%;
width: 100%;
}
.slider__track-placeholder {
width: 100%;
height: 8px;
background-color: #64748b;
}
.slider__segment--wrapper {
position: absolute;
height: 100%;
}
.slider__segment {
position: relative;
display: flex;
height: 100%;
}
.slider__segment-content {
background-color: rgba(255, 255, 255, 0.5);
height: 100%;
width: 1px;
border: none;
}
.slider__seeking-placeholder {
position: absolute;
pointer-events: none;
background-color: rgba(255, 255, 255, 0.5);
height: 100%;
width: 1px;
transform-origin: left;
}
.slider__segment-progress-handle {
position: absolute;
width: 20px;
height: 20px;
top: -23px;
left: -10px;
background-color: #3b82f6;
border-radius: 50%;
}
.slider__segment-progress-handle::after {
position: absolute;
content: "";
width: 0px;
height: 0px;
bottom: -12px;
left: 1px;
border: 10px solid transparent;
border-top-color: transparent;
border-top-style: solid;
border-top-width: 10px;
border-top: 10px solid #3b82f6;
}
.slider__segment .slider__segment-handle {
position: absolute;
width: 1rem;
height: 120%;
background-color: #b91c1c;
border: none;
margin: auto 0;
top: 0;
bottom: 0;
}
.slider__segment .slider__segment-handle::before {
content: "";
position: absolute;
height: 3rem;
width: 2px;
background-color: #ffffff;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.slider__segment .clipper__handle-left {
left: -1rem;
border-radius: 0.2rem 9999px 9999px 0.2rem;
}
.slider__segment .clipper__handle-right {
right: -1rem;
border-radius: 9999px 0.2rem 0.2rem 9999px;
}
`;
render(): TemplateResult<1> {
return html`
${this.secondsToHHMMSS(this._clip.startTime)}
${this.secondsToHHMMSS(this._currentTime)}
${this.secondsToHHMMSS(this._clip.endTime)}
${this._isLoading ? "loading..." : "not loading"}
this.setAction(ACTIONS.Seek)}"
>
this.setAction(ACTIONS.Seek)}"
@click="${(event: MouseEvent) => this.goTo(event)}"
>
`;
}
}