Add new class L.VideoOverlay (#4988)
* Add VideoOverlay class based on ImageOverlay * Make linter happy * Move VideoOverlay include to layer/index * Fix mapbox tokens
This commit is contained in:
parent
79ab486dde
commit
61ff641951
@ -12,6 +12,7 @@ This file just defines the order of the classes in the docs.
|
||||
@class TileLayer
|
||||
@class TileLayer.WMS
|
||||
@class ImageOverlay
|
||||
@class VideoOverlay
|
||||
|
||||
@class Path
|
||||
@class Polyline
|
||||
|
@ -50,6 +50,7 @@
|
||||
<li><a href="#tilelayer">TileLayer</a></li>
|
||||
<li><a href="#tilelayer-wms">TileLayer.WMS</a></li>
|
||||
<li><a href="#imageoverlay">ImageOverlay</a></li>
|
||||
<li><a href="#videooverlay">VideoOverlay</a></li>
|
||||
</ul>
|
||||
<h4>Vector Layers</h4>
|
||||
<ul>
|
||||
|
79
debug/map/videooverlay.html
Normal file
79
debug/map/videooverlay.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet debug page</title>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
|
||||
<script type="text/javascript" src="../../build/deps.js"></script>
|
||||
<script src="../leaflet-include.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map" style='width:750px; height: 450px;'></div>
|
||||
<button id="populate">Populate with 10 markers</button>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var map = L.map('map');
|
||||
|
||||
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
|
||||
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
|
||||
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||||
id: 'mapbox.satellite'
|
||||
}).addTo(map);
|
||||
|
||||
var videoUrls = [
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.mp4'
|
||||
],
|
||||
bounds = L.latLngBounds([[ 32, -130], [ 13, -100]]);
|
||||
|
||||
map.fitBounds(bounds);
|
||||
|
||||
var overlay = L.videoOverlay(videoUrls, bounds, {
|
||||
opacity: 0.8,
|
||||
interactive: true,
|
||||
autoplay: false
|
||||
});
|
||||
map.addLayer(overlay);
|
||||
|
||||
overlay.on('dblclick',function (e) {
|
||||
console.log('Double click on image.');
|
||||
});
|
||||
|
||||
overlay.on('load', function () {
|
||||
var MyPauseControl = L.Control.extend({
|
||||
onAdd: function() {
|
||||
var button = L.DomUtil.create('button');
|
||||
button.innerHTML = '⏸';
|
||||
L.DomEvent.on(button, 'click', function () {
|
||||
overlay.getElement().pause();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
});
|
||||
var MyPlayControl = L.Control.extend({
|
||||
onAdd: function() {
|
||||
var button = L.DomUtil.create('button');
|
||||
button.innerHTML = '⏵';
|
||||
L.DomEvent.on(button, 'click', function () {
|
||||
overlay.getElement().play();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
});
|
||||
|
||||
var pauseControl = (new MyPauseControl()).addTo(map);
|
||||
var playControl = (new MyPlayControl()).addTo(map);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -88,8 +88,14 @@ description="How the default map panes work to display overlays on top of tiles,
|
||||
%}
|
||||
|
||||
|
||||
=======
|
||||
{% include tutorial_link.html
|
||||
page="video-overlay/"
|
||||
thumbnail="video-overlay/thumbnail.gif"
|
||||
title="Showing video files"
|
||||
description="Leaflet can help you display videos somewhere on the map."
|
||||
%}
|
||||
|
||||
***
|
||||
|
||||
The following tutorials cover how to create plugins for Leaflet, and are intended only for developers experienced in Javascript:
|
||||
|
||||
|
23
docs/examples/video-overlay/example-bounds.md
Normal file
23
docs/examples/video-overlay/example-bounds.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
layout: tutorial_frame
|
||||
title: Video Overlay Tutorial
|
||||
---
|
||||
<script>
|
||||
var map = L.map('map');
|
||||
|
||||
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
|
||||
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
|
||||
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||||
id: 'mapbox.satellite'
|
||||
}).addTo(map);
|
||||
|
||||
bounds = L.latLngBounds([[ 32, -130], [ 13, -100]]);
|
||||
|
||||
L.rectangle(bounds).addTo(map);
|
||||
|
||||
map.fitBounds(bounds);
|
||||
|
||||
</script>
|
||||
|
31
docs/examples/video-overlay/example-nocontrols.md
Normal file
31
docs/examples/video-overlay/example-nocontrols.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
layout: tutorial_frame
|
||||
title: Video Overlay Tutorial
|
||||
---
|
||||
<script>
|
||||
var map = L.map('map');
|
||||
|
||||
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
|
||||
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
|
||||
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||||
id: 'mapbox.satellite'
|
||||
}).addTo(map);
|
||||
|
||||
var videoUrls = [
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.mp4'
|
||||
],
|
||||
bounds = L.latLngBounds([[ 32, -130], [ 13, -100]]);
|
||||
|
||||
map.fitBounds(bounds);
|
||||
|
||||
var overlay = L.videoOverlay(videoUrls, bounds, {
|
||||
opacity: 0.8,
|
||||
interactive: true
|
||||
});
|
||||
map.addLayer(overlay);
|
||||
|
||||
</script>
|
||||
|
58
docs/examples/video-overlay/example.md
Normal file
58
docs/examples/video-overlay/example.md
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
layout: tutorial_frame
|
||||
title: Video Overlay Tutorial
|
||||
---
|
||||
<script>
|
||||
var map = L.map('map');
|
||||
|
||||
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
|
||||
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
|
||||
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||||
id: 'mapbox.satellite'
|
||||
}).addTo(map);
|
||||
|
||||
var videoUrls = [
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.mp4'
|
||||
],
|
||||
bounds = L.latLngBounds([[ 32, -130], [ 13, -100]]);
|
||||
|
||||
map.fitBounds(bounds);
|
||||
|
||||
var overlay = L.videoOverlay(videoUrls, bounds, {
|
||||
opacity: 0.8,
|
||||
interactive: false,
|
||||
autoplay: false
|
||||
});
|
||||
map.addLayer(overlay);
|
||||
|
||||
overlay.on('load', function () {
|
||||
var MyPauseControl = L.Control.extend({
|
||||
onAdd: function() {
|
||||
var button = L.DomUtil.create('button');
|
||||
button.innerHTML = '⏸';
|
||||
L.DomEvent.on(button, 'click', function () {
|
||||
overlay.getElement().pause();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
});
|
||||
var MyPlayControl = L.Control.extend({
|
||||
onAdd: function() {
|
||||
var button = L.DomUtil.create('button');
|
||||
button.innerHTML = '⏵';
|
||||
L.DomEvent.on(button, 'click', function () {
|
||||
overlay.getElement().play();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
});
|
||||
|
||||
var pauseControl = (new MyPauseControl()).addTo(map);
|
||||
var playControl = (new MyPlayControl()).addTo(map);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
122
docs/examples/video-overlay/index.md
Normal file
122
docs/examples/video-overlay/index.md
Normal file
@ -0,0 +1,122 @@
|
||||
---
|
||||
layout: tutorial_v2
|
||||
title: Leaflet on Mobile
|
||||
---
|
||||
|
||||
## Video on webpages
|
||||
|
||||
Video used to be a hard task when building a webpage, until the [`<video>` HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video) was made available.
|
||||
|
||||
Nowadays, we can use the following HTML code:
|
||||
|
||||
<video width="500" controls>
|
||||
<source src="https://www.mapbox.com/bites/00188/patricia_nasa.webm" type="video/webm">
|
||||
<source src="https://www.mapbox.com/bites/00188/patricia_nasa.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
To display this video:
|
||||
|
||||
<video width="500" controls>
|
||||
<source src="https://www.mapbox.com/bites/00188/patricia_nasa.webm" type="video/webm">
|
||||
<source src="https://www.mapbox.com/bites/00188/patricia_nasa.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
If a video can be shown in a webpage in this way, then Leaflet can display it inside a map. It is important that the videos are prepared in such a way that they will fit the map: The video should have a "north-up" orientation, and its proportions should fit the map. If not, it will look out of place.
|
||||
|
||||
### Bounds of an image overlay
|
||||
|
||||
First of all, create a Leaflet map and add a background `L.TileLayer` in the usual way:
|
||||
|
||||
var map = L.map('map').setView([37.8, -96], 4);
|
||||
|
||||
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=' + mapboxAccessToken, {
|
||||
id: 'mapbox.satellite',
|
||||
attribution: ...
|
||||
}).addTo(map);
|
||||
|
||||
Then, we'll define the geographical bounds that the video will cover. This is an instance of [`L.LatLngBounds`](../../reference.html#latlngbounds), which is a rectangular shape:
|
||||
|
||||
var bounds = L.latLngBounds([[ 32, -130], [ 13, -100]]);
|
||||
|
||||
If you want to see the area covered by a `LatLngBounds`, use a [`L.Rectangle`]((../../reference.html#latlngbounds)):
|
||||
|
||||
L.rectangle(bounds).addTo(map);
|
||||
|
||||
map.fitBounds(bounds);
|
||||
|
||||
{% include frame.html url="example-bounds.html" %}
|
||||
|
||||
|
||||
### Adding the video overlay
|
||||
|
||||
Adding a video overlay works very similar to adding a image overlay. For just one image, [`L.ImageOverlay`s](../../reference.html#imageoverlay) is used like this:
|
||||
|
||||
var overlay = L.imageOverlay( imageUrl, bounds, options );
|
||||
|
||||
For a video overlay, just:
|
||||
|
||||
* Use `L.videoOverlay` instead of `L.imageOverlay`
|
||||
* Instead of the image URL, specify one video URL *or* an array of video URLs
|
||||
|
||||
```
|
||||
var videoUrls = [
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
|
||||
'https://www.mapbox.com/bites/00188/patricia_nasa.mp4'
|
||||
];
|
||||
|
||||
var bounds = L.latLngBounds([[ 32, -130], [ 13, -100]]);
|
||||
|
||||
var videoOverlay = L.videoOverlay( videoUrls, bounds, {
|
||||
opacity: 0.8
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
And just like that, you'll get the video on your map:
|
||||
|
||||
{% include frame.html url="example-nocontrols.html" %}
|
||||
|
||||
|
||||
Video overlays behave like any other Leaflet layer - you can add and remove them, let the user select from several videos using a [layers control](../layers-control/), etc.
|
||||
|
||||
|
||||
### A bit of control over the video
|
||||
|
||||
If you read the API documentation, you'll notice that the `L.VideoOverlay` class does not have a `play()` or `pause()` method.
|
||||
|
||||
For this, the `getElement()` method of the video overlay is useful. It returns the [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement) (which inherits from [`HTMLMediaElement`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement)) for the overlay - and that has methods like `play()` and `pause()`, e.g.
|
||||
|
||||
```
|
||||
videoOverlay.getElement().pause();
|
||||
```
|
||||
|
||||
This allows us to build custom interfaces. For example, we can build a small subclass of `L.Control` to play/pause this video overlay once it's loaded:
|
||||
|
||||
```
|
||||
videoOverlay.on('load', function () {
|
||||
var MyPauseControl = L.Control.extend({
|
||||
onAdd: function() {
|
||||
var button = L.DomUtil.create('button');
|
||||
button.innerHTML = '⏸';
|
||||
L.DomEvent.on(button, 'click', function () {
|
||||
videoOverlay.getElement().pause();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
});
|
||||
var MyPlayControl = L.Control.extend({
|
||||
onAdd: function() {
|
||||
var button = L.DomUtil.create('button');
|
||||
button.innerHTML = '⏵';
|
||||
L.DomEvent.on(button, 'click', function () {
|
||||
videoOverlay.getElement().play();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
});
|
||||
|
||||
var pauseControl = (new MyPauseControl()).addTo(map);
|
||||
var playControl = (new MyPlayControl()).addTo(map);
|
||||
});
|
||||
```
|
||||
|
||||
{% include frame.html url="example.html" %}
|
BIN
docs/examples/video-overlay/thumbnail.gif
Normal file
BIN
docs/examples/video-overlay/thumbnail.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 381 KiB |
@ -168,7 +168,8 @@ export var ImageOverlay = Layer.extend({
|
||||
},
|
||||
|
||||
// @method getElement(): HTMLElement
|
||||
// Get the img element that represents the ImageOverlay on the map
|
||||
// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
|
||||
// used by this overlay.
|
||||
getElement: function () {
|
||||
return this._image;
|
||||
},
|
||||
|
69
src/layer/VideoOverlay.js
Normal file
69
src/layer/VideoOverlay.js
Normal file
@ -0,0 +1,69 @@
|
||||
import {ImageOverlay} from './ImageOverlay';
|
||||
|
||||
/*
|
||||
* @class VideoOverlay
|
||||
* @aka L.VideoOverlay
|
||||
* @inherits ImageOverlay
|
||||
*
|
||||
* Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.
|
||||
*
|
||||
* A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)
|
||||
* HTML5 element.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```js
|
||||
* var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
|
||||
* imageBounds = [[ 32, -130], [ 13, -100]];
|
||||
* L.imageOverlay(imageUrl, imageBounds).addTo(map);
|
||||
* ```
|
||||
*/
|
||||
|
||||
export var VideoOverlay = ImageOverlay.extend({
|
||||
|
||||
// @section
|
||||
// @aka VideoOverlay options
|
||||
options: {
|
||||
// @option autoplay: Boolean = true
|
||||
// Whether the video starts playing automatically when loaded.
|
||||
autoplay: true,
|
||||
|
||||
// @option loop: Boolean = true
|
||||
// Whether the video will loop back to the beginning when played.
|
||||
loop: true
|
||||
},
|
||||
|
||||
_initImage: function () {
|
||||
var vid = this._image = L.DomUtil.create('video',
|
||||
'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : ''));
|
||||
|
||||
vid.onselectstart = L.Util.falseFn;
|
||||
vid.onmousemove = L.Util.falseFn;
|
||||
|
||||
// @event load: Event
|
||||
// Fired when the video has finished loading the first frame
|
||||
vid.onloadeddata = L.bind(this.fire, this, 'load');
|
||||
|
||||
if (!L.Util.isArray(this._url)) { this._url = [this._url]; }
|
||||
|
||||
vid.autoplay = !!this.options.autoplay;
|
||||
vid.loop = !!this.options.loop;
|
||||
for (var i = 0; i < this._url.length; i++) {
|
||||
var source = L.DomUtil.create('source');
|
||||
source.src = this._url[i];
|
||||
vid.appendChild(source);
|
||||
}
|
||||
}
|
||||
|
||||
// @method getElement(): HTMLVideoElement
|
||||
// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)
|
||||
// used by this overlay.
|
||||
});
|
||||
|
||||
|
||||
// @factory L.videoOverlay(videoUrl: String|Array, bounds: LatLngBounds, options?: VideoOverlay options)
|
||||
// Instantiates an image overlay object given the URL of the video (or array of URLs) and the
|
||||
// geographical bounds it is tied to.
|
||||
export function videoOverlay(url, bounds, options) {
|
||||
return new L.VideoOverlay(url, bounds, options);
|
||||
}
|
@ -12,6 +12,7 @@ GeoJSON.asFeature = asFeature;
|
||||
export {GeoJSON, geoJSON, geoJson};
|
||||
|
||||
export {ImageOverlay, imageOverlay} from './ImageOverlay';
|
||||
export {VideoOverlay, videoOverlay} from './VideoOverlay';
|
||||
|
||||
export {DivOverlay} from './DivOverlay';
|
||||
export {Popup, popup} from './Popup';
|
||||
|
Loading…
Reference in New Issue
Block a user