init
This commit is contained in:
BIN
pub/PTZ-Optics-Favicon.jpg
Normal file
BIN
pub/PTZ-Optics-Favicon.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
205
pub/css/style.css
Normal file
205
pub/css/style.css
Normal file
@@ -0,0 +1,205 @@
|
||||
html, body {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
body{
|
||||
font-size:.875rem;
|
||||
background-color:#ececec;
|
||||
max-width:1440px;
|
||||
max-height: 100vh;
|
||||
}
|
||||
option {
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
white-space: pre;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
.wrapper{
|
||||
width:100%;
|
||||
height: 100vh;
|
||||
align-items:stretch;
|
||||
}
|
||||
|
||||
/* Sidebar & Content */
|
||||
|
||||
#content,#sidebar{
|
||||
min-height:100vh;
|
||||
max-height:100vh;
|
||||
transition:all .3s;
|
||||
padding: 1em;
|
||||
}
|
||||
#sidebar{
|
||||
width:30%;
|
||||
min-width:30%;
|
||||
max-width:30%;
|
||||
position:fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index:999;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#sidebar.active{
|
||||
margin-left:-30%;
|
||||
}
|
||||
#content{
|
||||
width:65%;
|
||||
padding-right: 5%;
|
||||
margin-right: 1%;
|
||||
height: 100vh;
|
||||
}
|
||||
#content.active {
|
||||
width: 100%;
|
||||
margin-right: auto;
|
||||
}
|
||||
.optionview.row{
|
||||
margin-bottom: 1.0em;
|
||||
}
|
||||
ul.nav {
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
#optionsNav > ul, #optionsNav > .nav, #optionsNav > ul > li {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
transition:all .3s;
|
||||
}
|
||||
#optionWindow {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.highlight {
|
||||
padding: 5px;
|
||||
background-color: #93CCEA;
|
||||
}
|
||||
.topBtns {
|
||||
margin-bottom: 1.0em;
|
||||
}
|
||||
.imageRow {
|
||||
margin-bottom: 1em;
|
||||
margin-left: 0.8em;
|
||||
}
|
||||
|
||||
/* Movement buttons & option nav */
|
||||
|
||||
.movementBtn,.nav-item{
|
||||
cursor:pointer;
|
||||
}
|
||||
.movementBtn{
|
||||
width:2.7em;
|
||||
height:2.7em;
|
||||
color:#999;
|
||||
margin:.4em;
|
||||
transition: transform .2s;
|
||||
}
|
||||
.movementBtn:hover{
|
||||
color:#000;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
.movementBtn:active{
|
||||
color:green;
|
||||
transform: scale(1.2);
|
||||
text-shadow:0 0 6px green;
|
||||
}
|
||||
#ptzSpeedBtnRow,#setCallBtnRow{
|
||||
padding-top:.8em;
|
||||
}
|
||||
|
||||
/* Message & Stream Stage */
|
||||
|
||||
#stageContainer {
|
||||
height: 80%;
|
||||
width: 100%;
|
||||
position: static;
|
||||
}
|
||||
#streamStage, #msgStage {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
#streamStage {
|
||||
max-height: 100%;
|
||||
right: 0;
|
||||
}
|
||||
#msgStage {
|
||||
transition:all .4s;
|
||||
display:none;
|
||||
z-index: 10;
|
||||
}
|
||||
.errMsg {
|
||||
opacity: 0.5;
|
||||
color: #721c24;
|
||||
background-color: #f8d7da;
|
||||
border-color: #f5c6cb;
|
||||
}
|
||||
|
||||
.successMsg {
|
||||
opacity: 0.5;
|
||||
color: #155724;
|
||||
background-color: #d4edda;
|
||||
border-color: #c3e6cb;
|
||||
}
|
||||
|
||||
/* Mobile Devices */
|
||||
|
||||
@media (max-width:414px){
|
||||
.wrapper{
|
||||
width:100vw;
|
||||
height: 100vh;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
/* Sidebar & Content */
|
||||
#content,#sidebar{
|
||||
transition:all .3s;
|
||||
margin: 0;
|
||||
z-index: auto;
|
||||
right: auto;
|
||||
left: auto;
|
||||
min-width: 100vw;
|
||||
max-width: 100vw;
|
||||
}
|
||||
#sidebar{
|
||||
position: relative;
|
||||
height: 50%;
|
||||
width:100%;
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
top: 50%;
|
||||
max-height: 50%;
|
||||
min-height: 50%;
|
||||
}
|
||||
#sidebar.active{
|
||||
display: none;
|
||||
}
|
||||
#content{
|
||||
position: absolute;
|
||||
width:100%;
|
||||
max-width: 100vw;
|
||||
height: 50%;
|
||||
min-height: 50%;
|
||||
max-height: 50%;
|
||||
top:0px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#content.active {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
max-width: 100vw;
|
||||
}
|
||||
#optionWindow {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
/* stage */
|
||||
#stageContainer {
|
||||
height: 70%;
|
||||
position: inherit;
|
||||
}
|
||||
#streamStage {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
400
pub/index.html
Normal file
400
pub/index.html
Normal file
@@ -0,0 +1,400 @@
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<title>Visca API</title>
|
||||
<base href="/" />
|
||||
<link rel="icon" href="PTZ-Optics-Favicon.jpg" />
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<nav id="sidebar">
|
||||
<div id="options">
|
||||
<h3 class="text-center mx-auto">Option Panel</h3>
|
||||
<nav id="optionsNav" class="navbar navbar-default">
|
||||
<ul class="nav text-center mx-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active highlight" value="ctrl" onclick="optionView('ctrl');">PTZ</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" value="focus" onclick="optionView('focus');">Focus</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" value="camImage" onclick="optionView('camImage');">Image</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" value="preset" onclick="optionView('preset');">Presets</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div id="optionWindow">
|
||||
<div id="ctrl" class="optionView">
|
||||
<div class="row">
|
||||
<div id="arrowControl" class="col">
|
||||
<div class="row">
|
||||
<div class="col text-center mx-auto">
|
||||
<div class="btn-group pb-1" role="group" aria-label="Focus">
|
||||
<button id="focusWide" type="button" class="btn btn-sm btn-outline-dark" data-value="wide"><i class="fas fa-minus"></i></button>
|
||||
<button type="button" class="btn btn-small btn-dark disabled">Focus</button>
|
||||
<button id="focusTele" type="button" class="btn btn-sm btn-outline-dark" data-value="tele"><i class="fas fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col mx-auto text-center">
|
||||
<i id="motionUp" data-value="up" class="camera-ctrl movementBtn fas fa-sm fa-arrow-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col text-center">
|
||||
<i id="motionLeft" data-value="left" class="camera-ctrl movementBtn fas fa-sm fa-arrow-left"></i>
|
||||
<i class="camera-ctrl movementBtn fas fa-sm fa-home" onclick="moveHome()"></i>
|
||||
<i id="motionRight" data-value="right" class="camera-ctrl movementBtn fas fa-sm fa-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col mx-auto text-center">
|
||||
<i id="motionDown" data-value="down" class="camera-ctrl movementBtn fas fa-sm fa-arrow-down"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<div class="btn-group pb-1" role="group" aria-label="Focus">
|
||||
<button id="zoomWide" type="button" class="btn btn-sm btn-outline-dark" data-value="wide"><i class="fas fa-minus"></i></button>
|
||||
<button type="button" class="btn btn-small btn-dark disabled">Zoom</button>
|
||||
<button id="zoomTele" type="button" class="btn btn-sm btn-outline-dark" data-value="tele"><i class="fas fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pr-1 pt-1">
|
||||
<div class="col-lg-10 mx-auto">
|
||||
<div class="form-group">
|
||||
<label id="panSpeedLabel" for="formControlRange">Pan Speed: 10</label>
|
||||
<input id="panSpeedInput" data-html="pan" type="range" class="form-control-range panTiltInput" max="18" min="1" value="10">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label id="tiltSpeedLabel" for="formControlRange">Tilt Speed: 10</label>
|
||||
<input id="tiltSpeedInput" data-html="tilt" type="range" class="form-control-range panTiltInput" max="14" min="1" value="10">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label id="zoomSpeedLabel" for="formControlRange">Zoom Speed: 5</label>
|
||||
<input id="zoomSpeedInput" data-html="zoom" type="range" class="form-control-range panTiltInput" max="7" min="0" value="5">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label id="focusSpeedLabel" for="formControlRange">Focus Speed: 5</label>
|
||||
<input id="focusSpeedInput" data-html="focus" type="range" class="form-control-range panTiltInput" max="7" min="0" value="5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="focus" class="optionView" style="display:none;">
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col-lg-6">
|
||||
<label for="focusModeSel">Focus Mode:</label>
|
||||
<select id="focusModeSel" class="custom-select" onchange="focusMode()">
|
||||
<option value="auto">Auto</option>
|
||||
<option value="manual">Manual</option>
|
||||
<option value="toggle">toggle</option>
|
||||
<option value="lock">Lock</option>
|
||||
<option value="unlock">Unlock</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<label for="afZoneSel">AF Zone:</label>
|
||||
<select id="afZoneSel" class="custom-select" onchange="afZone()">
|
||||
<option value="top">Top</option>
|
||||
<option value="center">Center</option>
|
||||
<option value="bottom">Bottom</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="camImage" class="optionView" style="display:none;">
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<label for="wbModeSel">White Balance:</label>
|
||||
<select id="wbModeSel" class="custom-select" onchange="whiteBalance('wbmode')">
|
||||
<option value="auto">Auto</option>
|
||||
<option value="indoor">Indoor</option>
|
||||
<option value="outdoor">Outdoor</option>
|
||||
<option value="onepush">Onepush</option>
|
||||
<option value="manual">Manual</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="awbSel">AWB Sensitivity:</label>
|
||||
<select id="awbSel" class="custom-select" onchange="whiteBalance('awbsenstivity')">
|
||||
<option value="high">High</option>
|
||||
<option value="normal" selected>Normal</option>
|
||||
<option value="low">Low</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<label for="bgainBtn">Bgain:</label>
|
||||
<div id="bgainBtn" class="mx-auto">
|
||||
<div class="btn-group" role="group" aria-label="Bgain Button Group">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="bgain('standard', 'up')">Up</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="bgain('standard', 'down')">Down</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="bgain('standard', 'reset')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="rgainBtn">Rgain:</label>
|
||||
<div id="rgainBtn" class="mx-auto">
|
||||
<div class="btn-group" role="group" aria-label="Rgain Button Group">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="rgain('standard', 'up')">Up</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="rgain('standard', 'down')">Down</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="rgain('standard', 'reset')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="gainBtn">Gain:</label>
|
||||
<div id="gainBtn" class="mx-auto">
|
||||
<div class="btn-group" role="group" aria-label="Gain Button Group">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="gain('standard', 'up')">Up</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="gain('standard', 'down')">Down</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="gain('standard', 'reset')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<label for="blRadios">Backlight:</label>
|
||||
<div id="blRadios" class="mx-auto text-center">
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label" for="blOn">On</label>
|
||||
<input class="form-check-input" onclick="backlight('on')" type="radio" name="blRadio" id="blOn" value="on">
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label" for="blOff"> Off </label>
|
||||
<input class="form-check-input" onclick="backlight('off')" type="radio" name="blRadio" id="blOff" checked>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="bwRadios">Black White:</label>
|
||||
<div id="bwRadios" class="mx-auto text-center">
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label" for="bwOn">On</label>
|
||||
<input class="form-check-input" onclick="blackWhite('on')" type="radio" name="bwRadio" id="blOn" value="on">
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label" for="bwOff">Off</label>
|
||||
<input class="form-check-input" onclick="blackWhite('off')" type="radio" name="bwRadio" id="blOff" value="off" checked>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<label for="flickerBtn">Flicker:</label>
|
||||
<div id="flickerBtn" class="mx-auto">
|
||||
<div class="btn-group" role="group" aria-label="Camera Flicker">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="flicker('off')">Off</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="flicker('50Hz')">50Hz</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="flicker('60Hz')">60hz</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="imageFlipCb">Image Flip Dimension:</label>
|
||||
<div id="imageFlipCb" class="mx-auto text-center">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="lr" onchange="imgFlip('lr')">
|
||||
<label class="form-check-label" for="lr">Horizontal</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="pf" onchange="imgFlip('pf')">
|
||||
<label class="form-check-label" for="pf">Vertical</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<div class="form-group">
|
||||
<label id="colorHueInputLabel" for="colorHueInput">ColorHue: 8</label>
|
||||
<input id="colorHueInput" type="range" class="form-control-range" max="14" min="0" value="8" onchange="colorHue()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="form-group">
|
||||
<label id="brightInputLabel" for="brightInput">Brightness: 8</label>
|
||||
<input id="brightInput" type="range" class="form-control-range" max="14" min="0" value="8" onchange="brightness()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<div class="form-group">
|
||||
<label id="contrastInputLabel" for="contrastInput">Contrast: 9</label>
|
||||
<input id="contrastInput" type="range" class="form-control-range" max="14" min="0" value="9" onchange="contrast()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="aeSel">Auto Exp:</label>
|
||||
<select id="aeSel" class="custom-select" onchange="autoExp()">
|
||||
<option value="fullauto">Full Auto</option>
|
||||
<option value="manual" selected>Manual</option>
|
||||
<option value="shutter">Shutter</option>
|
||||
<option value="iris">Iris</option>
|
||||
<option value="bright">Bright</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col">
|
||||
<label for="shutterBtn">Shutter:</label>
|
||||
<div id="shutterBtn" class="mx-auto">
|
||||
<div class="btn-group" role="group" aria-label="Shutter Button Group">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="shutter('standard', 'up')">Up</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="shutter('standard', 'down')">Down</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="shutter('standard', 'reset')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="irisBtn">Iris:</label>
|
||||
<div id="irisBtn" class="mx-auto">
|
||||
<div class="btn-group" role="group" aria-label="Iris Button Group">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="iris('standard', 'up')">Up</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="iris('standard', 'down')">Down</button>
|
||||
<button type="button" class="btn btn-outline-dark btn-sm text-center" onclick="iris('standard', 'reset')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="preset" class="optionView" style="display:none;">
|
||||
<div class="row mb-2 text-center imageRow">
|
||||
<div class="col-lg-12 mx-auto">
|
||||
<label id="presetSpeedLabel" for="presetSpeedInput">Preset Recall Speed: 5</label>
|
||||
<input id="presetSpeedInput" type="range" class="form-control-range" max="18" min="1" value="5" onchange="presetAction('speed', 'presetSpeedInput')">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col-lg-12 mx-auto">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon1">Preset:</span>
|
||||
</div>
|
||||
<input id="presetInput" class="form-control" placeholder="Preset Number (0 - 127)" aria-label="Preset number Input" aria-describedby="Camera Preset">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center imageRow">
|
||||
<div class="col mx-auto text-center">
|
||||
<button id="setPresetBtn" type="button" class="btn btn-sm btn-outline-dark" onclick="presetAction('set')">Set</button>
|
||||
</div>
|
||||
<div class="col mx-auto text-center">
|
||||
<button id="callPresetBtn" type="button" class="btn btn-sm btn-outline-dark" onclick="presetAction('call')">Call</button>
|
||||
</div>
|
||||
<div class="col mx-auto text-center">
|
||||
<button id="recallPresetBtn" type="button" class="btn btn-sm btn-outline-dark" onclick="presetAction('reset')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="content" class="container-fluid">
|
||||
<div class="modal fade" id="newCameraModal" tabindex="-1" role="dialog" aria-labelledby="cameraModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="cameraModalLabel">New Camera</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="needs-validation">
|
||||
<div class="form-group">
|
||||
<label for="cameraNickname">Name:</label>
|
||||
<input type="text" name="name" class="form-control" id="cameraNickname" placeholder="Camera Nickname">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cameraIpAddy">IP Address:</label>
|
||||
<input type="text" name="ip" class="form-control" id="cameraIpAddy" placeholder="xxx.xxx.xxx.x" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cameraPort">Port:</label>
|
||||
<input type="text" name="port" class="form-control" id="cameraPort" placeholder="5678" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cameraRtsp">RTSP:</label>
|
||||
<input type="text" name="rtsp" class="form-control" id="cameraRtsp" placeholder="xxx.xxx.xxx.x:554/1" required>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-outline-dark" onclick="addCamera();" data-dismiss="modal">Save Camera</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row topBtns">
|
||||
<div class="col-lg-8 text-center mx-auto">
|
||||
<button type="button" class="btn btn-sm btn-outline-info" onclick="toggleSideBar()">
|
||||
<i class="fas fa-align-left"></i>
|
||||
<span>Toggle Sidebar</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark" data-toggle="modal" data-target="#newCameraModal"><span>Add Camera</span></button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteCamera();"><span>Delete Camera</span></button>
|
||||
<button id="fullscreenToggle" type="button" class="btn btn-sm btn-outline-dark" onclick="reqFullScreen()"><i class="fas fa-arrows-alt"></i><span></span></button>
|
||||
<select id="cameraList" class="custom-select" onchange="changeStream();"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div id="stageContainer" class="text-center">
|
||||
<div id="msgStage" class="alert text-center mt-1"></div>
|
||||
<canvas id="streamStage" class="img-fluid mx-auto text-center" controls></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="/js/main.js"></script>
|
||||
<script type="text/javascript" src="/js/motion.js"></script>
|
||||
<script type="text/javascript" src="/js/image.js"></script>
|
||||
<script type="text/javascript" src="/js/focusZoom.js"></script>
|
||||
<script type="text/javascript" src="/js/jsmpeg.min.js"></script>
|
||||
<script type="text/javascript" src="/js/stream.js"></script>
|
||||
<script type="text/javascript" src="/js/preset.js"></script>
|
||||
<script type="text/javascript">
|
||||
getAllSavedCameras()
|
||||
.then((cameras) => {
|
||||
const camObj = JSON.parse(cameras);
|
||||
camObj.forEach(function(camera, index) {
|
||||
addCameraTag(camera, index);
|
||||
});
|
||||
}).then(() => {
|
||||
startStream();
|
||||
motionTouchEvents();
|
||||
focusTouchEvents('focus');
|
||||
})
|
||||
.catch((err => console.log(err)));
|
||||
</script>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
166
pub/js/focusZoom.js
Normal file
166
pub/js/focusZoom.js
Normal file
@@ -0,0 +1,166 @@
|
||||
/*jshint esversion: 6 */
|
||||
function focusTouchEvents() {
|
||||
const opts = ['tele', 'wide'];
|
||||
opts.forEach((opt) => {
|
||||
const eleId = 'focus' + opt.charAt(0).toUpperCase() + opt.slice(1);
|
||||
const ele = document.getElementById(eleId);
|
||||
ele.addEventListener('mousedown', variableFocus);
|
||||
ele.addEventListener('mouseup', stopFocus);
|
||||
ele.addEventListener('touchstart', variableFocus);
|
||||
ele.addEventListener('touchend', stopFocus);
|
||||
});
|
||||
zoomTouchEvents();
|
||||
}
|
||||
|
||||
function zoomTouchEvents() {
|
||||
const opts = ['tele', 'wide'];
|
||||
opts.forEach((opt) => {
|
||||
const eleId = 'zoom' + opt.charAt(0).toUpperCase() + opt.slice(1);
|
||||
const ele = document.getElementById(eleId);
|
||||
ele.addEventListener('mousedown', variableZoom);
|
||||
ele.addEventListener('mouseup', stopZoom);
|
||||
ele.addEventListener('touchstart', variableZoom);
|
||||
ele.addEventListener('touchend', stopZoom);
|
||||
});
|
||||
}
|
||||
|
||||
function getFocusSpeed() {
|
||||
return document.getElementById('focusSpeedInput').value;
|
||||
}
|
||||
|
||||
function getZoomSpeed() {
|
||||
return document.getElementById('zoomSpeedInput').value;
|
||||
}
|
||||
|
||||
function stopFocus(e) {
|
||||
e.preventDefault();
|
||||
stdFocus('stop');
|
||||
}
|
||||
|
||||
function stopZoom(e) {
|
||||
e.preventDefault();
|
||||
stdZoom('stop');
|
||||
}
|
||||
|
||||
function variableFocus(e) {
|
||||
e.preventDefault();
|
||||
const opt = e.currentTarget.getAttribute('data-value');
|
||||
const focusSpeed = getFocusSpeed();
|
||||
|
||||
const payload = {
|
||||
"mode": "variable",
|
||||
"option": opt,
|
||||
"intensity": focusSpeed
|
||||
};
|
||||
sendCmd("/ptz/focus", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("variableFocus res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function directFocus(focusPos) {
|
||||
const payload = {
|
||||
"mode": "direct",
|
||||
"focusPos": focusPos
|
||||
};
|
||||
sendCmd("/ptz/focus", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("directFocus res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function stdFocus(opt) {
|
||||
const payload = {
|
||||
"mode": "standard",
|
||||
"option": opt
|
||||
};
|
||||
sendCmd("/ptz/focus", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("stdFocus res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function focusMode() {
|
||||
const payload = {
|
||||
"mode": "focusmode",
|
||||
"option": document.getElementById('focusModeSel').selectedOptions[0].value
|
||||
};
|
||||
sendCmd("/ptz/focus", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("focusmode res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function afZone() {
|
||||
const payload = {
|
||||
"mode": "afzone",
|
||||
"option": document.getElementById('afZoneSel').selectedOptions[0].value
|
||||
};
|
||||
sendCmd("/ptz/focus", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("afzone res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
// **************************************** ZOOM *************************************
|
||||
|
||||
function variableZoom(e) {
|
||||
e.preventDefault();
|
||||
const opt = e.currentTarget.getAttribute('data-value');
|
||||
const zoomSpeed = getZoomSpeed();
|
||||
const payload = {
|
||||
"mode": "variable",
|
||||
"option": opt,
|
||||
"intensity": zoomSpeed
|
||||
};
|
||||
sendCmd("/ptz/zoom", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("variableZoom res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function stdZoom(opt) {
|
||||
const payload = {
|
||||
"mode": "standard",
|
||||
"option": opt
|
||||
};
|
||||
sendCmd("/ptz/zoom", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("stdZoom res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function directZoom(zoomPos) {
|
||||
const payload = {
|
||||
"mode": "direct",
|
||||
"zoomPos": zoomPos
|
||||
};
|
||||
sendCmd("/ptz/zoom", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("directZoom res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
237
pub/js/image.js
Normal file
237
pub/js/image.js
Normal file
@@ -0,0 +1,237 @@
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
function whiteBalance(mode) {
|
||||
let id;
|
||||
if (mode === 'wbmode') {
|
||||
id = "wbModeSel";
|
||||
} else {
|
||||
id = "awbSel";
|
||||
}
|
||||
|
||||
const payload = {
|
||||
"mode": mode,
|
||||
"option": document.getElementById(id).selectedOptions[0].value
|
||||
};
|
||||
sendCmd("/image/wb", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("white bal res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function autoExp() {
|
||||
const payload = {
|
||||
"option": document.getElementById("aeSel").selectedOptions[0].value
|
||||
};
|
||||
sendCmd("/image/ae", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("auto exp res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function rgain(mode, opt, pos) {
|
||||
const payload = {
|
||||
"mode": mode
|
||||
};
|
||||
if (mode === "direct") {
|
||||
payload.pos = pos;
|
||||
} else if (mode === "standard"){
|
||||
payload.option = opt;
|
||||
}
|
||||
sendCmd("/image/rgain", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("rgain res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function bgain(mode, opt, pos) {
|
||||
const payload = {
|
||||
"mode": mode
|
||||
};
|
||||
if (mode === "direct") {
|
||||
payload.pos = pos;
|
||||
} else if (mode === "standard"){
|
||||
payload.option = opt;
|
||||
}
|
||||
sendCmd("/image/bgain", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("bgain res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function shutter(mode, option) {
|
||||
const payload = {
|
||||
"mode": mode,
|
||||
"option": option
|
||||
};
|
||||
|
||||
sendCmd("/image/shutter", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("shutter res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function iris(mode, option) {
|
||||
const payload = {
|
||||
"mode": mode
|
||||
};
|
||||
|
||||
if (mode === "direct") {
|
||||
payload.pos = pos;
|
||||
} else if (mode === "standard"){
|
||||
payload.option = option;
|
||||
}
|
||||
|
||||
sendCmd("/image/iris", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("iris res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function gain(mode, opt) {
|
||||
const payload = {
|
||||
"mode": mode,
|
||||
"option": opt
|
||||
};
|
||||
|
||||
sendCmd("/image/gain", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("gain res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function backlight(opt) {
|
||||
const payload = {
|
||||
"option": opt
|
||||
};
|
||||
sendCmd("/image/backlight", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("backlight res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function blackWhite(opt) {
|
||||
const payload = {
|
||||
"option": opt
|
||||
};
|
||||
sendCmd("/image/bw", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("blackwhite res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function flicker(opt) {
|
||||
const payload = {
|
||||
"option": opt
|
||||
};
|
||||
sendCmd("/image/flicker", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("flicker res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function imgFlip(mode) {
|
||||
let opt;
|
||||
if (document.getElementById(mode).checked) {
|
||||
opt = 'on';
|
||||
} else {
|
||||
opt = 'off';
|
||||
}
|
||||
const payload = {
|
||||
"option": opt,
|
||||
"mode": mode
|
||||
};
|
||||
sendCmd("/image/imgFlip", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("image flip res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function changeInputLabel(setting) {
|
||||
const input = document.getElementById(setting + 'Input');
|
||||
const label = document.getElementById(setting + "InputLabel");
|
||||
if (setting === 'bright') {
|
||||
label.innerHTML = "Brightness: " + input.value;
|
||||
} else {
|
||||
label.innerHTML = setting.charAt(0).toUpperCase() + setting.slice(1) + ": " + input.value;
|
||||
}
|
||||
}
|
||||
|
||||
function colorHue() {
|
||||
changeInputLabel('colorHue');
|
||||
const payload = {
|
||||
"pos": document.getElementById('colorHueInput').value
|
||||
};
|
||||
sendCmd("/image/colorHue", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("color hue res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function brightness() {
|
||||
changeInputLabel('bright');
|
||||
const payload = {
|
||||
"pos": document.getElementById('brightInput').value
|
||||
};
|
||||
sendCmd("/image/bright", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("bright res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function contrast() {
|
||||
changeInputLabel('contrast');
|
||||
const payload = {
|
||||
"pos": document.getElementById('contrastInput').value
|
||||
};
|
||||
sendCmd("/image/contrast", "POST", payload)
|
||||
.then((res) => {
|
||||
alertMsg("contrast res: " + res);
|
||||
})
|
||||
.catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function saveSetting() {
|
||||
sendCmd("/image/save", "POST", {});
|
||||
}
|
||||
3
pub/js/jsmpeg.min.js
vendored
Normal file
3
pub/js/jsmpeg.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
149
pub/js/main.js
Normal file
149
pub/js/main.js
Normal file
@@ -0,0 +1,149 @@
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
function sendCmd(path, method, payload = {}) {
|
||||
const server = 'http://' + document.location.hostname + ':4000';
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(method, server + path);
|
||||
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
xhr.onload = function() {
|
||||
if (this.status >= 200 && this.status < 300) {
|
||||
resolve(xhr.response);
|
||||
} else {
|
||||
reject(xhr.response);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
reject(xhr.response);
|
||||
};
|
||||
if (method !== "GET") {
|
||||
payload.id = getCurrentCamera().value;
|
||||
xhr.send(JSON.stringify(payload));
|
||||
} else {
|
||||
xhr.send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function alertMsg(msg, err) {
|
||||
const msgStage = document.getElementById('msgStage');
|
||||
msgStage.style.display = "block";
|
||||
|
||||
if (err) {
|
||||
msgStage.classList.add("errMsg");
|
||||
setTimeout(() => {
|
||||
msgStage.classList.remove("errMsg");
|
||||
msgStage.style.display = "none";
|
||||
}, 4000);
|
||||
} else {
|
||||
msgStage.classList.add("successMsg");
|
||||
setTimeout(() => {
|
||||
msgStage.classList.remove("successMsg");
|
||||
msgStage.style.display = "none";
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
msgStage.innerHTML = msg;
|
||||
}
|
||||
|
||||
function getAllSavedCameras() {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(sendCmd('/camera/cameras', 'GET', null));
|
||||
});
|
||||
}
|
||||
|
||||
function getCurrentCamera() {
|
||||
const cameraSelectTag = document.getElementById('cameraList');
|
||||
return cameraSelectTag.options[cameraSelectTag.selectedIndex];
|
||||
}
|
||||
|
||||
function optionView(view) {
|
||||
document.getElementById("options").querySelectorAll("a.active")[0].classList.remove("active", "highlight");
|
||||
document.querySelectorAll("a[value=" + view + "]")[0].classList.add("active", "highlight");
|
||||
|
||||
const allOptionViews = document.getElementsByClassName('optionView');
|
||||
Array.prototype.forEach.call(allOptionViews, function(view) {
|
||||
view.style.display = "none";
|
||||
});
|
||||
document.getElementById(view).style.display = "block";
|
||||
}
|
||||
|
||||
Array.prototype.forEach.call(document.getElementsByClassName('panTiltInput'), function(input) {
|
||||
input.addEventListener('change', changeRangeInputLabel, false);
|
||||
});
|
||||
|
||||
function changeRangeInputLabel(e) {
|
||||
const identity = e.currentTarget.getAttribute('data-html');
|
||||
document.getElementById(identity + "SpeedLabel").innerHTML = identity.charAt(0).toUpperCase() + identity.slice(1) + " Speed: " + e.currentTarget.value;
|
||||
}
|
||||
|
||||
function addCamera() {
|
||||
const payload = {
|
||||
name: document.getElementById('cameraNickname').value,
|
||||
ip: document.getElementById('cameraIpAddy').value,
|
||||
port: document.getElementById('cameraPort').value,
|
||||
rtsp: document.getElementById('cameraRtsp').value
|
||||
};
|
||||
sendCmd('/camera/create', 'POST', payload)
|
||||
.then(function(res) {
|
||||
const camera = JSON.parse(res);
|
||||
addCameraTag(camera);
|
||||
alertMsg("Camera Successfully Added");
|
||||
})
|
||||
.catch(err => {
|
||||
alertMsg(err);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSideBar() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const content = document.getElementById('content');
|
||||
if(sidebar.classList.contains('active')) {
|
||||
sidebar.classList.remove('active');
|
||||
content.classList.remove('active');
|
||||
} else {
|
||||
sidebar.classList.add('active');
|
||||
content.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function addCameraTag(camera, index = 1) {
|
||||
const optTag = document.createElement("option");
|
||||
const eleId = camera.name || camera.ip;
|
||||
optTag.dataset.streamPort = camera.streamPort;
|
||||
if (index === 0) {
|
||||
optTag.setAttribute("selected", "selected");
|
||||
}
|
||||
optTag.appendChild(document.createTextNode(eleId));
|
||||
optTag.setAttribute("value", camera._id);
|
||||
document.getElementById('cameraList').appendChild(optTag);
|
||||
}
|
||||
|
||||
function deleteCamera() {
|
||||
const camera = getCurrentCamera();
|
||||
if(confirm("Would you like to delete " + camera.innerHTML + "?")) {
|
||||
sendCmd('/camera/', "DELETE")
|
||||
.then(() => {
|
||||
const cameraSelectTag = document.getElementById('cameraList');
|
||||
cameraSelectTag.remove(cameraSelectTag.selectedIndex);
|
||||
changeStream();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function reqFullScreen() {
|
||||
const doc = window.document;
|
||||
const docEl = doc.documentElement;
|
||||
|
||||
const requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
|
||||
const cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;
|
||||
|
||||
if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
|
||||
requestFullScreen.call(docEl);
|
||||
} else {
|
||||
cancelFullScreen.call(doc);
|
||||
}
|
||||
}
|
||||
116
pub/js/motion.js
Normal file
116
pub/js/motion.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/*jshint esversion: 6 */
|
||||
function motionTouchEvents() {
|
||||
const directions = ['right', 'left', 'up', 'down'];
|
||||
directions.forEach((direction) => {
|
||||
const eleId = 'motion' + direction.charAt(0).toUpperCase() + direction.slice(1);
|
||||
const ele = document.getElementById(eleId);
|
||||
ele.addEventListener('mousedown', stdMove);
|
||||
ele.addEventListener('mouseup', stopMotion);
|
||||
ele.addEventListener('touchstart', stdMove);
|
||||
ele.addEventListener('touchend', stopMotion);
|
||||
});
|
||||
}
|
||||
|
||||
function moveHome() {
|
||||
const payload = {mode: "home"};
|
||||
sendCmd("/ptz/motion", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("home res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function stopMotion(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const panTiltArr = getPanTiltSpeeds();
|
||||
const payload = {
|
||||
"mode": "standard",
|
||||
"direction": "stop",
|
||||
"panSpeed": panTiltArr[0],
|
||||
"tiltSpeed": panTiltArr[1]
|
||||
};
|
||||
sendCmd("/ptz/motion", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("continousMove_" + direction + " res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function stdMove(e) {
|
||||
e.preventDefault();
|
||||
const direction = e.target.getAttribute('data-value');
|
||||
const panTiltArr = getPanTiltSpeeds();
|
||||
|
||||
const payload = {
|
||||
"mode": "standard",
|
||||
"direction": direction,
|
||||
"panSpeed": panTiltArr[0],
|
||||
"tiltSpeed": panTiltArr[1]
|
||||
};
|
||||
sendCmd("/ptz/motion", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("continousMove_" + direction + " res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function getPanTiltSpeeds() {
|
||||
return [document.getElementById('panSpeedInput').value, document.getElementById('tiltSpeedInput').value];
|
||||
}
|
||||
|
||||
function moveAbsPos(pan, tilt) {
|
||||
const panTiltArr = getPanTiltSpeeds();
|
||||
const payload = {
|
||||
"mode": "absolute",
|
||||
"panSpeed": panTiltArr[0],
|
||||
"tiltSpeed": panTiltArr[1],
|
||||
"pan": pan,
|
||||
"tilt": tilt
|
||||
};
|
||||
sendCmd("/ptz/motion", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("moveAbsPos res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function moveRelPos(pan, tilt) {
|
||||
const panTiltArr = getPanTiltSpeeds();
|
||||
const payload = {
|
||||
"mode": "relative",
|
||||
"panSpeed": panTiltArr[0],
|
||||
"tiltSpeed": panTiltArr[1],
|
||||
"pan": pan,
|
||||
"tilt": tilt
|
||||
};
|
||||
sendCmd("/ptz/motion", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("moveRelPos res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function presets(mode, memNum) {
|
||||
const payload = {
|
||||
"mode": mode,
|
||||
"num": memNum
|
||||
};
|
||||
sendCmd("ptz/presets", "POST", payload)
|
||||
.then(function(res) {
|
||||
alertMsg("Preset res: " + res);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
39
pub/js/preset.js
Normal file
39
pub/js/preset.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
function presetAction(action, eleId = 'presetInput') {
|
||||
let payload = {
|
||||
mode: action
|
||||
};
|
||||
if (action === 'speed') {
|
||||
payload.speed = document.getElementById(eleId).value;
|
||||
changePresetSpeedLabel(payload.speed);
|
||||
} else {
|
||||
animateActionBtn(action);
|
||||
payload.memNum = document.getElementById(eleId).value;
|
||||
}
|
||||
|
||||
sendCmd('/ptz/presets', 'POST', payload)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
if (action !== 'speed' && res === "Socket1 Cmd Done" || action !== 'speed' && res === "Socket2 Cmd Done") {
|
||||
stopPresetBtnAnimate(action);
|
||||
}
|
||||
alertMsg("Preset Action res: " + res + " Payload: " + payload);
|
||||
}).catch((err) => {
|
||||
alertMsg(err, true);
|
||||
});
|
||||
}
|
||||
|
||||
function animateActionBtn(action) {
|
||||
const btn = document.getElementById(action + 'PresetBtn');
|
||||
btn.innerHTML = '<i class="fa fa-spinner fa-pulse"></i>';
|
||||
}
|
||||
|
||||
function stopPresetBtnAnimate(action) {
|
||||
const btn = document.getElementById(action + 'PresetBtn');
|
||||
btn.innerHTML = action.charAt(0).toUpperCase() + action.slice(1);
|
||||
}
|
||||
|
||||
function changePresetSpeedLabel(speed) {
|
||||
document.getElementById("presetSpeedLabel").innerHTML = "Preset Recall Speed: " + speed;
|
||||
}
|
||||
20
pub/js/stream.js
Normal file
20
pub/js/stream.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/*jshint esversion: 6 */
|
||||
let player;
|
||||
|
||||
function changeStream() {
|
||||
player.destroy();
|
||||
startStream();
|
||||
}
|
||||
|
||||
function startStream() {
|
||||
const canvas = document.getElementById('streamStage');
|
||||
const payload = {
|
||||
width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
|
||||
height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
|
||||
};
|
||||
|
||||
sendCmd('/camera/stream', 'POST', payload).then((camera) => {
|
||||
const streamPort = JSON.parse(camera);
|
||||
player = new JSMpeg.Player('ws://' + document.location.hostname + ':' + streamPort, {canvas:canvas});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user