[mirotalk] - responsive whiteboard

This commit is contained in:
Miroslav Pejic
2025-12-04 00:07:59 +01:00
parent 64cf943adb
commit b125283f81
9 changed files with 136 additions and 39 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# ====================================================
# MiroTalk P2P v.1.6.69 - Environment Configuration
# MiroTalk P2P v.1.6.70 - Environment Configuration
# ====================================================
# App environment
+1 -1
View File
@@ -2,7 +2,7 @@
/**
* ==============================================
* MiroTalk P2P v.1.6.69 - Configuration File
* MiroTalk P2P v.1.6.70 - Configuration File
* ==============================================
*
* Branding and customizations require a license:
+1 -1
View File
@@ -45,7 +45,7 @@ dependencies: {
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.6.69
* @version 1.6.70
*
*/
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "mirotalk",
"version": "1.6.69",
"version": "1.6.70",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mirotalk",
"version": "1.6.69",
"version": "1.6.70",
"license": "AGPL-3.0",
"dependencies": {
"@mattermost/client": "11.1.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mirotalk",
"version": "1.6.69",
"version": "1.6.70",
"description": "A free WebRTC browser-based video call",
"main": "server.js",
"scripts": {
+2 -2
View File
@@ -27,8 +27,8 @@
--iframe-height: 480px;
/* whiteboard resize */
--wb-width: 800px;
--wb-height: 600px;
--wb-width: 1920px;
--wb-height: 1080px;
/* my settings */
--mySettings-select-w: 100%;
+37 -3
View File
@@ -7,8 +7,10 @@
position: fixed;
margin: auto;
padding: 10px;
width: var(--wb-width);
height: var(--wb-height);
width: calc(var(--wb-width) * 1px);
height: calc(var(--wb-height) * 1px);
max-width: 100vw;
max-height: 100vh;
background: var(--wb-bg);
border: var(--border);
box-shadow: var(--box-shadow);
@@ -27,7 +29,34 @@
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
animation-duration: 1s;
overflow: hidden;
overflow: visible;
box-sizing: border-box;
}
/* Mobile optimizations */
@media (max-width: 768px) {
#whiteboard {
padding: 5px;
border-radius: 5px;
}
.whiteboard-header {
padding: 2px;
}
.whiteboard-header-title button,
.whiteboard-header-options button {
padding: 5px;
font-size: 0.75rem;
min-width: 28px;
height: 28px;
}
.whiteboardColorPicker {
width: 16px;
height: 12px;
margin: 1px;
}
}
.whiteboard-header {
@@ -45,6 +74,11 @@
align-items: center;
}
.whiteboard-header-options {
display: flex;
align-items: center;
}
#whiteboardUnlockBtn,
#whiteboardLockBtn {
display: none;
+1 -1
View File
@@ -77,7 +77,7 @@ let brand = {
},
about: {
imageUrl: '../images/mirotalk-logo.gif',
title: 'WebRTC P2P v1.6.69',
title: 'WebRTC P2P v1.6.70',
html: `
<button
id="support-button"
+90 -27
View File
@@ -15,7 +15,7 @@
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.6.69
* @version 1.6.70
*
*/
@@ -116,8 +116,10 @@ const fileSharingInput = '*'; // allow all file extensions
const Base64Prefix = 'data:application/pdf;base64,';
const wbPdfInput = 'application/pdf';
const wbImageInput = 'image/*';
const wbWidth = 1280;
const wbHeight = 768;
// Reference dimensions for whiteboard (16:9 aspect ratio)
const wbReferenceWidth = 1920;
const wbReferenceHeight = 1080;
// Peer infos
const extraInfo = getId('extraInfo');
@@ -11193,8 +11195,9 @@ function toggleWhiteboard() {
}
whiteboard.classList.toggle('show');
whiteboard.style.top = '50%';
whiteboard.style.left = '50%';
centerWhiteboard();
wbIsOpen = !wbIsOpen;
screenReaderAccessibility.announceMessage(wbIsOpen ? 'Whiteboard opened' : 'Whiteboard closed');
}
@@ -11208,6 +11211,32 @@ function setupWhiteboard() {
setupWhiteboardLocalListeners();
setupWhiteboardShortcuts();
setupWhiteboardDragAndDrop();
setupWhiteboardResizeListener();
}
/**
* Whiteboard: setup resize listener for responsive behavior
*/
function setupWhiteboardResizeListener() {
let resizeTimer;
window.addEventListener('resize', () => {
// Debounce resize events to avoid performance issues
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
if (wbCanvas && wbIsOpen) {
setupWhiteboardCanvasSize();
}
}, 250);
});
// Also handle orientation change for mobile devices
window.addEventListener('orientationchange', () => {
setTimeout(() => {
if (wbCanvas && wbIsOpen) {
setupWhiteboardCanvasSize();
}
}, 300);
});
}
/**
@@ -11221,32 +11250,62 @@ function setupWhiteboardCanvas() {
}
/**
* Whiteboard: setup canvas size
* Whiteboard: setup canvas size to always fit full screen with proper scaling
*/
function setupWhiteboardCanvasSize() {
const optimalSize = [wbWidth, wbHeight];
const scaleFactorX = window.innerWidth / optimalSize[0];
const scaleFactorY = window.innerHeight / optimalSize[1];
if (scaleFactorX < scaleFactorY && scaleFactorX < 1) {
wbCanvas.setWidth(optimalSize[0] * scaleFactorX);
wbCanvas.setHeight(optimalSize[1] * scaleFactorX);
wbCanvas.setZoom(scaleFactorX);
setWhiteboardSize(optimalSize[0] * scaleFactorX, optimalSize[1] * scaleFactorX);
} else if (scaleFactorX > scaleFactorY && scaleFactorY < 1) {
wbCanvas.setWidth(optimalSize[0] * scaleFactorY);
wbCanvas.setHeight(optimalSize[1] * scaleFactorY);
wbCanvas.setZoom(scaleFactorY);
setWhiteboardSize(optimalSize[0] * scaleFactorY, optimalSize[1] * scaleFactorY);
} else {
wbCanvas.setWidth(optimalSize[0]);
wbCanvas.setHeight(optimalSize[1]);
wbCanvas.setZoom(1);
setWhiteboardSize(optimalSize[0], optimalSize[1]);
}
// Get available viewport dimensions
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Account for whiteboard container padding
const containerPadding = isMobileDevice ? 10 : 20; // 5px * 2 for mobile, 10px * 2 for desktop
// Header height varies by device
const headerHeight = isMobileDevice ? 40 : 60; // Smaller header on mobile
const extraMargin = 20; // Small margin to avoid any overflow
const availableWidth = viewportWidth - containerPadding - extraMargin;
const availableHeight = viewportHeight - containerPadding - headerHeight - extraMargin;
// Calculate scale factor to fit the viewport while maintaining aspect ratio
const scaleX = availableWidth / wbReferenceWidth;
const scaleY = availableHeight / wbReferenceHeight;
const scale = Math.min(scaleX, scaleY);
// Set canvas dimensions to scaled reference size
const canvasWidth = wbReferenceWidth * scale;
const canvasHeight = wbReferenceHeight * scale;
// Update canvas dimensions and zoom
wbCanvas.setWidth(canvasWidth);
wbCanvas.setHeight(canvasHeight);
wbCanvas.setZoom(scale);
// Update CSS variables for whiteboard container
// Add padding and header to get total container size
setWhiteboardSize(canvasWidth + containerPadding, canvasHeight + headerHeight + containerPadding);
// Recenter whiteboard on screen
centerWhiteboard();
// Recalculate offsets and render
wbCanvas.calcOffset();
wbCanvas.renderAll();
}
/**
* Whiteboard: center on screen
*/
function centerWhiteboard() {
if (whiteboard) {
// Force reflow to ensure centering is applied
whiteboard.style.top = '50%';
whiteboard.style.left = '50%';
whiteboard.style.transform = 'translate(-50%, -50%)';
}
}
/**
* Whiteboard: setup size
* @param {string} w width
@@ -11975,10 +12034,14 @@ async function wbUpdate() {
function handleJsonToWbCanvas(config) {
if (!wbIsOpen) toggleWhiteboard();
wbIsRedoing = true;
// Parse the JSON and load it
wbCanvas.loadFromJSON(config.wbCanvasJson, function () {
wbCanvas.renderAll();
// After loading, ensure proper scaling is maintained
setupWhiteboardCanvasSize();
wbIsRedoing = false;
});
if (!isPresenter && !wbCanvas.isDrawingMode && wbIsLock) {
wbDrawing(false);
}
@@ -13086,7 +13149,7 @@ function showAbout() {
Swal.fire({
background: swBg,
position: 'center',
title: brand.about?.title && brand.about.title.trim() !== '' ? brand.about.title : 'WebRTC P2P v1.6.69',
title: brand.about?.title && brand.about.title.trim() !== '' ? brand.about.title : 'WebRTC P2P v1.6.70',
imageUrl: brand.about?.imageUrl && brand.about.imageUrl.trim() !== '' ? brand.about.imageUrl : images.about,
customClass: { image: 'img-about' },
html: `