import useWorker from "../lib/omnimatrix-video-player/omnimatrix-video-player.js"; import FingerprintJS from "../lib/FingerprintJS/fingerprint.min.js"; /** * function useWorker(url: string, className: string, device: string, callback?: Function): any @param url — wss连接地址 wss://origin/VideoShow/Common?UUID=uuid&DeviceID=deviceID&Token=token @param className — 选择器 .video-class | #video-class ... @param device — 设备ID @param callback — 画面渲染完成时的回调 @returns — 包含两个Web Worker和一个关闭函数的对象 */ /** * @returns Promise * @description 获取指纹 */ function getFingerprint() { return new Promise((resolve, reject) => { // Get the visitor identifier when you need it. FingerprintJS.load() .then((fp) => fp.get()) .then((result) => { // This is the visitor identifier: const visitorId = result.visitorId; resolve(visitorId); }) .catch(reject); }); } // 格式化时间 function dateFormat(oDate, fmt) { var o = { "M+": oDate.getMonth() + 1, //月份 "d+": oDate.getDate(), //日 "h+": oDate.getHours(), //小时 "m+": oDate.getMinutes(), //分 "s+": oDate.getSeconds(), //秒 "q+": Math.floor((oDate.getMonth() + 3) / 3), //季度 S: oDate.getMilliseconds(), //毫秒 }; if (/(y+)/.test(fmt)) { fmt = fmt.replace( RegExp.$1, (oDate.getFullYear() + "").substr(4 - RegExp.$1.length) ); } for (var k in o) { if (new RegExp("(" + k + ")").test(fmt)) { fmt = fmt.replace( RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length) ); } } return fmt; } // 显示回调信息 function showCBInfo(szInfo) { szInfo = "
" + dateFormat(new Date(), "yyyy-MM-dd hh:mm:ss") + " " + szInfo + "
"; $("#cbinfo").html(szInfo + $("#cbinfo").html()); } /** * 获取ws连接地址 * @returns */ function getAddress(type = "Full", params = { X: 0, Y: 0 }) { return `wss://${$("#Ip").val()}/VideoShow/Preview/${type}/Main?X=${ params.X }&Y=${params.Y}`; } /** * 重置画布 * @param {String} selector ——选择器 */ function resetVideo(selector) { let parent = $(selector).parent(); $(selector).remove(); parent.append( `` ); } /** * * @param {String} selector ——选择器 * @returns */ function getRatio(selector) { return { ratioX: $(selector).width() / $(selector).attr("width"), ratioY: $(selector).height() / $(selector).attr("height"), width: $(selector).width(), baseWidth: $(selector).attr("width"), baseHeight: $(selector).attr("height"), }; } /** * 用于请求 * @param {String} url ——请求地址 * @param {String} method ——请求方式 * @param {Object} data ——请求参数 * @returns Promise */ function request(url, method = "GET", data = {}) { return new Promise((resolve, reject) => { $.ajax({ type: method, url, data, dataType: "json", timeout: 15000, success: function (response) { resolve(response); }, error: function (error) { reject(error); }, }); }); } // 滚轮缩放、放大逻辑 function enableImageManipulation(containerId, imageId, options = {}) { const container = document.querySelector(containerId); const image = document.querySelector(imageId); let isDragging = false; let startX, startY, initialX = 0, initialY = 0, scale = 1; let currentX = 0, currentY = 0, targetX = 0, targetY = 0; // 配置选项: 最小和最大缩放比例,是否启用缩放和拖动功能 const minScale = options.minScale || container.offsetWidth / image.width; const maxScale = options.maxScale || 3; const dragSpeed = options.dragSpeed || 0.2; const enableZoom = options.enableZoom !== false; // 默认启用缩放 const enableDrag = options.enableDrag !== false; // 默认启用拖动 // 处理缩放功能 if (enableZoom) { container.addEventListener("wheel", function (event) { event.preventDefault(); const { offsetX, offsetY } = event; const delta = Math.sign(event.deltaY) * -0.1; const newScale = Math.min(Math.max(scale + delta, minScale), maxScale); const dx = (offsetX - currentX) * (newScale / scale - 1); const dy = (offsetY - currentY) * (newScale / scale - 1); scale = newScale; currentX -= dx; currentY -= dy; updateImageTransform(); adjustPosition(); }); } // 处理拖动功能 if (enableDrag) { image.addEventListener("mousedown", function (event) { isDragging = true; startX = event.clientX; startY = event.clientY; const transform = image.style.transform.match(/translate\(([^)]+)\)/); [initialX, initialY] = transform ? transform[1].split(",").map(parseFloat) : [0, 0]; }); document.addEventListener("mousemove", function (event) { if (isDragging) { const dx = event.clientX - startX; const dy = event.clientY - startY; targetX = initialX + dx; targetY = initialY + dy; requestAnimationFrame(updateDrag); } }); function reset() { isDragging = false; } document.addEventListener("mouseleave", reset); document.addEventListener("mouseup", reset); } // 更新拖动的图像位置 function updateDrag() { if (!isDragging) return; currentX += (targetX - currentX) * dragSpeed; currentY += (targetY - currentY) * dragSpeed; updateImageTransform(); adjustPosition(); requestAnimationFrame(updateDrag); } // 更新图像的变换样式 function updateImageTransform() { image.style.transform = `translate(${currentX}px, ${currentY}px) scale(${scale})`; } // 调整图像位置以限制在容器内 function adjustPosition() { const rect = image.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); let newX = rect.left - containerRect.left; let newY = rect.top - containerRect.top; if (rect.width < containerRect.width) { newX = (containerRect.width - rect.width) / 2; } else { if (newX > 0) newX = 0; if (newX + rect.width < containerRect.width) newX = containerRect.width - rect.width; } if (rect.height < containerRect.height) { newY = (containerRect.height - rect.height) / 2; } else { if (newY > 0) newY = 0; if (newY + rect.height < containerRect.height) newY = containerRect.height - rect.height; } currentX = newX; currentY = newY; updateImageTransform(); } return () => { isDragging = false; startX = 0; startY = 0; initialX = 0; initialY = 0; scale = 1; currentX = 0; currentY = 0; targetX = 0; targetY = 0; }; } // 全屏方法 function fullScreenDisplay(dom) { /* 全屏操作的主要方法和属性 * 不同浏览器需要添加不同的前缀 * chrome:webkit   firefox:moz   ie:ms   opera:o * 1.requestFullScreen():开启全屏显示 * 2.cancelFullScreen():退出全屏显示:在不同的浏览器下退出全屏只能使用document来实现 * 3.fullScreenElement:是否是全屏状态,也只能使用document进行判断 */ // 判断是否全屏,全屏则退出,非全屏则全屏 if ( document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement ) { if (document.cancelFullScreen) { document.cancelFullScreen(); } else if (document.webkitCancelFullScreen) { document.webkitCancelFullScreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.msCancelFullScreen) { document.msCancelFullScreen(); } } else { dom .requestFullscreen() .then(() => { // 进入全屏成功 }) .catch(() => { // 进入全屏失败 }); } } const workerObj = {}; // 视频线程对象 const partObj = {}; // 获取的细节对象 let partActive = 1; // 细节框选中 let stateObj = { qj: false, part1: false, part2: false, }; // 全景录像状态 let partXY = {}; //双击全景的x y let resetSF = null; $(async function () { // const fingerprint = await getFingerprint(); $("#controlgroup").controlgroup(); $("button").button(); $.each($("#controlgroup > input"), function (k, v) { $(v).on("input", async () => { $("#wsUrl").text(getAddress()); }); }); function jt(worker) { worker && worker.postMessage({ type: "jt" }); } function lx(WebSocketWork, type) { stateObj[type] = !stateObj[type]; if (type === "qj") { stateObj[type] ? showCBInfo(`全景开始录像`) : showCBInfo(`全景结束录像`); } else { stateObj[type] ? showCBInfo(`细节开始录像`) : showCBInfo(`细节结束录像`); } WebSocketWork && WebSocketWork.postMessage({ type: "lx", lx: stateObj[type], }); } $("#wsUrl").text(getAddress()); $(".play-btn-qj").click(function () { showCBInfo("全景播放"); if (workerObj["qj"]) { $(".close-btn-qj").click(); } let [ip = ""] = [$("#Ip").val()]; if (!ip) { alert("请完善全局配置"); return; } $(".video-tip").show(); workerObj["qj"] = useWorker(getAddress(), "#video-demo", null, () => { showCBInfo("全景播放完成"); $(".video-tip").hide(); }); function jtClick() { showCBInfo(`全景开始截图`); jt(workerObj["qj"].worker); } function lxClick() { lx(workerObj["qj"].WebSocketWork, "qj"); $(this).toggleClass("lx-style"); } // 关闭 $(".close-btn-qj").click(() => { if (!workerObj["qj"]) return; $(".jt-btn-qj").off("click"); $(".lx-btn-qj").off("click"); workerObj["qj"].close(); resetVideo("#video-demo"); workerObj["qj"] = null; showCBInfo(`全景关闭`); }); // 截屏 $(".jt-btn-qj").click(jtClick); // 录像 $(".lx-btn-qj").click(lxClick); // 双击全景 $(".panorama-box #video-demo").on("dblclick", function (e) { showCBInfo("细节播放"); if (!workerObj["qj"]) return; const closePart = (index) => { if (!workerObj["part" + index]) return; workerObj["part" + index].close(); resetVideo(`#video-demo${index}`); workerObj["part" + index] = null; showCBInfo(`关闭细节${partActive}`); }; const { ratioX, ratioY, baseWidth, baseHeight } = getRatio( ".panorama-box #video-demo" ); const mouseX = e.offsetX; const mouseY = e.offsetY; console.log("双击全景", mouseX, mouseY); const params = { X: `${mouseX / ratioX > baseWidth ? baseWidth : mouseX / ratioX}`, Y: `${mouseY / ratioY > baseHeight ? baseHeight : mouseY / ratioY}`, }; partXY[partActive] = params; // 关闭细节 closePart(partActive); $(`.video-tip${partActive}`).show(); workerObj["part" + partActive] = useWorker( getAddress("Part", params), `#video-demo${partActive}`, null, () => { showCBInfo(`细节${partActive}播放完成`); $(`.video-tip${partActive}`).hide(); resetSF = enableImageManipulation( `.particulars-box .wheel${partActive}`, `#video-demo${partActive}`, { enableZoom: true, // 启用缩放 enableDrag: true, // 启用拖动 minScale: 1, // 最小缩放比例 maxScale: 6, // 最大缩放比例 dragSpeed: 0.15, // 拖动速度 } ); } ); $.each($(".particulars-box-list>li"), function (i, v) { $(v).find("button.close-btn-part").off("click"); $(v).find("button.lx-btn-part").off("click"); $(v).find("button.jt-btn-part").off("click"); $(v).off("mousedown"); $(v).off("mouseup"); let index = i + 1; // 关闭 $(v) .find("button.close-btn-part") .click(function () { closePart(index); }); // 截图 $(v) .find("button.jt-btn-part") .click(() => { showCBInfo(`细节开始截图`); jt(workerObj["part" + index]?.worker); }); // 录像 $(v) .find("button.lx-btn-part") .click(() => { lx(workerObj["part" + index]?.WebSocketWork, "part" + index); workerObj["part" + index] && $(v).find("button.lx-btn-part").toggleClass("lx-style"); }); }); }); }); $.each($(".particulars-box-list>li"), function (i, v) { let index = i + 1; $(v).click(function () { if (index === partActive) return; partActive = index; $(".particulars-box-list>li").removeClass("active"); $(v).addClass("active"); }); $(`#video-demo${index}`) .parent(".video-container") .on("dblclick", function () { resetSF(); $(`#video-demo${index}`).css("transform", "translate(0,0) scale(1)"); fullScreenDisplay(this); }); }); });