Commit f8bd91c5 by Иван Кубота

Refactor camera adding functions.

Change UI Move PositionSelect to separate file
parent 371cda0f
AddCss('/main.css');
let content, remoteVideoEl;
var getConferenceID = function() {
return 'DDD'.replace(/D/g, ()=>Math.random()*10|0)
};
const store = window.store = new Store({
conference_id: 'DDD'.replace(/D/g, ()=>Math.random()*10|0), // LUCID
conference_id: getConferenceID(), // LUCID
connection: false,
webcamtypes: [
{text: 'Left', value: 'Left', filter: 'RemoteUser'},
{text: 'Center', value: 'Center', filter: 'OfficeUserLeft'},
{text: 'Right', value: 'Right', filter: 'RemoteUser'},
{text: 'Left', value: 'Left', filter: 'RemoteUser'},
],
guestPositions: [
......@@ -18,7 +22,7 @@ const store = window.store = new Store({
{text: 'Remote Guest', value: 'RemoteUser', realValue: 'RemoteUser'},
{text: 'Office Guest', value: 'OfficeUserLeft', realValue: 'OfficeUser'},
/*{text: 'Office User Right', value: 'OfficeUserRight'},
{text: 'Office User Left', value: 'OfficeUserLeft'},*/
{text: 'Office User Left', value: 'OfficseUserLeft'},*/
],
});
......@@ -43,7 +47,7 @@ var params = location.hash.replace('#/','')
if(params.id){
store.set('conference_id', params.id);
Screen.show( 'Conference' );
Screen.show( 'Conference', true );
}else{
Screen.show( 'Main' );
}
......
......@@ -10,270 +10,6 @@
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/selfie_segmentation.js" crossorigin="anonymous"></script>
<script src="https://form.dev/vanilla/build/rDOM_latest.js"></script>
<style>
@font-face {
font-family: "Amazon Ember";
src: url("font/AmazonEmber_W_Bd.woff2"), url("font/AmazonEmber_W_Bd.woff");
font-weight: bold;
}
@font-face {
font-family: "Amazon Ember";
src: url("font/AmazonEmber_W_Rg.woff2"), url("font/AmazonEmber_W_Rg.woff");
font-weight: normal;
}
* {
font-family: "Amazon Ember", Verdana;
}
img.logo {
position: absolute;
top: 40px;
left: 40px;
}
html {
height: 100%;
}
.main-content {
margin: 16px 0;
}
#content {
height: 100%;
position: relative;
}
.main-background {
display: flex;
flex-direction: column;
height: 100%;
background: url(/img/back.jpg);
background-size: cover;
background-position-x: center;
}
.main-background:before {
content: '';
position: absolute;
left: 0;
top: 0;
background: rgba(0,0,0,0.5);
right: 0;
bottom: 0;
}
.main-background .p, .main-background .h1 {
color: #fff;
}
.main-background .p {
margin-top: 9px;
}
.top-bar {
height: 64px;
background: #1E143A;
padding: 16px 44px;
box-sizing: border-box;
}
body {
margin: 0;
height: 100%;
}
.button {
box-sizing: border-box;
border-radius: 20px;
padding: 6px 20px;
margin-left: 16px;
cursor: pointer;
}
.button.primary {
background: #584DDA;
color: #fff;
border: 2px solid #584DDA;
}
.button.secondary {
background: transparent;
color: #fff;
border: 2px solid;
}
.buttons {
float: right;
display: flex;
}
.main-buttons {
display: flex;
margin-top: 40px;
}
.sub-content {
position: relative;
margin: auto;
box-sizing: border-box;
padding: 20px;
width: 100%;
max-width: 1124px;
/*position: absolute;*/
/*left: 12.4%;*/
/*top: 50%;*/
/*transform: translateY(-50%);*/
}
.main-background .button {
margin-right: 16px;
margin-left: 0;
padding: 8px 32px;
font-size: 16px;
}
button.dropdown-field__toggler:after {
content: '▼';
}
button.dropdown-field__toggler {
background: transparent !important;
border: 0;
border-bottom: 2px solid #594CD7;
width: 366px;
min-height: 34px;
position: relative;
text-align: left;
padding: 4px;
font-size: 14px;
line-height: 24px;
cursor: pointer;
}
button.dropdown-field__toggler:after {
content: '▼';
position: absolute;
top: 3px;
right: 10px;
font-family: arial;
font-size: 10px;
transform: scaleY(0.7) translateY(4px);
}
.dropdown-field--opened button.dropdown-field__toggler:after {
content: '▲';
}
input[type="text"] {
background: transparent !important;
border: 0;
line-height: 36px;
border-bottom: 2px solid #fff;
font-size: 16px;
color: #fff;
outline: none;
}
input[type="text"]:focus {
border-bottom: 2px solid #594CD7;
}
.page-content {
display: flex;
flex-direction: column;
height: 100%;
}
.content {
margin: auto;
box-sizing: border-box;
padding: 20px;
width: 100%;
max-width: 1124px;
}
.block {
margin-bottom: 40px;
}
.header {
font-size: 32px;
margin-bottom: 8px;
}
.h1 {
font-size: 40px;
line-height: 64px;
font-style: normal;
font-weight: bold;
}
.p {
font-size: 16px;
line-height: 32px;
font-style: normal;
font-weight: normal;
}
.input {
border: none;
padding: 4px 8px;
border-bottom: 2px solid #00000066;
width: 366px;
}
.input:focus-visible {
outline: none;
}
.input:focus {
border-bottom: 2px solid #594CD7;
}
.label_label {
display: inline-block;
width: 108px;
font-size: 16px;
padding: 4px 0 0 2px;
}
.callapp_local_video {
display: none;
}
.hidden {
display: none;
}
.income-video {
display: inline-block;
margin: 20px 8px 0 0;
}
.income-video-id {
position: absolute;
z-index: 1;
}
.dropdown-field__tooltip {
display: none;
}
.dropdown-field--opened .dropdown-field__tooltip {
display: block;
position: absolute;
background: #fff;
border: 2px solid #594CD7;
z-index: 1;
padding: 8px 0;
margin-top: -2px;
min-width: 362px;
}
.dropdown-item {
padding: 8px 20px;
font-size: 14px;
line-height: 20px;
/* margin-bottom: 8px; */
}
.dropdown-item:hover {
background: #594CD7;
color: #fff;
cursor: pointer;
}
.form-field__label-text {
font-size: 24px;
font-weight: bold;
margin: 40px 0 4px;
display: block;
line-height: 32px;
}
.form-field {
margin: 2px 0 12px;
}
.canvas-resizer canvas {
display: block;
}
.canvas-resizer {
float: right;
position: relative;
top: 66px;
}
.description.gray {
color: #5C5C5C;
}
.description {
font-size: 14px;
line-height: 24px;
}
</style>
</head>
<body>
......@@ -303,6 +39,7 @@
<script src="view/TableComponent.js"></script>
<script src="view/CanvasResizer.js"></script>
<script src="view/Screen.js"></script>
<script src="view/PositionSelect.js"></script>
<script src="view/MainScreen.js"></script>
<script src="view/CallScreen.js"></script>
<script src="app.js"></script>
......
@font-face {
font-family: "Amazon Ember";
src: url("font/AmazonEmber_W_Bd.woff2"), url("font/AmazonEmber_W_Bd.woff");
font-weight: bold;
}
@font-face {
font-family: "Amazon Ember";
src: url("font/AmazonEmber_W_Rg.woff2"), url("font/AmazonEmber_W_Rg.woff");
font-weight: normal;
}
* {
font-family: "Amazon Ember", Verdana;
}
img.logo {
position: absolute;
top: 40px;
left: 40px;
}
html {
height: 100%;
}
.main-content {
margin: 16px 0;
}
#content {
height: 100%;
position: relative;
}
.main-background {
display: flex;
flex-direction: column;
height: 100%;
background: url(/img/back.jpg);
background-size: cover;
background-position-x: center;
}
.main-background:before {
content: '';
position: absolute;
left: 0;
top: 0;
background: rgba(0,0,0,0.5);
right: 0;
bottom: 0;
}
.main-background .p, .main-background .h1 {
color: #fff;
}
.main-background .p {
margin-top: 9px;
}
.top-bar {
height: 64px;
background: #1E143A;
padding: 16px 44px;
box-sizing: border-box;
}
body {
margin: 0;
height: 100%;
}
.button {
box-sizing: border-box;
border-radius: 20px;
padding: 6px 20px;
margin-left: 16px;
cursor: pointer;
}
.button.primary {
background: #584DDA;
color: #fff;
border: 2px solid #584DDA;
}
.button.orange {
background: rgba(240, 89, 41, 0.92);
color: #fff;
border: 2px solid rgba(240, 89, 41, 0.92);
}
.button.primary:disabled, .button.primary.disabled {
opacity: 0.5;
}
.button.secondary {
background: transparent;
color: #fff;
border: 2px solid;
}
.buttons {
float: right;
display: flex;
}
.main-buttons {
display: flex;
margin-top: 40px;
}
.sub-content {
position: relative;
margin: auto;
box-sizing: border-box;
padding: 20px;
width: 100%;
max-width: 1124px;
/*position: absolute;*/
/*left: 12.4%;*/
/*top: 50%;*/
/*transform: translateY(-50%);*/
}
.main-background .button {
margin-right: 16px;
margin-left: 0;
padding: 8px 32px;
font-size: 16px;
}
button.dropdown-field__toggler:after {
content: '▼';
}
button.dropdown-field__toggler {
background: transparent !important;
border: 0;
border-bottom: 2px solid #594CD7;
width: 366px;
min-height: 34px;
position: relative;
text-align: left;
padding: 4px;
font-size: 14px;
line-height: 24px;
cursor: pointer;
}
button.dropdown-field__toggler:after {
content: '▼';
position: absolute;
top: 3px;
right: 10px;
font-family: arial;
font-size: 10px;
transform: scaleY(0.7) translateY(4px);
}
.dropdown-field--opened button.dropdown-field__toggler:after {
content: '▲';
}
input[type="text"] {
background: transparent !important;
border: 0;
line-height: 36px;
border-bottom: 2px solid #fff;
font-size: 16px;
color: #fff;
outline: none;
}
input[type="text"]:focus {
border-bottom: 2px solid #594CD7;
}
.page-content {
display: flex;
flex-direction: column;
height: 100%;
}
.content {
margin: auto;
box-sizing: border-box;
padding: 20px;
width: 100%;
max-width: 1124px;
}
.block {
margin-bottom: 40px;
}
.header {
font-size: 32px;
margin-bottom: 8px;
}
.h1 {
font-size: 40px;
line-height: 64px;
font-style: normal;
font-weight: bold;
}
.p {
font-size: 16px;
line-height: 32px;
font-style: normal;
font-weight: normal;
}
.input {
border: none;
padding: 4px 8px;
border-bottom: 2px solid #00000066;
width: 366px;
}
.input:focus-visible {
outline: none;
}
.input:focus {
border-bottom: 2px solid #594CD7;
}
.label_label {
display: inline-block;
width: 108px;
font-size: 16px;
padding: 4px 0 0 2px;
}
.callapp_local_video {
display: none;
}
.hidden {
display: none;
}
.income-video {
display: inline-block;
margin: 20px 8px 0 0;
}
.income-video-id {
position: absolute;
z-index: 1;
}
.dropdown-field__tooltip {
display: none;
}
.dropdown-field--opened .dropdown-field__tooltip {
display: block;
position: absolute;
background: #fff;
border: 2px solid #594CD7;
z-index: 1;
padding: 8px 0;
margin-top: -2px;
min-width: 362px;
}
.dropdown-item {
padding: 8px 20px;
font-size: 14px;
line-height: 20px;
/* margin-bottom: 8px; */
}
.dropdown-item:hover {
background: #594CD7;
color: #fff;
cursor: pointer;
}
.form-field__label-text {
font-size: 24px;
font-weight: bold;
margin: 40px 0 4px;
display: block;
line-height: 32px;
}
.form-field {
margin: 2px 0 12px;
}
.canvas-resizer canvas {
display: block;
}
.canvas-resizer {
float: right;
position: relative;
top: 66px;
}
.description.gray {
color: #5C5C5C;
}
.description {
font-size: 14px;
line-height: 24px;
}
\ No newline at end of file
......@@ -81,7 +81,7 @@ Screen.Conference = function() {
};
}
var camera1canvas, camera2canvas, single = new Store.Value.Boolean(true);
var single = new Store.Value.Boolean(true);
var linkHook = _=>
store.sub('conference_id', function(val) {
......@@ -91,23 +91,24 @@ Screen.Conference = function() {
var streams = {};
var userID = 0;
var cameraID = 0;
var remoteVideoEl = D.div({cls: 'remote-video'});
var generateUserUI = function() {
var currentUserID = userID;
var generateCameraUI = function() {
var currentCameraID = cameraID;
cameraID++;
var camTypes = store.get('webcamtypes');
store.set('webcam'+userID, camTypes[userID % camTypes.length].value);
store.set('webcam'+currentCameraID, camTypes[currentCameraID % camTypes.length].value);
var userRoles = store.get('userRoles');
store.set('userRole'+userID, userRoles[userID % userRoles.length].value);
store.set('userRole'+currentCameraID, userRoles[currentCameraID % userRoles.length].value);
var guestPositions = store.get('guestPositions');
store.set('guestPosition'+userID, false);
store.set('guestPosition'+currentCameraID, false);
var cameras = ['Left', 'Center', 'Right']
var cameraCanvas, canvasResizerEl,
dom = D.div( { cls: 'block', style: { marginBottom: '80px' } },
D.div( { cls: 'header' }, 'Camera ' + ( currentUserID + 1 ) ),
D.div( { cls: 'header' }, cameras[currentCameraID%3] + ' Camera' ),
canvasResizerEl = CanvasResizer(
cameraCanvas = D.h( 'canvas', {
cls: "output_canvas",
......@@ -119,32 +120,27 @@ Screen.Conference = function() {
}
} )
),
TableComponent({
roles: 'userRoles',
role: store.bind( 'userRole' + userID ),
guestPositions: 'guestPositions',
guestPosition: store.bind( 'guestPosition' + userID )
}),
Select( {
/*Select( {
values: 'userRoles',
bind: store.bind( 'userRole' + userID ),
bind: store.bind( 'userRole' ),
label: 'Your role',
disabled: isConnected
} ),
} ),*/
Select( {
values: 'videoinput',
bind: store.bind( 'videoinput' + userID ),
bind: store.bind( 'videoinput' + currentCameraID ),
label: 'Camera device',
disabled: isConnected
} ),
Select( {
/* Select( {
values: 'webcamtypes',
bind: store.bind( 'webcam' + userID ),
bind: store.bind( 'webcam' + cameraID ),
label: 'Camera position',
filter: store.bind( 'userRole' + userID ),
filter: store.bind( 'userRole' + cameraID ),
disabled: isConnected
} )
} ),*/
);
......@@ -167,11 +163,11 @@ Screen.Conference = function() {
if(!is)
return;
var count = devices.videoinput.length;
store.set('videoinput'+currentUserID, devices.videoinput[
(count-1-currentUserID +count*currentUserID)%count
store.set('videoinput'+currentCameraID, devices.videoinput[
(count-1-currentCameraID +count*currentCameraID)%count
].value);
});
store.sub(['inputsSetted', 'videoinput'+userID], async (is, input) => {
store.sub(['inputsSetted', 'videoinput'+currentCameraID], async (is, input) => {
if(!is)
return;
......@@ -194,13 +190,15 @@ Screen.Conference = function() {
canvasResizerEl.style.display = 'block';
}catch(e){
video1.srcObject = null;
video1.pause();
canvasResizerEl.style.display = 'none';
console.error(e)
}
}
for(var streamID in streams){
var inUse = false;
for(var j = 0; j <= userID; j++){
for(var j = 0; j <= cameraID; j++){
if(store.get('videoinput'+j) === streamID){
inUse = true;
break;
......@@ -219,17 +217,17 @@ Screen.Conference = function() {
});
window.instances || (window.instances = []);
var RTCinstance;
store.sub('appLoaded', function(loaded) {
if(!loaded)
store.sub(['appLoaded'], function(loaded, callScreenCamerasTune) {
if(!loaded)// || !callScreenCamerasTune)
return;
RTCinstance = new RTC(
currentUserID ? null : document.querySelector("#videoinputapp1"),
cameraCanvas, 'canvas'+currentUserID,
currentUserID,
currentUserID ? null : remoteVideoEl
currentCameraID ? null : document.querySelector("#videoinputapp1"),
cameraCanvas, 'canvas'+currentCameraID,
currentCameraID,
currentCameraID ? null : remoteVideoEl
);
window.instances.push(RTCinstance);
RTCinstance.mUiRemoteVideoParent = currentUserID ? null : remoteVideoEl;
RTCinstance.mUiRemoteVideoParent = currentCameraID ? null : remoteVideoEl;
var selfieSegmentation = new SelfieSegmentation( {
locateFile: ( file ) => {
......@@ -247,21 +245,33 @@ Screen.Conference = function() {
} );
var segmentation = async function() {
if(video1.videoWidth>10 && store.get('videoinput'+currentUserID)){
await selfieSegmentation.send( { image: video1 } );
}
if( store.get( 'callScreenCamerasTune' ) ){
if(cameraID<3){
usersBlock.appendChild( generateCameraUI() )
}
if( video1.videoWidth > 10 && store.get( 'videoinput' + currentCameraID ) ){
try{
await selfieSegmentation.send( { image: video1 } );
}catch( e ){
}
}
}
requestAnimationFrame(segmentation);
};
console.log(video1, canvasResizerEl, canvasElement, currentCameraID)
requestAnimationFrame(segmentation);
});
userID++;
return dom;
}
var usersBlock, tooMuchUsers = new Store.Value.Boolean(false);
var dom = D.div({cls: 'page-content'},
D.div({cls: 'top-bar'},
D.h('img', {src: 'amazon-logo.svg'}),
D.div({cls: 'buttons'},
D.div({cls: 'buttons hidden'},
D.h('button', {cls: ['button secondary', {hidden: Store.NOT(isConnected)}], onclick: ()=>store.set('connection', false)}, 'End session'),
D.h('button', {cls: ['button primary', {hidden: isConnected}], onclick: ()=>store.set('connection', true)}, 'Ready to connect')
)
......@@ -274,15 +284,21 @@ Screen.Conference = function() {
D.div({cls: 'description'}, 'Link to session: ', link),
),
usersBlock = D.div({cls: 'users-block'},
generateUserUI()
Screen.PositionSelect(),
usersBlock = D.div({cls: ['users-block', {
hidden: Store.NOT(store.val('callScreenCamerasTune'))
}]},
generateCameraUI(),
/*generateCameraUI(),
generateCameraUI()*/
),
D.h('button', {cls: ['button primary', {hidden: Store.OR(isConnected, tooMuchUsers)}],
window.addACameraBtn = D.h('button', {cls: ['button primary hidden', {hidden: Store.OR(isConnected, tooMuchUsers)}],
onclick: ()=> {
usersBlock.appendChild(generateUserUI())
if(userID > 1)
tooMuchUsers.set(true);
usersBlock.appendChild(generateCameraUI())
/*if(cameraID > 1)
tooMuchUsers.set(true);*/
}
}, 'Add camera'),
......@@ -290,7 +306,7 @@ Screen.Conference = function() {
D.div({cls: 'block hidden'},
D.div({cls: 'header'}, 'Conference info'),
LabeledInput({label: 'Session ID', cls: 'callapp_address input', autocomplete: 'off', value: 'DDD'.replace(/D/g, ()=>Math.random()*10|0)}, 'conference_id'), // LUCID
LabeledInput({label: 'Session ID', cls: 'callapp_address input', autocomplete: 'off', value: getConferenceID()}, 'conference_id'), // LUCID
),
D.div({cls: ['block', {hidden: true}]}, //Store.NOT(isConnected)
D.div({cls: ['header']}, 'Remote video'),
......@@ -451,3 +467,10 @@ Screen.Conference = function() {
})();
return dom;
};
Screen.Conference.beforeShow = function() {
store.set({
connection: false,
callScreenCamerasTune: false
});
};
\ No newline at end of file
......@@ -12,7 +12,7 @@ Screen.Main = function() {
),
D.div({cls: 'main-buttons'},
D.h('button', {cls: 'button primary', onclick: ()=>Screen.show('Conference')}, 'Create New Session'),
D.h('button', {cls: 'button primary', onclick: ()=>Screen.show('Conference', true)}, 'Create New Session'),
D.h('button', {cls: 'button primary', onclick: ()=> showJoinForm.set(true)}, 'Connect to Session'),
)
),
......@@ -24,7 +24,7 @@ Screen.Main = function() {
),
D.div({cls: 'main-buttons'},
D.h('button', {cls: 'button primary', onclick: ()=>Screen.show('Conference')}, 'Connect to Session'),
D.h('button', {cls: 'button primary', onclick: ()=>Screen.show('Conference', true)}, 'Connect to Session'),
D.h('button', {cls: 'button secondary', onclick: ()=> showJoinForm.set(false)}, 'Go Back'),
)
......@@ -33,4 +33,10 @@ Screen.Main = function() {
)
);
return dom;
};
Screen.Main.beforeShow = function() {
store.set({
conference_id: getConferenceID()
});
};
\ No newline at end of file
Screen.PositionSelect = function() {
return D.div({cls: [{
hidden: store.val('callScreenCamerasTune')
}]},
D.div({cls: 'block'},
TableComponent({
roles: 'userRoles',
role: store.bind( 'userRole' ),
guestPositions: 'guestPositions',
guestPosition: store.bind( 'guestPosition' )
}),
),
D.div({cls: 'bottom-buttons'},
D.h('button', {
cls: ['button primary', {disabled: Store.NOT(store.val('guestPosition'))}],
onclick: ()=>{
store.set('callScreenCamerasTune', true);
}
}, 'Continue'),
D.h('button', {
cls: ['button orange', {hidden: /*isConnected*/false}],
onclick: ()=>{
Screen.show( 'Main', true );
}}, 'Exit to main menu')
)
);
}
\ No newline at end of file
const Screen = {
cache: {},
show: function(name) {
show: function(name, refresh) {
const renderEl = document.getElementById('content');
D.removeChildren(renderEl);
if(!(name in Screen.cache)){
Screen[ name ].beforeShow && Screen[ name ].beforeShow();
if(!(name in Screen.cache)){//} || refresh){
Screen.cache[ name ] = Screen[ name ]();
}
renderEl.appendChild(Screen.cache[name]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment