Updated self-served client to new version
This commit is contained in:
parent
0e23ce8d0b
commit
a6332f4f30
2 changed files with 253 additions and 218 deletions
|
|
@ -1,19 +1,3 @@
|
||||||
/*
|
|
||||||
TODO: Make delete button work
|
|
||||||
|
|
||||||
TODO: Recordings list
|
|
||||||
TODO: New recording panel
|
|
||||||
TODO: Somehow have Python make funky thumbnails for videos?
|
|
||||||
|
|
||||||
TODO: Remember a position and restore that position
|
|
||||||
TODO: Right click to auto-focus, centered on that region
|
|
||||||
|
|
||||||
TODO: Box to specify device IP
|
|
||||||
TODO: Dynamically add stream image src from JS (allows streaming from an external IP)
|
|
||||||
*/
|
|
||||||
|
|
||||||
var baseURI = "/api/v1"
|
|
||||||
|
|
||||||
// Key IDs
|
// Key IDs
|
||||||
var pgupKeyID = 33;
|
var pgupKeyID = 33;
|
||||||
var pgdnKeyID = 34;
|
var pgdnKeyID = 34;
|
||||||
|
|
@ -28,71 +12,250 @@ var escKeyID = 27;
|
||||||
|
|
||||||
var keysDown = {}; //Array of keys down
|
var keysDown = {}; //Array of keys down
|
||||||
|
|
||||||
var stageVelocity = 50;
|
var clientStageParams = {
|
||||||
var focusVelocity = 20;
|
"velocityXY": 50,
|
||||||
|
"velocityZ": 20,
|
||||||
var requestLock = false;
|
"fov": [0, 0]
|
||||||
|
|
||||||
// Microscope client-side callibration
|
|
||||||
//TODO: Move to serverside microscope property
|
|
||||||
var fovX = 4100;
|
|
||||||
var fovY = 3146;
|
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
getStagePositions()
|
|
||||||
updateTextBoxes()
|
|
||||||
getCaptures()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Blank out interface except connect menu onload.
|
||||||
|
window.onload = function() {
|
||||||
|
// Populate with current URL
|
||||||
|
document.getElementById('microscopeHostInput').value = window.location.hostname
|
||||||
|
setHostFromInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Microscope API connection class
|
||||||
|
class apiConnection {
|
||||||
|
constructor(hostName, hostPort, apiVersion="v1") {
|
||||||
|
this.hostName = hostName;
|
||||||
|
this.hostPort = hostPort;
|
||||||
|
this.apiVersion = apiVersion;
|
||||||
|
|
||||||
|
this.baseURI = `http://${hostName}:${hostPort}/api/${apiVersion}`
|
||||||
|
|
||||||
|
this.requestLock = false;
|
||||||
|
|
||||||
|
// Used to access 'this' from innter functions
|
||||||
|
const self = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify
|
||||||
|
identify(callback) {
|
||||||
|
function identifyCallback(response, status) {
|
||||||
|
if (status == null) {
|
||||||
|
console.log("No server found. Aborting.")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(response, status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getConfig(identifyCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get microscope state
|
||||||
|
getState(callback) {
|
||||||
|
this.safeRequest("GET", this.baseURI+"/state", null, callback, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get microscope configuration
|
||||||
|
getConfig(callback) {
|
||||||
|
this.safeRequest("GET", this.baseURI+"/config", null, callback, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New capture
|
||||||
|
newCapture(filename, temporary, use_video_port, bayer, callback, resizeWidth=null, resizeHeight=null) {
|
||||||
|
var payload = {
|
||||||
|
"filename": filename,
|
||||||
|
"temporary": temporary,
|
||||||
|
"use_video_port": use_video_port,
|
||||||
|
"bayer": bayer
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((resizeWidth) && (resizeHeight)) {
|
||||||
|
payload.size = {
|
||||||
|
"width": resizeWidth,
|
||||||
|
"height": resizeHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(payload);
|
||||||
|
this.safeRequest("POST", this.baseURI+"/camera/capture/", payload, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a capture
|
||||||
|
deleteCapture(capture_id, callback) {
|
||||||
|
var r = confirm("Warning! This will delete all copies of this capture from the Raspberry Pi. Click OK to proceed.");
|
||||||
|
if (r == true) {
|
||||||
|
this.safeRequest("DELETE", this.baseURI+"/camera/capture/"+capture_id+"/", null, callback, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all captures in the session
|
||||||
|
deleteAllCaptures(callback) {
|
||||||
|
var r = confirm("Warning! This will delete all copies of all captures from the Raspberry Pi. Click OK to proceed.");
|
||||||
|
if (r == true) {
|
||||||
|
this.safeRequest("DELETE", this.baseURI+"/camera/capture/", null, callback, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of captures in the session
|
||||||
|
getCaptures(callback) {
|
||||||
|
this.safeRequest("GET", this.baseURI+"/camera/capture", null, callback, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move stage absolute
|
||||||
|
setStagePositions(x_abs, y_abs, z_abs, callback, absolute=false) {
|
||||||
|
// Make a position request
|
||||||
|
this.safeRequest("POST", this.baseURI+"/stage/position", { "absolute": absolute, "x": x_abs, "y": y_abs, "z": z_abs}, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method for making requests
|
||||||
|
safeRequest(method, url, payload, callback, lock=true, force=false) {
|
||||||
|
var allowRequest;
|
||||||
|
|
||||||
|
if (force == true) {
|
||||||
|
allowRequest = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
allowRequest = !(self.requestLock)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowRequest == true) {
|
||||||
|
var xhr = new XMLHttpRequest(); // new HttpRequest instance
|
||||||
|
xhr.open(method, url);
|
||||||
|
|
||||||
|
if (lock == true) { // If request is using the lock
|
||||||
|
self.requestLock = true; // Hold the lock
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.onload = function(e) {
|
||||||
|
if (xhr.readyState === 4) {
|
||||||
|
if (lock == true) { // If request is using the lock
|
||||||
|
self.requestLock = false; // Release the lock
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xhr.status !== 200) {
|
||||||
|
console.error(xhr.statusText);
|
||||||
|
}
|
||||||
|
callback(JSON.parse(xhr.responseText), xhr.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = function(e) {
|
||||||
|
callback("An error occurred during the transaction.", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "POST" || method == "PUT") {
|
||||||
|
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send(JSON.stringify(payload));
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("Cannot start the following request while the previous requets is pending:")
|
||||||
|
console.log(method, url, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declare connection
|
||||||
|
var api = null
|
||||||
|
|
||||||
|
// Setup methods
|
||||||
|
function setHostFromInput() {
|
||||||
|
hostName = document.getElementById('microscopeHostInput').value;
|
||||||
|
hostPort = document.getElementById('microscopePortInput').value;
|
||||||
|
|
||||||
|
api = new apiConnection(hostName, hostPort)
|
||||||
|
api.identify(loadInterfaceFromHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the UI from a connected host
|
||||||
|
function loadInterfaceFromHost(response, status) {
|
||||||
|
if (status == 200) {
|
||||||
|
// Populate the preview panel
|
||||||
|
streamContent = `<img src="${api.baseURI}/stream" ondblclick="clickHotspotImage(event);">`
|
||||||
|
document.getElementById("streambox").innerHTML = streamContent;
|
||||||
|
|
||||||
|
// Update UI with client params
|
||||||
|
updateClientValues();
|
||||||
|
|
||||||
|
// Update UI with microscope state
|
||||||
|
api.getState(updateStateValues)
|
||||||
|
|
||||||
|
// Update UI with microscope config
|
||||||
|
api.getConfig(updateConfigValues)
|
||||||
|
|
||||||
|
// Update UI with captures
|
||||||
|
api.getCaptures(constructCaptureList)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateClientValues() {
|
||||||
|
// Microscope velocity
|
||||||
|
document.getElementById('stageVelocityText').value = clientStageParams.velocityXY;
|
||||||
|
document.getElementById('stageVelocityInput').value = clientStageParams.velocityXY;
|
||||||
|
document.getElementById('focusVelocityText').value = clientStageParams.velocityZ;
|
||||||
|
document.getElementById('focusVelocityInput').value = clientStageParams.velocityZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStateValues(response, status){
|
||||||
|
if (status == 200) {
|
||||||
|
updatePositionValues(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateConfigValues(response, status){
|
||||||
|
if (status == 200) {
|
||||||
|
updateFovValues(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePositionValues(state) {
|
||||||
|
document.getElementById('x_abs').value = state.stage.position.x;
|
||||||
|
document.getElementById('y_abs').value = state.stage.position.y;
|
||||||
|
document.getElementById('z_abs').value = state.stage.position.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFovValues(config) {
|
||||||
|
clientStageParams.fov = config.fov
|
||||||
|
console.log(clientStageParams.fov)
|
||||||
|
}
|
||||||
|
|
||||||
// Cosmetic methods
|
// Cosmetic methods
|
||||||
|
|
||||||
|
// Adds/removes a class to a specified div
|
||||||
function toggleClassToDiv(div_id, class_name) {
|
function toggleClassToDiv(div_id, class_name) {
|
||||||
document.getElementById(div_id).classList.toggle(class_name)
|
document.getElementById(div_id).classList.toggle(class_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Microscope methods
|
function updateCaptures() {
|
||||||
|
api.getCaptures(constructCaptureList)
|
||||||
function deleteCapture(capture_id) {
|
|
||||||
function deleteCaptureCallback(response, status) {
|
|
||||||
console.log(status);
|
|
||||||
getCaptures();
|
|
||||||
}
|
|
||||||
var r = confirm("Warning! This will delete all copies of this capture from the Raspberry Pi. Click OK to proceed.");
|
|
||||||
if (r == true) {
|
|
||||||
safeRequest("DELETE", baseURI+"/camera/capture/"+capture_id+"/", null, deleteCaptureCallback, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteAllCaptures() {
|
function deleteAllCaptures() {
|
||||||
function deleteAllCapturesCallback(response, status) {
|
api.deleteAllCaptures(updateCaptures)
|
||||||
console.log(status);
|
|
||||||
getCaptures();
|
|
||||||
}
|
|
||||||
var r = confirm("Warning! This will delete all copies of all captures from the Raspberry Pi. Click OK to proceed.");
|
|
||||||
if (r == true) {
|
|
||||||
safeRequest("DELETE", baseURI+"/camera/capture/", null, deleteAllCapturesCallback, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCaptures() {
|
function constructCaptureList(response) {
|
||||||
function updateCapturesCallback(response, status) {
|
|
||||||
console.log(status);
|
|
||||||
updateCaptureList(response);
|
|
||||||
}
|
|
||||||
safeRequest("GET", baseURI+"/camera/capture", null, updateCapturesCallback, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCaptureList(response) {
|
|
||||||
// Clear captures list
|
// Clear captures list
|
||||||
var capturesNode = document.getElementById("captures");
|
var capturesNode = document.getElementById("captures");
|
||||||
|
|
||||||
while (capturesNode.firstChild) {
|
while (capturesNode.firstChild) {
|
||||||
capturesNode.removeChild(capturesNode.firstChild);
|
capturesNode.removeChild(capturesNode.firstChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reverse so newest capture appears first
|
||||||
|
response.reverse()
|
||||||
|
|
||||||
// For each capture in the response array
|
// For each capture in the response array
|
||||||
response.forEach(function(element) {
|
response.forEach(function(element) {
|
||||||
// Store the capture object URI
|
// Store the capture object URI
|
||||||
element_uri = `${baseURI}/camera/capture/${element.metadata.id}`
|
element_uri = `${api.baseURI}/camera/capture/${element.metadata.id}`
|
||||||
|
|
||||||
// Generate inner HTML from capture object
|
// Generate inner HTML from capture object
|
||||||
html = `
|
html = `
|
||||||
|
|
@ -104,7 +267,7 @@ function updateCaptureList(response) {
|
||||||
<button type="button" class="capture-button" onclick="window.open('${element_uri}/metadata');">Metadata</button>
|
<button type="button" class="capture-button" onclick="window.open('${element_uri}/metadata');">Metadata</button>
|
||||||
<br>
|
<br>
|
||||||
<button type="button" class="capture-button" onclick="window.open('${element_uri}/', '_blank');">JSON</button>
|
<button type="button" class="capture-button" onclick="window.open('${element_uri}/', '_blank');">JSON</button>
|
||||||
<button type="button" class="capture-button" onclick="deleteCapture('${element.metadata.id}');">Delete</button>
|
<button type="button" class="capture-button" onclick="api.deleteCapture('${element.metadata.id}', constructCaptureList);">Delete</button>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
@ -118,59 +281,6 @@ function updateCaptureList(response) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTextBoxes() {
|
|
||||||
document.getElementById('stageVelocityText').value = stageVelocity;
|
|
||||||
document.getElementById('stageVelocityInput').value = stageVelocity;
|
|
||||||
document.getElementById('focusVelocityText').value = focusVelocity;
|
|
||||||
document.getElementById('focusVelocityInput').value = focusVelocity;
|
|
||||||
|
|
||||||
document.getElementById('fovXText').value = fovX;
|
|
||||||
document.getElementById('fovYText').value = fovY;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStagePositions(response) {
|
|
||||||
document.getElementById('x_abs').value = response.x;
|
|
||||||
document.getElementById('y_abs').value = response.y;
|
|
||||||
document.getElementById('z_abs').value = response.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStagePositions() {
|
|
||||||
function updatePositionCallback(response, status) {
|
|
||||||
console.log(status, response);
|
|
||||||
updateStagePositions(response);
|
|
||||||
}
|
|
||||||
safeRequest("GET", baseURI+"/stage/position", null, updatePositionCallback, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capture methods
|
|
||||||
function newCapture(filename, temporary, use_video_port, bayer, resizeWidth=null, resizeHeight=null) {
|
|
||||||
// Make a position request
|
|
||||||
function newCaptureCallback(response, status) {
|
|
||||||
if (status != 200) {
|
|
||||||
alert("Capture failed.");
|
|
||||||
}
|
|
||||||
console.log(status, response);
|
|
||||||
getCaptures(); // Update full list of captures when done
|
|
||||||
}
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"filename": filename,
|
|
||||||
"temporary": temporary,
|
|
||||||
"use_video_port": use_video_port,
|
|
||||||
"bayer": bayer
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((resizeWidth) && (resizeHeight)) {
|
|
||||||
payload.size = {
|
|
||||||
"width": resizeWidth,
|
|
||||||
"height": resizeHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(payload);
|
|
||||||
safeRequest("POST", baseURI+"/camera/capture/", payload, newCaptureCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function newCaptureFromInput() {
|
function newCaptureFromInput() {
|
||||||
captureFilenameInput = document.getElementById('captureFilenameInput');
|
captureFilenameInput = document.getElementById('captureFilenameInput');
|
||||||
captureTemporaryCheck = document.getElementById('captureTemporaryCheck');
|
captureTemporaryCheck = document.getElementById('captureTemporaryCheck');
|
||||||
|
|
@ -198,13 +308,15 @@ function newCaptureFromInput() {
|
||||||
resizeHeight = null;
|
resizeHeight = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
newCapture(
|
// Make a capture request
|
||||||
|
api.newCapture(
|
||||||
filename,
|
filename,
|
||||||
captureTemporaryCheck.checked,
|
captureTemporaryCheck.checked,
|
||||||
!(captureFullResolutionCheck.checked),
|
!(captureFullResolutionCheck.checked),
|
||||||
captureBayerCheck.checked,
|
captureBayerCheck.checked,
|
||||||
resizeWidth,
|
updateCaptures,
|
||||||
resizeHeight
|
resizeWidth=resizeWidth,
|
||||||
|
resizeHeight=resizeHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -218,43 +330,14 @@ function newCaptureResizeToggle(checkbox) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move stage methods
|
// Move stage methods
|
||||||
// TODO: Combine setStagePositions and moveStagePositions, with bool argument for 'absolute'
|
|
||||||
|
|
||||||
function setStagePositions(x_abs, y_abs, z_abs) {
|
|
||||||
// Make a position request
|
|
||||||
function absMoveCallback(response, status) {
|
|
||||||
if (status != 200) {
|
|
||||||
alert("Error moving stage.");
|
|
||||||
}
|
|
||||||
console.log(status, response);
|
|
||||||
updateStagePositions(response);
|
|
||||||
}
|
|
||||||
safeRequest("POST", baseURI+"/stage/position", { "absolute": true, "x": x_abs, "y": y_abs, "z": z_abs}, absMoveCallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveStagePositions(x_rel, y_rel, z_rel) {
|
|
||||||
// Make a position request
|
|
||||||
function relMoveCallback(response, status) {
|
|
||||||
if (status != 200) {
|
|
||||||
alert("Error moving stage.");
|
|
||||||
}
|
|
||||||
console.log(status, response);
|
|
||||||
updateStagePositions(response);
|
|
||||||
}
|
|
||||||
safeRequest("POST", baseURI+"/stage/position", { "absolute": false, "x": x_rel, "y": y_rel, "z": z_rel}, relMoveCallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
function setStagePositionsFromInput() {
|
function setStagePositionsFromInput() {
|
||||||
x_abs = Number(document.getElementById('x_abs').value);
|
x_abs = Number(document.getElementById('x_abs').value);
|
||||||
y_abs = Number(document.getElementById('y_abs').value);
|
y_abs = Number(document.getElementById('y_abs').value);
|
||||||
z_abs = Number(document.getElementById('z_abs').value);
|
z_abs = Number(document.getElementById('z_abs').value);
|
||||||
setStagePositions(x_abs, y_abs, z_abs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Standard callback for user-controller movement
|
// Make a position request
|
||||||
function keyMoveCallback(response, status) {
|
api.setStagePositions(x_abs, y_abs, z_abs, updatePositionValues, absolute=true)
|
||||||
console.log(status, response);
|
|
||||||
updateStagePositions(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods for input events
|
// Methods for input events
|
||||||
|
|
@ -268,30 +351,31 @@ function clickHotspotImage(event) {
|
||||||
xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
||||||
yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
||||||
console.log(xRelative, yRelative)
|
console.log(xRelative, yRelative)
|
||||||
xSteps = xRelative * fovX;
|
xSteps = xRelative * clientStageParams.fov[0];
|
||||||
ySteps = yRelative * fovY;
|
ySteps = yRelative * clientStageParams.fov[1];
|
||||||
console.log(xSteps, ySteps, 0)
|
console.log(xSteps, ySteps, 0)
|
||||||
|
|
||||||
// Make a position request
|
// Make a position request
|
||||||
moveStagePositions(xSteps, ySteps, 0)
|
api.setStagePositions(xSteps, ySteps, 0, updatePositionValues)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll-to-focus
|
// Scroll-to-focus
|
||||||
window.addEventListener('wheel', function(e) {
|
window.addEventListener('wheel', function(e) {
|
||||||
multiplier = 1/100;
|
multiplier = 1/100;
|
||||||
z_delta = e.deltaY * multiplier * focusVelocity;
|
z_delta = e.deltaY * multiplier * clientStageParams.velocityZ;
|
||||||
if ((document.getElementById("scrollFocusCheck").checked == true) && (e.target.parentNode.classList.value == "column middle")) {
|
if ((document.getElementById("scrollFocusCheck").checked == true) && (e.target.parentNode.classList.value == "scrolltarget")) {
|
||||||
console.log(z_delta);
|
console.log(z_delta);
|
||||||
console.log(e.target.parentNode.classList.value);
|
console.log(e.target.parentNode.classList.value);
|
||||||
|
|
||||||
// Make a position request
|
// Make a position request
|
||||||
safeRequest("POST", baseURI+"/stage/position", { "absolute": false, "z": z_delta}, keyMoveCallback)
|
api.setStagePositions(0, 0, z_delta, updatePositionValues)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Keyboard to move
|
// Keyboard to move
|
||||||
addEventListener("keydown", function (e) {
|
addEventListener("keydown", function (e) {
|
||||||
keysDown[e.keyCode] = true; //Add key to array
|
keysDown[e.keyCode] = true; //Add key to array
|
||||||
console.log(keysDown)
|
|
||||||
|
|
||||||
// If not currently in an input box
|
// If not currently in an input box
|
||||||
if (!(e.target instanceof HTMLInputElement)) {
|
if (!(e.target instanceof HTMLInputElement)) {
|
||||||
|
|
@ -304,26 +388,26 @@ addEventListener("keydown", function (e) {
|
||||||
y_rel = 0;
|
y_rel = 0;
|
||||||
z_rel = 0;
|
z_rel = 0;
|
||||||
if (leftKeyID in keysDown) {
|
if (leftKeyID in keysDown) {
|
||||||
x_rel = x_rel + stageVelocity;
|
x_rel = x_rel + clientStageParams.velocityXY;
|
||||||
}
|
}
|
||||||
if (rightKeyID in keysDown) {
|
if (rightKeyID in keysDown) {
|
||||||
x_rel = x_rel - stageVelocity;
|
x_rel = x_rel - clientStageParams.velocityXY;
|
||||||
}
|
}
|
||||||
if (upKeyID in keysDown) {
|
if (upKeyID in keysDown) {
|
||||||
y_rel = y_rel + stageVelocity;
|
y_rel = y_rel + clientStageParams.velocityXY;
|
||||||
}
|
}
|
||||||
if (downKeyID in keysDown) {
|
if (downKeyID in keysDown) {
|
||||||
y_rel = y_rel - stageVelocity;
|
y_rel = y_rel - clientStageParams.velocityXY;
|
||||||
}
|
}
|
||||||
if (pgupKeyID in keysDown) {
|
if (pgupKeyID in keysDown) {
|
||||||
z_rel = z_rel - focusVelocity;
|
z_rel = z_rel - clientStageParams.velocityZ;
|
||||||
}
|
}
|
||||||
if (pgdnKeyID in keysDown) {
|
if (pgdnKeyID in keysDown) {
|
||||||
z_rel = z_rel + focusVelocity;
|
z_rel = z_rel + clientStageParams.velocityZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a position request
|
// Make a position request
|
||||||
moveStagePositions(x_rel, y_rel, z_rel)
|
api.setStagePositions(x_rel, y_rel, z_rel, updatePositionValues)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,44 +417,4 @@ addEventListener("keyup", function (e) {
|
||||||
delete keysDown[e.keyCode]; //Remove key from array
|
delete keysDown[e.keyCode]; //Remove key from array
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
// Methods for making requests
|
|
||||||
function safeRequest(method, url, payload, callback, lock=true, force=false) {
|
|
||||||
if (force == true) {
|
|
||||||
allowRequest = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
allowRequest = !(requestLock);
|
|
||||||
}
|
|
||||||
if (allowRequest == true) {
|
|
||||||
var xhr = new XMLHttpRequest(); // new HttpRequest instance
|
|
||||||
xhr.open(method, url);
|
|
||||||
|
|
||||||
if (lock == true) { // If request is using the lock
|
|
||||||
requestLock = true; // Hold the lock
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.onload = function (e) {
|
|
||||||
if (xhr.readyState === 4) {
|
|
||||||
if (lock == true) { // If request is using the lock
|
|
||||||
requestLock = false; // Release the lock
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xhr.status !== 200) {
|
|
||||||
console.error(xhr.statusText);
|
|
||||||
}
|
|
||||||
callback(JSON.parse(xhr.responseText), xhr.status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (method == "POST" || method == "PUT") {
|
|
||||||
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.send(JSON.stringify(payload));
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log("Cannot start the following request while the previous requets is pending:")
|
|
||||||
console.log(method, url, payload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,15 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui, maximum-scale=1.0, user-scalable=0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui, maximum-scale=1.0, user-scalable=0">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column left" id="left-sb">
|
<div class="column left" id="left-sb">
|
||||||
<h2>Settings</h2>
|
<h2>Settings</h2>
|
||||||
|
Host: <input type="text" id="microscopeHostInput" value="localhost"><br>
|
||||||
|
Port: <input type="number" id="microscopePortInput" value=5000><br>
|
||||||
|
<button type="button" onclick="setHostFromInput();">Connect</button>
|
||||||
|
|
||||||
<h3>Position</h3>
|
<h3>Position</h3>
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -27,19 +31,6 @@
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Doubleclick to position: <input type="checkbox" id="clickPositionCheck" checked><br>
|
Doubleclick to position: <input type="checkbox" id="clickPositionCheck" checked><br>
|
||||||
<div class="flexbox">
|
|
||||||
<div class="flexgrow">FOV width:</div>
|
|
||||||
<div>
|
|
||||||
<input type="number" id="fovXText" onchange="fovX = Number(this.value); updateTextBoxes();" style="width: 7em" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flexbox">
|
|
||||||
<div class="flexgrow">FOV height:</div>
|
|
||||||
<div>
|
|
||||||
<input type="number" id="fovYText" onchange="fovY = Number(this.value); updateTextBoxes();" style="width: 7em" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -56,14 +47,14 @@
|
||||||
<div class="flexbox">
|
<div class="flexbox">
|
||||||
<div class="flexgrow">x-y:</div>
|
<div class="flexgrow">x-y:</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="range" id="stageVelocityInput" min="50" max="200" oninput="stageVelocity = Number(this.value); updateTextBoxes();">
|
<input type="range" id="stageVelocityInput" min="50" max="200" oninput="clientStageParams.velocityXY = Number(this.value); updateClientValues();">
|
||||||
<input type="text" id="stageVelocityText" size="3" disabled>
|
<input type="text" id="stageVelocityText" size="3" disabled>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flexbox">
|
<div class="flexbox">
|
||||||
<div class="flexgrow">z:</div>
|
<div class="flexgrow">z:</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="range" id="focusVelocityInput" min="10" max="100" oninput="focusVelocity = Number(this.value); updateTextBoxes();">
|
<input type="range" id="focusVelocityInput" min="10" max="100" oninput="clientStageParams.velocityZ = Number(this.value); updateClientValues();">
|
||||||
<input type="text" id="focusVelocityText" size="3" disabled>
|
<input type="text" id="focusVelocityText" size="3" disabled>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -84,7 +75,7 @@
|
||||||
<img src="{{url_for('static', filename='icons/baseline-camera_alt-24px.svg')}}">
|
<img src="{{url_for('static', filename='icons/baseline-camera_alt-24px.svg')}}">
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<img src="/api/v1/stream" ondblclick="clickHotspotImage(event);">
|
<div class="scrolltarget" id="streambox">No active stream</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column right" id="right-sb">
|
<div class="column right" id="right-sb">
|
||||||
|
|
@ -101,7 +92,7 @@
|
||||||
<button type="button" onclick="newCaptureFromInput();">Capture</button>
|
<button type="button" onclick="newCaptureFromInput();">Capture</button>
|
||||||
|
|
||||||
<h2>Captures</h2>
|
<h2>Captures</h2>
|
||||||
<button type="button" onclick="getCaptures();">Update</button>
|
<button type="button" onclick="updateCaptures();">Update</button>
|
||||||
<button type="button" onclick="deleteAllCaptures();">Delete all</button>
|
<button type="button" onclick="deleteAllCaptures();">Delete all</button>
|
||||||
<div id="captures"></div>
|
<div id="captures"></div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue