mirror of https://github.com/sveltejs/svelte
parent
4d3be024cc
commit
e5ec5acd89
@ -0,0 +1,127 @@
|
|||||||
|
<script>
|
||||||
|
// These values are bound to properties of the video
|
||||||
|
let time = 0;
|
||||||
|
let duration;
|
||||||
|
let paused = true;
|
||||||
|
|
||||||
|
let showControls = true;
|
||||||
|
let showControlsTimeout;
|
||||||
|
|
||||||
|
function handleMousemove(e) {
|
||||||
|
// Make the controls visible, but fade out after
|
||||||
|
// 2.5 seconds of inactivity
|
||||||
|
clearTimeout(showControlsTimeout);
|
||||||
|
showControlsTimeout = setTimeout(() => showControls = false, 2500);
|
||||||
|
showControls = true;
|
||||||
|
|
||||||
|
if (e.which !== 1) return; // mouse not down
|
||||||
|
if (!duration) return; // video not loaded yet
|
||||||
|
|
||||||
|
const { left, right } = this.getBoundingClientRect();
|
||||||
|
time = duration * (e.clientX - left) / (right - left);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMousedown(e) {
|
||||||
|
// we can't rely on the built-in click event, because it fires
|
||||||
|
// after a drag — we have to listen for clicks ourselves
|
||||||
|
|
||||||
|
function handleMouseup() {
|
||||||
|
if (paused) e.target.play();
|
||||||
|
else e.target.pause();
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
e.target.removeEventListener('mouseup', handleMouseup);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.addEventListener('mouseup', handleMouseup);
|
||||||
|
|
||||||
|
setTimeout(cancel, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function format(seconds) {
|
||||||
|
if (isNaN(seconds)) return '...';
|
||||||
|
|
||||||
|
const minutes = Math.floor(seconds / 60);
|
||||||
|
seconds = Math.floor(seconds % 60);
|
||||||
|
if (seconds < 10) seconds = '0' + seconds;
|
||||||
|
|
||||||
|
return `${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
transition: opacity 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0 0 8px black;
|
||||||
|
font-size: 1.4em;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
width: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time:last-child { text-align: right }
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-bar {
|
||||||
|
background-color: rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-value {
|
||||||
|
background-color: rgba(255,255,255,0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>Caminandes: Llamigos</h1>
|
||||||
|
<p>From <a href="https://cloud.blender.org/open-projects">Blender Open Projects</a>. CC-BY</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<video
|
||||||
|
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg"
|
||||||
|
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4"
|
||||||
|
on:mousemove={handleMousemove}
|
||||||
|
on:mousedown={handleMousedown}
|
||||||
|
></video>
|
||||||
|
|
||||||
|
<div class="controls" style="opacity: {duration && showControls ? 1 : 0}">
|
||||||
|
<progress value="{(time / duration) || 0}"/>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<span class="time">{format(time)}</span>
|
||||||
|
<span>click anywhere to {paused ? 'play' : 'pause'} / drag to seek</span>
|
||||||
|
<span class="time">{format(duration)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,130 @@
|
|||||||
|
<script>
|
||||||
|
// These values are bound to properties of the video
|
||||||
|
let time = 0;
|
||||||
|
let duration;
|
||||||
|
let paused = true;
|
||||||
|
|
||||||
|
let showControls = true;
|
||||||
|
let showControlsTimeout;
|
||||||
|
|
||||||
|
function handleMousemove(e) {
|
||||||
|
// Make the controls visible, but fade out after
|
||||||
|
// 2.5 seconds of inactivity
|
||||||
|
clearTimeout(showControlsTimeout);
|
||||||
|
showControlsTimeout = setTimeout(() => showControls = false, 2500);
|
||||||
|
showControls = true;
|
||||||
|
|
||||||
|
if (e.which !== 1) return; // mouse not down
|
||||||
|
if (!duration) return; // video not loaded yet
|
||||||
|
|
||||||
|
const { left, right } = this.getBoundingClientRect();
|
||||||
|
time = duration * (e.clientX - left) / (right - left);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMousedown(e) {
|
||||||
|
// we can't rely on the built-in click event, because it fires
|
||||||
|
// after a drag — we have to listen for clicks ourselves
|
||||||
|
|
||||||
|
function handleMouseup() {
|
||||||
|
if (paused) e.target.play();
|
||||||
|
else e.target.pause();
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
e.target.removeEventListener('mouseup', handleMouseup);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.addEventListener('mouseup', handleMouseup);
|
||||||
|
|
||||||
|
setTimeout(cancel, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function format(seconds) {
|
||||||
|
if (isNaN(seconds)) return '...';
|
||||||
|
|
||||||
|
const minutes = Math.floor(seconds / 60);
|
||||||
|
seconds = Math.floor(seconds % 60);
|
||||||
|
if (seconds < 10) seconds = '0' + seconds;
|
||||||
|
|
||||||
|
return `${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
transition: opacity 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0 0 8px black;
|
||||||
|
font-size: 1.4em;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
width: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time:last-child { text-align: right }
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-bar {
|
||||||
|
background-color: rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-value {
|
||||||
|
background-color: rgba(255,255,255,0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>Caminandes: Llamigos</h1>
|
||||||
|
<p>From <a href="https://cloud.blender.org/open-projects">Blender Open Projects</a>. CC-BY</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<video
|
||||||
|
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg"
|
||||||
|
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4"
|
||||||
|
on:mousemove={handleMousemove}
|
||||||
|
on:mousedown={handleMousedown}
|
||||||
|
bind:currentTime={time}
|
||||||
|
bind:duration
|
||||||
|
bind:paused
|
||||||
|
></video>
|
||||||
|
|
||||||
|
<div class="controls" style="opacity: {duration && showControls ? 1 : 0}">
|
||||||
|
<progress value="{(time / duration) || 0}"/>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<span class="time">{format(time)}</span>
|
||||||
|
<span>click anywhere to {paused ? 'play' : 'pause'} / drag to seek</span>
|
||||||
|
<span class="time">{format(duration)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
title: Media elements
|
||||||
|
---
|
||||||
|
|
||||||
|
The `<audio>` and `<video>` elements have several properties that you can bind to. This example demonstrates a few of them.
|
||||||
|
|
||||||
|
On line 116, add `currentTime={time}`, `duration` and `paused` bindings:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<video
|
||||||
|
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg"
|
||||||
|
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4"
|
||||||
|
on:mousemove={handleMousemove}
|
||||||
|
on:mousedown={handleMousedown}
|
||||||
|
bind:currentTime={time}
|
||||||
|
bind:duration
|
||||||
|
bind:paused
|
||||||
|
></video>
|
||||||
|
```
|
||||||
|
|
||||||
|
> `bind:duration` is equivalent to `bind:duration={duration}`
|
||||||
|
|
||||||
|
Now, when you click on the video, it will update `time`, `duration` and `paused` as appropriate. This means we can use them to build custom controls.
|
||||||
|
|
||||||
|
> Ordinarily on the web, you would track `currentTime` by listening for `timeupdate` events. But these events fire too infrequently, resulting in choppy UI. Svelte does better — it checks `currentTime` using `requestAnimationFrame`.
|
||||||
|
|
||||||
|
The complete set of bindings for `<audio>` and `<video>` is as follows — four *readonly* bindings...
|
||||||
|
|
||||||
|
* `duration` (readonly) — the total duration of the video, in seconds
|
||||||
|
* `buffered` (readonly) — an array of `{start, end}` objects
|
||||||
|
* `seekable` (readonly) — ditto
|
||||||
|
* `played` (readonly) — ditto
|
||||||
|
|
||||||
|
...and three *two-way* bindings:
|
||||||
|
|
||||||
|
* `currentTime` — the current point in the video, in seconds
|
||||||
|
* `paused` — this one should be self-explanatory
|
||||||
|
* `volume` — a value between 0 and 1
|
Loading…
Reference in new issue