UNPKG

@jxstjh/jhvideo

Version:

HTML5 jhvideo base on MPEG2-TS Stream Player

808 lines (751 loc) 32.7 kB
import JPlayer from "../jplayer"; import {BarItemType, Direction, StreamOpt, Streamtype, ToolBarItem} from "../model/playerModel"; import { closeSvg, fullScreenSvg, settingSvg, refreshSvg, screenshotSvg, recordSvg, ptzSvg, zoomSvg, speedRightSvg, speedLeftSvg, streamSpeedIconMap, refreshSvgIcon, ptzScreenshot, ptzRecord, ptzTogVod, mobildSliderRecordIcon, mobildSliderShootIcon, rectangleSvg, callOnSvg, audioOnSvg } from './icons' function creatToolBarItem(playIns: JPlayer, barItem: ToolBarItem, prefixName = 'JPlayer') { const {type, label, icon, cmd, className, cb} = barItem const item = document.createElement('div') className && (item.className = className) // barItem.tip && (item.title = barItem.tip) if (barItem.tip) { item.classList.add('css-tooltip', 'poptip--top') item.setAttribute('aria-controls', barItem.tip) } item.classList.add(`${prefixName}-tool-item`, `${prefixName}-${type}`) cmd && (item.setAttribute('data-cmd', cmd)) if (type === BarItemType.LABEL) { label && (item.innerText = label) } else if (type === BarItemType.BTN) { icon && (item.innerHTML = icon) } cb && (item.addEventListener('click', cb.bind(playIns))) if (cmd === 'record') { const child: HTMLSpanElement = document.createElement('span') child.className = 'record-child' item.appendChild(child) } return item } function creatToolToogleItem(playIns: JPlayer, streamOpt: StreamOpt) { const {vod} = streamOpt const item = document.createElement('div') item.classList.add('tool-item', 'left',) const div = document.createElement('div') div.classList.add('toogle-vod') for (let index = 1; index >= 0; index--) { const span = document.createElement('span') span.classList.add('toogle-vod-item') span.innerText = index ? '前端存储' : '中心存储' const cmd = 'toogleVodOrigin' span.setAttribute('data-cmd', cmd) span.setAttribute('data-value', String(index)) span.addEventListener('click', function (e) { playIns.toggleVodOrigin(e) }) div.appendChild(span) } if (vod === 0) { (div.children[1].classList.add('active')) } else { (div.children[0].classList.add('active')) } item.appendChild(div) return item } function creatToolSpeedItem(playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer') { const {vod} = streamOpt const item = document.createElement('div') item.classList.add(`${prefixName}-tool-item`, 'left',) const div = document.createElement('div') div.classList.add('stream-speed') const speedRight = document.createElement('i') speedRight.addEventListener('click', function (e) { playIns._vodPlayer.addStreamSpeed() }) speedRight.classList.add('stream-speed-item', 'stream-speed-add') speedRight.innerHTML = speedRightSvg const speedLeft = document.createElement('i') speedLeft.classList.add('stream-speed-item', 'stream-speed-reduce') speedLeft.addEventListener('click', function (e) { playIns._vodPlayer.reduceStreamSpeed() }) speedLeft.innerHTML = speedLeftSvg const txt = document.createElement('span') txt.classList.add('stream-speed-text') const mockSpeed = 0 txt.innerHTML = streamSpeedIconMap(mockSpeed) div.appendChild(speedLeft) div.appendChild(txt) div.appendChild(speedRight) item.appendChild(div) return item } const creatHeaderToolBar = function (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer', isMobile: boolean = false): HTMLElement { const {isptz, headerToolBar, title, protocolType} = streamOpt const header = document.createElement('div') header.className = `${prefixName}-toolbar ${prefixName}-header` header.appendChild(creatToolBarItem(playIns, { type: BarItemType.LABEL, label: title, className: `${prefixName}-title` })) // 创建title if (protocolType !== 'hls') { header.appendChild(creatToolBarItem(playIns, { type: BarItemType.LABEL, label: '0/kbs', className: `${prefixName}-speed left` })) // 创建speed } header.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: closeSvg, cmd: 'close', className: `${prefixName}-close right`, cb: function (e) { if (this._isFullScreen) { this.setFullScreen(false) } else { this.close() } } })) // 创建关闭按钮 // // 移动模式下 创建刷新按钮 // if (isMobile) { // header.appendChild(creatToolBarItem(playIns, { // type: BarItemType.BTN, // icon: refreshSvg, // cmd: 'refresh', // className: 'refresh right', // tip: '刷新', // cb: function (e) { // this.refresh() // } // })) // 创建刷新按钮 // } if (Array.isArray(headerToolBar) && headerToolBar.length > 0) { headerToolBar.forEach(function (item) { creatToolBarItem(playIns, item) }) } return header } const creatJoystickToolBar = function (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer', isMobile: boolean = false): HTMLDivElement { const {isptz, headerToolBar, title} = streamOpt const joystick = document.createElement('div') joystick.className = prefixName + '-toolbar joystick' return joystick } // const creatProcessToolBar = (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer') => { // const process = document.createElement('div') // process.className = `${prefixName}-toolbar ${prefixName}-process` // const timeLine = document.createElement("canvas"); // timeLine.id = `${prefixName}-time-line` // // const offsetBar = document.createElement('div') // // offsetBar.className = 'offset-bar' // // const offsetPoint = document.createElement('div') // // offsetPoint.className = 'offset-point' // // process.appendChild(offsetPoint) // // const tooltip = document.createElement('div') // // tooltip.className = 'process-tool-tip' // // tooltip.innerText = '00:00:00' // // process.appendChild(tooltip) // process.appendChild(timeLine) // return process // } const creatToolTimerItem = (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer') => { const clock = document.createElement('div') clock.className = `${prefixName}-tool-item left btn time-clock` const currentTime = document.createElement('span') currentTime.className = 'time-clock-item current' const separate = document.createElement('span') // separate.className = 'time-clock-separate' // separate.innerText = '/' // const totalTime = document.createElement('span') // totalTime.className = 'time-clock-item total' clock.appendChild(currentTime) clock.appendChild(separate) // clock.appendChild(totalTime) return clock } const creatToolPickerItem = (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer') => { const picker = document.createElement('div') picker.className = `${prefixName}-tool-item left btn picker` const range = document.createElement('input') range.className = 'time-clock-item range' range.readOnly = true; picker.appendChild(range) return picker } const creatFooterToolBar = function (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer'): HTMLElement { const {isptz, footerToolBar, streamtype, isDraw,isTalk} = streamOpt const isVod = streamtype === 'vod' const footer = document.createElement('div') footer.className = `${prefixName}-toolbar ${prefixName}-footer` footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: fullScreenSvg, cmd: 'fullScreen', className: 'fullScreen', tip: '全屏', cb: function (e) { this.setFullScreen(!this.isFullScreen) } })) // 创建全屏按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: settingSvg, cmd: 'setting', className: 'setting', tip: '设置', cb: function (e) { this.toggleSetting() } })) // 创建设置按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: `<div class="${prefixName}-play-button ${prefixName}-svg-icon"></div>`, cmd: 'playing', tip: '播放/暂停', className: 'playing left', cb: function (e) { this.playing ? (this.pause()) : (this.play()) } })) // 创建播放按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: refreshSvg, cmd: 'refresh', className: 'refresh left', tip: '刷新', cb: function (e) { this.refresh() } })) // 创建刷新按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: audioOnSvg, cmd: 'call', className: 'jh-audio-change', tip: '已关闭声音', cb: function (e) { this._audioCtrl.setState(e) } })) // 音频按钮 if (isVod) { // 录像模式下 footer.appendChild(creatToolTimerItem(playIns, streamOpt, prefixName)) } // 创建时间指示器 if (isVod) { // 录像模式下 footer.appendChild(creatToolSpeedItem(playIns, streamOpt, prefixName)) } // 创建倍速控制器 // TODO:换饿了 const _record = false if(_record){ footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: recordSvg, cmd: 'record', className: 'record', tip: '录像', cb: function (e) { this.record() } })) } // 创建录像按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: screenshotSvg, cmd: 'screenshot', className: 'screenshot', tip: '截图', cb: function (e) { this.screenshot() } })) // 创建截图按钮 if (isptz && !isVod) { footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: ptzSvg, cmd: 'ptz', className: 'ptz', tip: '云控', cb: function (e) { this.togglePtz() } })) // 创建云台控制 } footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: zoomSvg, cmd: 'zoom', className: 'zoom', tip: '数码放大', cb: function (e) { this.toggleZoom() } })) // 创建数码放大 if (isDraw) { footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: rectangleSvg, cmd: 'rectangle', className: 'rectangle', tip: '绘制矩形', cb: function (e) { this.toggleDraw(e) } })) // 绘制矩形按钮 } if(isTalk && streamtype==='live'){ footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: callOnSvg, cmd: 'talk', className: 'jh-talk-btn', tip: '喊话', cb: function (e) { this._talkCtrl.init() } })) } if (isVod) { // 录像模式下 footer.appendChild(creatToolPickerItem(playIns, streamOpt)) }// 创建时间指示器 return footer } const creatMobileFooterToolBar = function (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer'): HTMLElement { const {isptz, footerToolBar, streamtype} = streamOpt const isVod = streamtype === 'vod' const footer = document.createElement('div') footer.className = `${prefixName}-toolbar ${prefixName}-footer mobile` footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: fullScreenSvg, cmd: 'fullScreen', className: 'fullScreen', cb: function (e) { this.setFullScreen(!this.isFullScreen) } })) // 创建全屏按钮 // footer.appendChild(creatToolBarItem(playIns, { // type: BarItemType.BTN, // icon: settingSvg, // cmd: 'setting', // className: 'setting', // cb: function (e) { // this.toggleSetting() // } // })) // 创建设置按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: `<div class="play-button ${prefixName}-svg-icon"></div>`, cmd: 'playing', className: 'playing left', cb: function (e) { this.playing ? (this.pause()) : (this.play()) } })) // 创建播放按钮 footer.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: refreshSvg, cmd: 'refresh', className: 'refresh left', cb: function (e) { this.refresh() } })) // 创建刷新按钮 // 创建timeSlider if (isVod) { const timeSlider: HTMLCanvasElement = document.createElement('canvas') timeSlider.className = prefixName + '-timeline-slider' timeSlider.ondragstart = function () { return false } footer.appendChild(timeSlider) } return footer } const creatMobileSilderToolBar = function (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer'): HTMLElement { const {isptz, footerToolBar, streamtype} = streamOpt const isVod = streamtype === 'vod' const slider = document.createElement('div') slider.className = `${prefixName}-toolbar left mobile` slider.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: mobildSliderRecordIcon, cmd: 'record', className: 'record', cb: function (e) { this.record() } })) // 创建录像按钮 slider.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: mobildSliderShootIcon, cmd: 'screenshot', className: 'screenshot', cb: function (e) { this.screenshot() } })) // 创建截图按钮 return slider } const createSeekDom = (prefixName: string) => { const seekWarper = document.createElement('div') seekWarper.classList.add(prefixName + '-seek-wrapper') const seek = document.createElement('div') seek.classList.add('line-scale-pulse-out') for (let index = 0; index < 5; index++) { const element = document.createElement('div') seek.appendChild(element) } seekWarper.appendChild(seek) return seekWarper } const createMobileWindowDom = (prefixName: string, playIns) => { const playWarper = document.createElement('div') playWarper.classList.add(prefixName + '-mobile-btn-wrapper') const play = creatToolBarItem(playIns, { type: BarItemType.BTN, icon: `<div class="${prefixName}-play-button icon"></div>`, cmd: 'playing', className: 'playing ', cb: function (e) { this.playing ? (this.pause()) : (this.play()) } }) playWarper.appendChild(play) return playWarper } const createLoaderDom = (prefixName: string): HTMLElement => { const loader = document.createElement('div') loader.classList.add(prefixName + '-loading-wrapper') const loaderBox = document.createElement('div'); loaderBox.className = 'loader-box'; (['one', 'two', 'three']).forEach(element => { const div = document.createElement('div') div.className = 'inner ' + element loaderBox.appendChild(div) }); loader.appendChild(loaderBox) const loaderText = document.createElement('span') loaderText.className = 'loader-text'; loader.appendChild(loaderText) return loader } const createLoaderDom2 = (prefixName: string, logoPath?: string): HTMLElement => { const loader = document.createElement('div') loader.classList.add(prefixName + '-loading-wrapper') const loaderContent = document.createElement('div') loaderContent.className = 'loader-content'; // 是否加载外部logo if (logoPath) { const loaderImg = document.createElement('div') loaderImg.className = 'loader-img' const imgLabel = document.createElement('img'); imgLabel.src = logoPath loaderImg.appendChild(imgLabel) loaderContent.appendChild(loaderImg) } else { const loaderBox = document.createElement('div'); loaderBox.className = 'loader-box'; loaderContent.appendChild(loaderBox) } // 添加文字 const loaderText = document.createElement('span') loaderText.className = 'loader-text'; loaderContent.appendChild(loaderText) loader.appendChild(loaderContent) return loader } const createErrorDom = (prefixName, playIns): HTMLElement => { const error = document.createElement('div') error.classList.add(prefixName + '-error-wrapper') const errorBtnBox = document.createElement('div'); errorBtnBox.className = 'error-btn-box'; errorBtnBox.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: closeSvg, cmd: 'close', className: 'close', cb: function (e) { if (this._isFullScreen) { this.setFullScreen(false); return; } const errorBtnBox = this.el.querySelector(".error-btn-box"); if (errorBtnBox?.parentNode) { errorBtnBox.parentNode.removeChild(errorBtnBox); } this.close(); } })) // 创建关闭按钮 errorBtnBox.appendChild(creatToolBarItem(playIns, { type: BarItemType.BTN, icon: refreshSvgIcon, cmd: 'refresh', className: 'refresh', cb: function (e) { this.refresh() } })) // 创建刷新按钮 error.appendChild(errorBtnBox) const errorBox = document.createElement('div'); errorBox.className = 'error-box'; errorBox.innerHTML = ` <?xml version="1.0" encoding="UTF-8"?> <svg viewBox="0 0 52 45" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Generator: Sketch 63 (92445) - https://sketch.com --> <g stroke="none" stroke-width="1" > <g id="2-2-0历史录像" transform="translate(-1145.000000, -572.000000)" fill-rule="nonzero"> <g id="编组-3备份" transform="translate(913.000000, 430.000000)"> <g id="编组-6" transform="translate(182.000000, 134.000000)"> <g id="i无视频" transform="translate(45.175439, 0.000000)"> <rect id="矩形" opacity="0" x="0" y="0" width="60.2339181" height="60.2339181"></rect> <path d="M54.7392992,13.7440416 C53.9262668,13.2630626 52.8997108,13.2957823 51.9224294,13.8291127 L46.4332288,16.8245975 L46.4332288,11.2442596 C46.4314181,9.47047735 44.9882161,8.03299263 43.207379,8.03118908 L11.5303224,8.03118908 C9.74948531,8.03299263 8.30628332,9.47047735 8.3044726,11.2442596 L8.3044726,21.7407263 C8.3044726,22.6442547 9.03984029,23.3767093 9.94696231,23.3767093 C10.8540843,23.3767093 11.589452,22.6442547 11.589452,21.7407263 L11.5303224,11.303155 L43.1482494,11.2442596 L43.207379,39.5827565 L37.622914,39.5827565 C36.7157919,39.5827565 35.9804242,40.315211 35.9804242,41.2187394 C35.9804242,42.1222679 36.7157919,42.8547224 37.622914,42.8547224 L43.207379,42.8547224 C44.9884817,42.8520176 46.4314199,41.4140639 46.4332288,39.6400159 L46.4332288,32.4825904 L51.9207869,35.4780752 C52.4381712,35.7611003 52.9703378,35.9017948 53.4745822,35.9017948 C53.9246244,35.9017948 54.3549567,35.790548 54.7392992,35.5647823 C55.499772,35.114887 55.9366742,34.3018035 55.9366742,33.3300296 L55.9366742,15.9771583 C55.9366742,15.0070204 55.499772,14.1939369 54.7392992,13.7440416 Z M52.6516948,32.1455779 L46.4332288,28.7525493 L46.4332288,20.5562746 L52.6516948,17.163246 L52.6516948,32.1455779 L52.6516948,32.1455779 Z M19.8019006,22.7550357 C11.6518666,22.7550357 5.01949318,29.359499 5.01949318,37.4788824 C5.01949318,45.5982658 11.6518666,52.202729 19.8019006,52.202729 C27.9519345,52.202729 34.584308,45.5982658 34.584308,37.4788824 C34.584308,29.359499 27.9519345,22.7550357 19.8019006,22.7550357 Z M19.8019006,48.9307631 C13.4618903,48.9307631 8.3044726,43.7921406 8.3044726,37.4788824 C8.3044726,31.1656241 13.4618903,26.0270017 19.8019006,26.0270017 C26.1419109,26.0270017 31.2993286,31.1656241 31.2993286,37.4788824 C31.2993286,43.7921406 26.1419109,48.9307631 19.8019006,48.9307631 Z" id="形状" fill="#FFFFFF"></path> <path d="M19.4669376,41.0342315 C20.1569643,41.0342315 20.5019776,40.6253268 20.5019776,39.8075175 C20.5019776,39.5647303 20.5179504,39.3474997 20.5498961,39.1558256 C20.5818418,38.9641516 20.6521223,38.7692829 20.7607376,38.5712197 C20.8693529,38.3731565 21.0322759,38.1495368 21.2495065,37.9003605 C21.4667371,37.6511842 21.7606373,37.3477002 22.1312072,36.9899086 C22.7445642,36.3765516 23.1981929,35.8079185 23.4920931,35.2840094 C23.7859933,34.7601003 23.9329435,34.1914672 23.9329435,33.5781102 C23.9329435,32.2619482 23.5687627,31.2556594 22.8404013,30.5592436 C22.1120398,29.8628278 21.1089455,29.5146199 19.8311184,29.5146199 C18.5532912,29.5146199 17.5118621,29.9171354 16.706831,30.7221665 C15.8890216,31.5399759 15.480117,32.4727897 15.480117,33.520608 C15.480117,34.2489694 15.8506868,34.6131502 16.5918266,34.6131502 C17.2946315,34.6131502 17.6652014,34.2361912 17.7035362,33.4822731 C17.7290927,32.9839206 17.9271559,32.559043 18.2977258,32.2076406 C18.6682957,31.8562381 19.1602591,31.6805369 19.7736161,31.6805369 C20.3869732,31.6805369 20.8661583,31.8338761 21.2111717,32.1405546 C21.556185,32.4472332 21.7286917,32.8880835 21.7286917,33.4631057 C21.7286917,33.7058929 21.7127188,33.9135398 21.6807731,34.0860465 C21.6488275,34.2585531 21.578547,34.4310598 21.4699317,34.6035665 C21.3613164,34.7760731 21.2111717,34.9613581 21.0194976,35.1594213 C20.8278235,35.3574845 20.5786472,35.6034662 20.2719687,35.8973664 C18.9430285,37.2007501 18.2785584,38.5041338 18.2785584,39.8075175 C18.2785584,40.0375264 18.2913367,40.232395 18.3168932,40.3921234 C18.3424497,40.5518518 18.3967574,40.6796345 18.4798162,40.7754715 C18.5628749,40.8713086 18.6810739,40.9383945 18.8344132,40.9767293 C18.9877524,41.0150641 19.1985939,41.0342315 19.4669376,41.0342315 Z M19.3135984,45.6152418 C19.5436073,45.6152418 19.7576433,45.5705179 19.9557065,45.48107 C20.1537697,45.3916221 20.3294709,45.2702285 20.4828102,45.1168892 C20.6361495,44.96355 20.757543,44.7878487 20.8469909,44.5897855 C20.9364388,44.3917223 20.9811628,44.1776863 20.9811628,43.9476774 C20.9811628,43.7176685 20.9364388,43.5036325 20.8469909,43.3055693 C20.757543,43.1075061 20.6361495,42.9318048 20.4828102,42.7784656 C20.3294709,42.6251263 20.1537697,42.5037327 19.9557065,42.4142848 C19.7576433,42.3248369 19.5436073,42.280113 19.3135984,42.280113 C19.0835895,42.280113 18.8695534,42.3248369 18.6714902,42.4142848 C18.473427,42.5037327 18.2977258,42.6251263 18.1443865,42.7784656 C17.9910473,42.9318048 17.8696537,43.1075061 17.7802058,43.3055693 C17.6907579,43.5036325 17.646034,43.7176685 17.646034,43.9476774 C17.646034,44.1776863 17.6907579,44.3917223 17.7802058,44.5897855 C17.8696537,44.7878487 17.9910473,44.96355 18.1443865,45.1168892 C18.2977258,45.2702285 18.473427,45.3916221 18.6714902,45.48107 C18.8695534,45.5705179 19.0835895,45.6152418 19.3135984,45.6152418 Z" id="?" fill="#FFFFFF"></path> </g> </g> </g> </g> </g> </svg> ` error.appendChild(errorBox) const errorContent = document.createElement('div') errorContent.className = 'error-content'; errorContent.innerHTML = '' + '<div class="error-explain"><span class="error-explain-text"></span></div>' + '<div class="error-propose"><button class="error-propose-button">排查建议' + '<div class="error-propose-position"><div class="error-propose-scrollbar"><span class="error-propose-text"></span></div></div>' + '</button></div>' error.appendChild(errorContent) return error } const createZoomDom = (prefixName, playIns: JPlayer): [HTMLElement, HTMLCanvasElement] => { const zoom = document.createElement('div') zoom.classList.add(prefixName + '-zoom-wrapper') const canvas = document.createElement('canvas'); canvas.className = 'zoom-canvas'; zoom.appendChild(canvas) // 创建canvas return [zoom, canvas] } // 算法绘制区域 const createRectangleDom = (prefixName, playIns: JPlayer): [HTMLElement, HTMLCanvasElement] => { const rectangle = document.createElement('div') rectangle.classList.add(prefixName + '-rectangle-wrapper') const fabricDom = document.createElement('canvas') fabricDom.id = prefixName + '-rectangle-canvas' fabricDom.className = 'rectangle-canvas'; rectangle.appendChild(fabricDom) // 创建canvas return [rectangle, fabricDom] } // 算法确认框 const createDrawTipBtnDom = (prefixName, playIns: JPlayer): HTMLElement => { const div = document.createElement('div') div.classList.add(prefixName + '-draw-tip-btn') div.innerHTML = `<div class="container"> <div class="tip">双击框线可增加编辑点位,拖动点位可更改生效区域</div> <div class="btnBox"> <button class="cancel">取消</button> <button class="ok">确定</button> </div> </div>` div.addEventListener('click', function (e) { playIns.drawBtnHandle(e) }) return div } // const createSettingMenuItem = (playIns: JPlayer, label = '', children = []): HTMLElement => { const li = document.createElement('li') li.className = 'menu__list' const a = document.createElement('a') a.innerText = label a.href = 'javascript:void(0)' li.appendChild(a) const innerUl = document.createElement('ul') innerUl.className = 'menu__drop' children.forEach(r => { const innerLi = document.createElement('li') const innerA = document.createElement('a') innerA.href = 'javascript:void(0)' innerA.innerText = r.label innerA.onclick = r.fn.bind(playIns) innerLi.appendChild(innerA) innerUl.appendChild(innerLi) }) li.appendChild(innerUl) return li } const createSettingMenuDom = (playIns: JPlayer, streamOpt: StreamOpt, prefixName = 'JPlayer'): HTMLElement => { const {isptz, footerToolBar, streamtype} = streamOpt const isVod = streamtype === 'vod' const menu = document.createElement('div') menu.className = prefixName + '-toolbar side-menu' const ul = document.createElement('ul') ul.className = 'menu' // 画面比例 li start const rationList = [ { label: '原始', fn: function () { this.resetRatio() } }, { label: '充满', fn: function () { this.setFillRatio() } }, { label: '16:9', fn: function () { this.ratioAdjust(16, 9) } }, { label: '4:3', fn: function () { this.ratioAdjust(4, 3) } }, { label: '16:10', fn: function () { this.ratioAdjust(16, 10) } }, ] const rationLi = createSettingMenuItem(playIns, '画面比例', rationList) ul.appendChild(rationLi) // 画面比例 li end if (isVod) { // 录像来源 start const vodConfig = [ { label: '前端存储', fn: function () { this.toggleVodOriginForNumber(1) } }, { label: '中心存储', fn: function () { this.toggleVodOriginForNumber(0) } }, ] const vodLi = createSettingMenuItem(playIns, '存储来源', vodConfig) ul.appendChild(vodLi) // 录像来源 end } else { // 切换码流 start const liveConfig = [ { label: '主码流', fn: function () { this.switchStream(0) } }, { label: '辅码流', fn: function () { this.switchStream(1) } }, ] const liveLi = createSettingMenuItem(playIns, '切换码流', liveConfig) ul.appendChild(liveLi) // 切换码流 end } menu.appendChild(ul) return menu } const createPtzControllerDom = (playIns: JPlayer, hideTools = false, isPtz: boolean = false, streamtype: Streamtype = 'live', prefixName = 'JPlayer'): HTMLDivElement[] => { // 容器 const box = document.createElement('div') box.className = prefixName + '-ptz-controller' // 工具栏 const toolbox = document.createElement('div') toolbox.className = prefixName + '-ptz-toolbox' const btns = [ { label: '截图', icon: ptzScreenshot, className: 'screenshot', onclick: function () { this.screenshot() }.bind(playIns) }, { label: '截图', icon: ptzTogVod, className: 'vod', onclick: function () { this.toggleVod().then(r => { console.log(r) }) }.bind(playIns) }, { label: '录像', icon: ptzRecord, className: 'screenshot', onclick: function () { this.record() }.bind(playIns) }, ] btns.forEach(btn => { const div = document.createElement('div') div.className = 'toolbox-btn ' + btn.className div.setAttribute('aria-labe', btn.label) div.innerHTML = btn.icon div.onclick = btn.onclick; toolbox.appendChild(div) }) // 摇杆 const joystick = document.createElement('div') joystick.className = prefixName + '-ptz-joystick' joystick.style.position = 'relative' if (!hideTools) { box.appendChild(toolbox) } if (isPtz && streamtype === 'live') { box.appendChild(joystick) } return [box, toolbox, joystick] } export const getDirection = (ox, oy) => { if (ox === 0 || oy === 0) { return Direction.NAN } else if (ox > 0 && oy > 0) { return Direction.DR } else if (ox > 0 && oy < 0) { return Direction.TR } else if (ox < 0 && oy < 0) { return Direction.TL } else if (ox < 0 && oy > 0) { return Direction.DL } } export { createSettingMenuDom, creatMobileSilderToolBar, creatJoystickToolBar, createErrorDom, createLoaderDom, createLoaderDom2, createSeekDom, creatHeaderToolBar, creatFooterToolBar, createZoomDom, createMobileWindowDom, creatMobileFooterToolBar, createPtzControllerDom, createRectangleDom, createDrawTipBtnDom }