Skip to content

Commit e20d49a

Browse files
【fix】videomap videolayer支持播放暂停
AI-GEN: 70% Cursor
1 parent d4e526c commit e20d49a

6 files changed

Lines changed: 232 additions & 4 deletions

File tree

‎src/mapboxgl/mapping/VideoMap.js‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ const MAP_EVENTS = [
105105
* @param {number} [options.vectorUpdateInterval] - 矢量要素重投影的节流间隔,单位秒。默认等于 interval。仅当 videoParameters 为数组时生效:值越大矢量刷新越省性能但与视频背景错位越明显;设为小于 interval 无意义。
106106
* @fires VideoMap#load
107107
* @fires VideoMap#vectorupdate
108+
* @fires VideoMap#play
109+
* @fires VideoMap#pause
108110
* @extends {mapboxgl.Evented}
109111
* @usage
110112
*```
@@ -348,6 +350,35 @@ export class VideoMap extends mapboxgl.Evented {
348350
}
349351
}
350352

353+
/**
354+
* @function VideoMap.prototype.play
355+
* @description 播放视频。
356+
*/
357+
play() {
358+
if (this.videoMapLayer) {
359+
this.videoMapLayer.play();
360+
}
361+
}
362+
363+
/**
364+
* @function VideoMap.prototype.pause
365+
* @description 暂停视频。
366+
*/
367+
pause() {
368+
if (this.videoMapLayer) {
369+
this.videoMapLayer.pause();
370+
}
371+
}
372+
373+
/**
374+
* @function VideoMap.prototype.paused
375+
* @description 获取当前视频播放状态。返回 `true` 表示已暂停,返回 `false` 表示正在播放。
376+
* @returns {boolean} 视频是否暂停。
377+
*/
378+
paused() {
379+
return this.videoMapLayer ? this.videoMapLayer.paused() : true;
380+
}
381+
351382
/**
352383
* @function VideoMap.prototype.destroy
353384
* @description 销毁视频地图。
@@ -365,6 +396,20 @@ export class VideoMap extends mapboxgl.Evented {
365396

366397
_addVideoLayer(src) {
367398
this.videoMapLayer = new VideoMapLayer(this);
399+
/**
400+
* @event VideoMap#play
401+
* @description 视频开始播放时触发。
402+
*/
403+
this.videoMapLayer.on('play', () => {
404+
this.fire('play');
405+
});
406+
/**
407+
* @event VideoMap#pause
408+
* @description 视频暂停时触发。
409+
*/
410+
this.videoMapLayer.on('pause', () => {
411+
this.fire('pause');
412+
});
368413
this.videoMapLayer.add(src);
369414
this._bindEvents();
370415
}

‎src/mapboxgl/mapping/layers/VideoMapLayer.js‎

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default class VideoMapLayer extends mapboxgl.Evented {
3535
this.renderer = new VideoLayerRenderer({ url: this.address, id: this.id, loop: this.loop, autoplay: this.autoplay });
3636
this.video = this.renderer.createVideo();
3737
this.videoDomId = this.renderer.getVideoDomId();
38+
this._bindPlaybackEvents();
3839
this.video.one('firstplay', () => {
3940
if (this.autoplay) {
4041
this.play();
@@ -91,7 +92,7 @@ export default class VideoMapLayer extends mapboxgl.Evented {
9192

9293
_afterAddVideoLayer() {
9394
if (this.autoplay) {
94-
this.map.getSource(this.id).play();
95+
this.play();
9596
}
9697
this._bindTimeUpdates();
9798
this.fire('loaded', {
@@ -178,14 +179,54 @@ export default class VideoMapLayer extends mapboxgl.Evented {
178179
* @description 播放视频。
179180
*/
180181
play() {
181-
this.video.play();
182+
if (this.video) {
183+
this.video.play();
184+
}
185+
const source = this._getVideoSource();
186+
if (source && typeof source.play === 'function') {
187+
source.play();
188+
}
182189
}
183190
/**
184191
* @function VideoMapLayer.prototype.pause
185192
* @description 暂停视频。
186193
*/
187194
pause() {
188-
this.video.pause();
195+
if (this.video) {
196+
this.video.pause();
197+
}
198+
const source = this._getVideoSource();
199+
if (source && typeof source.pause === 'function') {
200+
source.pause();
201+
}
202+
}
203+
/**
204+
* @function VideoMapLayer.prototype.paused
205+
* @description 获取视频是否处于暂停状态。
206+
* @returns {boolean} 视频是否暂停。
207+
*/
208+
paused() {
209+
if (this.video && typeof this.video.paused === 'function') {
210+
return this.video.paused();
211+
}
212+
return true;
213+
}
214+
_bindPlaybackEvents() {
215+
if (!this.video) {
216+
return;
217+
}
218+
this.video.on('play', () => {
219+
this.fire('play');
220+
});
221+
this.video.on('pause', () => {
222+
this.fire('pause');
223+
});
224+
}
225+
_getVideoSource() {
226+
if (!this.map || !this.id || typeof this.map.getSource !== 'function') {
227+
return null;
228+
}
229+
return this.map.getSource(this.id) || null;
189230
}
190231
/**
191232
* @function VideoMapLayer.prototype.remove

‎src/mapboxgl/overlay/VideoLayer.js‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
* @param {number} [options.interval=0.1] 非定点视频参数间隔,单位秒,当视频参数为数组时,会根据该参数将 VideoTimeParameters.time 处理成均匀间隔的视频参数,默认为 0.1 秒,最小值为 0.001 秒。
5454
* @param {string} [options.id] - 视频图层 ID。默认使用 CommonUtil.createUniqueID("VideoLayer_") 创建专题图层 ID。
5555
* @param {Array} [options.clipRegion] -裁剪范围
56+
* @fires VideoLayer#play
57+
* @fires VideoLayer#pause
5658
* @extends {mapboxgl.Evented}
5759
* @usage
5860
* ```
@@ -116,6 +118,7 @@
116118
this.renderer = new VideoLayerRenderer({ url: this.url, id: this.layerId });
117119
this.video = this.renderer.createVideo();
118120
this.videoDomId = this.renderer.getVideoDomId();
121+
this._bindPlaybackEvents();
119122

120123
this.video.one('firstplay', () => {
121124
this.video.play();
@@ -516,5 +519,72 @@
516519
const visible = visibility ? 'visible' : 'none';
517520
this.map.setLayoutProperty(this.layerId, 'visibility', visible);
518521
}
522+
523+
/**
524+
* @function VideoLayer.prototype.play
525+
* @description 播放视频。
526+
*/
527+
play() {
528+
if (this.video) {
529+
this.video.play();
530+
}
531+
const source = this._getVideoSource();
532+
if (source && typeof source.play === 'function') {
533+
source.play();
534+
}
535+
}
536+
537+
/**
538+
* @function VideoLayer.prototype.pause
539+
* @description 暂停视频。
540+
*/
541+
pause() {
542+
if (this.video) {
543+
this.video.pause();
544+
}
545+
const source = this._getVideoSource();
546+
if (source && typeof source.pause === 'function') {
547+
source.pause();
548+
}
549+
}
550+
551+
/**
552+
* @function VideoLayer.prototype.paused
553+
* @description 获取当前视频播放状态。返回 `true` 表示已暂停,返回 `false` 表示正在播放。
554+
* @returns {boolean} 视频是否暂停。
555+
*/
556+
paused() {
557+
if (this.video && typeof this.video.paused === 'function') {
558+
return this.video.paused();
559+
}
560+
return true;
561+
}
562+
563+
_bindPlaybackEvents() {
564+
if (!this.video) {
565+
return;
566+
}
567+
/**
568+
* @event VideoLayer#play
569+
* @description 视频开始播放时触发。
570+
*/
571+
this.video.on('play', () => {
572+
this.fire('play');
573+
});
574+
/**
575+
* @event VideoLayer#pause
576+
* @description 视频暂停时触发。
577+
*/
578+
this.video.on('pause', () => {
579+
this.fire('pause');
580+
});
581+
}
582+
583+
_getVideoSource() {
584+
if (!this.map || !this.layerId || typeof this.map.getSource !== 'function') {
585+
return null;
586+
}
587+
return this.map.getSource(this.layerId) || null;
588+
}
519589
}
520590

‎test/mapboxgl/mapping/VideoMapSpec.js‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,33 @@ describe('mapboxgl_videoMap', () => {
226226
done();
227227
}, 2000);
228228
});
229+
230+
it('play pause', (done) => {
231+
var videoMap = new VideoMap({
232+
url: videoUrl,
233+
opencv: cv,
234+
videoParameters: {
235+
fovX: 84,
236+
fovY: 47,
237+
centerX: 960,
238+
centerY: 540,
239+
pitch: -20,
240+
roll: 0,
241+
yaw: 2,
242+
x: 11587478.810629973,
243+
y: 3570800.195541344,
244+
z: 154.50312
245+
}
246+
});
247+
videoMap.on('load', function () {
248+
spyOn(videoMap.videoMapLayer, 'play').and.callThrough();
249+
spyOn(videoMap.videoMapLayer, 'pause').and.callThrough();
250+
videoMap.pause();
251+
expect(videoMap.videoMapLayer.pause).toHaveBeenCalled();
252+
expect(videoMap.paused()).toBeDefined();
253+
videoMap.play();
254+
expect(videoMap.videoMapLayer.play).toHaveBeenCalled();
255+
done();
256+
});
257+
});
229258
});

‎test/mapboxgl/overlay/VideoLayerSpec.js‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,4 +387,46 @@ describe('mapboxgl_VideoLayer', () => {
387387
done();
388388
}, 3000);
389389
});
390+
391+
it('play pause', (done) => {
392+
const videoLayer = new VideoLayer({
393+
opencv: cv,
394+
url: videoUrl,
395+
clipRegion: [
396+
[0, 0],
397+
[1920, 0],
398+
[1920, 900],
399+
[0, 900]
400+
],
401+
videoParameters: {
402+
fovX: 84,
403+
fovY: 47,
404+
centerX: 960,
405+
centerY: 540,
406+
pitch: -20,
407+
roll: 0,
408+
yaw: 2,
409+
x: 11587478.810629973,
410+
y: 3570800.195541344,
411+
z: 154.50312
412+
},
413+
extent: [
414+
[116.14394400766855, 28.249134537249257],
415+
[116.143464581289, 28.252977295834056],
416+
[116.14734767029731, 28.251762901914655],
417+
[116.14737169684759, 28.25095489453961]
418+
]
419+
});
420+
videoLayer.onAdd(map);
421+
setTimeout(() => {
422+
spyOn(videoLayer.video, 'play').and.callThrough();
423+
spyOn(videoLayer.video, 'pause').and.callThrough();
424+
videoLayer.pause();
425+
expect(videoLayer.video.pause).toHaveBeenCalled();
426+
expect(videoLayer.paused()).toBeDefined();
427+
videoLayer.play();
428+
expect(videoLayer.video.play).toHaveBeenCalled();
429+
done();
430+
}, 3000);
431+
});
390432
});

‎test/tool/mock_mapboxgl_map.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ const Map = function (options) {
174174
if (sourceInfo && sourceInfo.type === 'video') {
175175
return {
176176
setCoordinates: function () {},
177-
play: function () {}
177+
play: function () {},
178+
pause: function () {}
178179
};
179180
}
180181
if (sourceInfo && sourceInfo.type === 'geojson') {

0 commit comments

Comments
 (0)