Merge branch '1.0.1-dev' into 'master'
Removed old client from API root See merge request openflexure/openflexure-microscope-server!13
This commit is contained in:
commit
5f1e17e1da
6 changed files with 0 additions and 666 deletions
|
|
@ -110,15 +110,6 @@ app.register_blueprint(plugin_blueprint, url_prefix=uri('/plugin', 'v1'))
|
||||||
task_blueprint = blueprints.task.construct_blueprint(api_microscope)
|
task_blueprint = blueprints.task.construct_blueprint(api_microscope)
|
||||||
app.register_blueprint(task_blueprint, url_prefix=uri('/task', 'v1'))
|
app.register_blueprint(task_blueprint, url_prefix=uri('/task', 'v1'))
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def index():
|
|
||||||
"""
|
|
||||||
API demo app
|
|
||||||
"""
|
|
||||||
return render_template(
|
|
||||||
'index_v1.html'
|
|
||||||
)
|
|
||||||
|
|
||||||
@app.route('/routes')
|
@app.route('/routes')
|
||||||
def routes():
|
def routes():
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3.2"/><path d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 324 B |
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><path fill="none" d="M0 0h20v20H0V0z"/><path d="M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 774 B |
|
|
@ -1,418 +0,0 @@
|
||||||
// Key IDs
|
|
||||||
var pgupKeyID = 33;
|
|
||||||
var pgdnKeyID = 34;
|
|
||||||
|
|
||||||
var leftKeyID = 37;
|
|
||||||
var upKeyID = 38;
|
|
||||||
var rightKeyID = 39;
|
|
||||||
var downKeyID = 40;
|
|
||||||
|
|
||||||
var enterKeyID = 13;
|
|
||||||
var escKeyID = 27;
|
|
||||||
|
|
||||||
var keysDown = {}; //Array of keys down
|
|
||||||
|
|
||||||
var clientStageParams = {
|
|
||||||
"velocityXY": 50,
|
|
||||||
"velocityZ": 20,
|
|
||||||
"fov": [0, 0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// Adds/removes a class to a specified div
|
|
||||||
function toggleClassToDiv(div_id, class_name) {
|
|
||||||
document.getElementById(div_id).classList.toggle(class_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCaptures() {
|
|
||||||
api.getCaptures(constructCaptureList)
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteAllCaptures() {
|
|
||||||
api.deleteAllCaptures(updateCaptures)
|
|
||||||
}
|
|
||||||
|
|
||||||
function constructCaptureList(response) {
|
|
||||||
// Clear captures list
|
|
||||||
var capturesNode = document.getElementById("captures");
|
|
||||||
|
|
||||||
while (capturesNode.firstChild) {
|
|
||||||
capturesNode.removeChild(capturesNode.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse so newest capture appears first
|
|
||||||
response.reverse()
|
|
||||||
|
|
||||||
// For each capture in the response array
|
|
||||||
response.forEach(function(element) {
|
|
||||||
// Store the capture object URI
|
|
||||||
element_uri = `${api.baseURI}/camera/capture/${element.metadata.id}`
|
|
||||||
|
|
||||||
// Generate inner HTML from capture object
|
|
||||||
html = `
|
|
||||||
<div class="capture-thumb"><img src="${element_uri}/download?thumbnail=true"></div>
|
|
||||||
<div class="capture-actions">
|
|
||||||
<div class='capture-heading'>${element.metadata.filename}</div>
|
|
||||||
<br>
|
|
||||||
<button type="button" class="capture-button" onclick="window.open('${element_uri}/download');">Image</button>
|
|
||||||
<button type="button" class="capture-button" onclick="window.open('${element_uri}/metadata');">Metadata</button>
|
|
||||||
<br>
|
|
||||||
<button type="button" class="capture-button" onclick="window.open('${element_uri}/', '_blank');">JSON</button>
|
|
||||||
<button type="button" class="capture-button" onclick="api.deleteCapture('${element.metadata.id}', constructCaptureList);">Delete</button>
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
|
|
||||||
// Create a new capture div, and append HTML
|
|
||||||
var div = document.createElement("div");
|
|
||||||
div.className = "capture";
|
|
||||||
div.innerHTML = html;
|
|
||||||
capturesNode.appendChild(div);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function newCaptureFromInput() {
|
|
||||||
captureFilenameInput = document.getElementById('captureFilenameInput');
|
|
||||||
captureTemporaryCheck = document.getElementById('captureTemporaryCheck');
|
|
||||||
captureFullResolutionCheck = document.getElementById('captureFullResolutionCheck');
|
|
||||||
captureBayerCheck = document.getElementById('captureBayerCheck')
|
|
||||||
|
|
||||||
captureResizeCheck = document.getElementById('captureResizeCheck');
|
|
||||||
captureWidthInput = document.getElementById('captureWidthInput')
|
|
||||||
captureHeightInput = document.getElementById('captureHeightInput')
|
|
||||||
|
|
||||||
// Get filename if one is given
|
|
||||||
if (captureFilenameInput.value === "") {
|
|
||||||
filename = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
filename = captureFilenameInput.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (captureResizeCheck.checked) {
|
|
||||||
resizeWidth = Number(captureWidthInput.value);
|
|
||||||
resizeHeight = Number(captureHeightInput.value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
resizeWidth = null;
|
|
||||||
resizeHeight = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a capture request
|
|
||||||
api.newCapture(
|
|
||||||
filename,
|
|
||||||
captureTemporaryCheck.checked,
|
|
||||||
!(captureFullResolutionCheck.checked),
|
|
||||||
captureBayerCheck.checked,
|
|
||||||
updateCaptures,
|
|
||||||
resizeWidth=resizeWidth,
|
|
||||||
resizeHeight=resizeHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function newCaptureResizeToggle(checkbox) {
|
|
||||||
captureWidthInput = document.getElementById('captureWidthInput')
|
|
||||||
captureHeightInput = document.getElementById('captureHeightInput')
|
|
||||||
|
|
||||||
captureWidthInput.disabled = !(checkbox.checked)
|
|
||||||
captureHeightInput.disabled = !(checkbox.checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move stage methods
|
|
||||||
|
|
||||||
function setStagePositionsFromInput() {
|
|
||||||
x_abs = Number(document.getElementById('x_abs').value);
|
|
||||||
y_abs = Number(document.getElementById('y_abs').value);
|
|
||||||
z_abs = Number(document.getElementById('z_abs').value);
|
|
||||||
|
|
||||||
// Make a position request
|
|
||||||
api.setStagePositions(x_abs, y_abs, z_abs, updatePositionValues, absolute=true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods for input events
|
|
||||||
|
|
||||||
// Click-to-move
|
|
||||||
function clickHotspotImage(event) {
|
|
||||||
if (document.getElementById("clickPositionCheck").checked == true) {
|
|
||||||
xCoordinate = event.offsetX;
|
|
||||||
yCoordinate = event.offsetY;
|
|
||||||
console.log(xCoordinate, yCoordinate)
|
|
||||||
xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
|
||||||
yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
|
||||||
console.log(xRelative, yRelative)
|
|
||||||
xSteps = xRelative * clientStageParams.fov[0];
|
|
||||||
ySteps = yRelative * clientStageParams.fov[1];
|
|
||||||
console.log(xSteps, ySteps, 0)
|
|
||||||
|
|
||||||
// Make a position request
|
|
||||||
api.setStagePositions(xSteps, ySteps, 0, updatePositionValues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll-to-focus
|
|
||||||
window.addEventListener('wheel', function(e) {
|
|
||||||
multiplier = 1/100;
|
|
||||||
z_delta = e.deltaY * multiplier * clientStageParams.velocityZ;
|
|
||||||
if ((document.getElementById("scrollFocusCheck").checked == true) && (e.target.parentNode.classList.value == "scrolltarget")) {
|
|
||||||
console.log(z_delta);
|
|
||||||
console.log(e.target.parentNode.classList.value);
|
|
||||||
|
|
||||||
// Make a position request
|
|
||||||
api.setStagePositions(0, 0, z_delta, updatePositionValues)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keyboard to move
|
|
||||||
addEventListener("keydown", function (e) {
|
|
||||||
keysDown[e.keyCode] = true; //Add key to array
|
|
||||||
|
|
||||||
// If not currently in an input box
|
|
||||||
if (!(e.target instanceof HTMLInputElement)) {
|
|
||||||
// If stage movement keys are pressed
|
|
||||||
if ((leftKeyID in keysDown) || (rightKeyID in keysDown) || (upKeyID in keysDown) || (downKeyID in keysDown) || (pgupKeyID in keysDown) || (pgdnKeyID in keysDown)) {
|
|
||||||
// Calculate movement array
|
|
||||||
x_rel = 0;
|
|
||||||
y_rel = 0;
|
|
||||||
z_rel = 0;
|
|
||||||
if (leftKeyID in keysDown) {
|
|
||||||
x_rel = x_rel + clientStageParams.velocityXY;
|
|
||||||
}
|
|
||||||
if (rightKeyID in keysDown) {
|
|
||||||
x_rel = x_rel - clientStageParams.velocityXY;
|
|
||||||
}
|
|
||||||
if (upKeyID in keysDown) {
|
|
||||||
y_rel = y_rel + clientStageParams.velocityXY;
|
|
||||||
}
|
|
||||||
if (downKeyID in keysDown) {
|
|
||||||
y_rel = y_rel - clientStageParams.velocityXY;
|
|
||||||
}
|
|
||||||
if (pgupKeyID in keysDown) {
|
|
||||||
z_rel = z_rel - clientStageParams.velocityZ;
|
|
||||||
}
|
|
||||||
if (pgdnKeyID in keysDown) {
|
|
||||||
z_rel = z_rel + clientStageParams.velocityZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a position request
|
|
||||||
api.setStagePositions(x_rel, y_rel, z_rel, updatePositionValues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
addEventListener("keyup", function (e) {
|
|
||||||
delete keysDown[e.keyCode]; //Remove key from array
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,132 +0,0 @@
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Preview sizing */
|
|
||||||
.middle img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: contain
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create columns that float next to each other */
|
|
||||||
.column {
|
|
||||||
padding: 10px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left, .right {
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
overflow-y: scroll;
|
|
||||||
flex: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
flex-basis: 250px;
|
|
||||||
-webkit-transition: all 0.2s ease-in-out;
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left{
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right{
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden{
|
|
||||||
flex-basis: 0;
|
|
||||||
padding:0
|
|
||||||
}
|
|
||||||
|
|
||||||
.middle {
|
|
||||||
position: relative;
|
|
||||||
flex-grow: 1;
|
|
||||||
background-color: #d3d3d3;
|
|
||||||
}
|
|
||||||
|
|
||||||
#left-sb-btn {
|
|
||||||
left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#right-sb-btn {
|
|
||||||
right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sb-btn {
|
|
||||||
top: 20px;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sb-btn button{
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
margin: 0;
|
|
||||||
padding:5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear floats after the columns */
|
|
||||||
.row{
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flexboxes */
|
|
||||||
.flexbox {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flexgrow {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Data divs */
|
|
||||||
|
|
||||||
#captures {
|
|
||||||
font-size:12px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.capture {
|
|
||||||
height: 75px;
|
|
||||||
width: 240px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
background-color: #d3d3d3;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.capture-thumb {
|
|
||||||
width: 80px;
|
|
||||||
height: 75px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.capture-heading {
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 5px 0 5px 0;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.capture-actions {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.capture img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.capture-button {
|
|
||||||
width: 75px;
|
|
||||||
margin-bottom: 3px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>OpenFlexure Microscope API Demo</title>
|
|
||||||
|
|
||||||
<link rel= "stylesheet" type= "text/css" href="{{url_for('static', filename='style_v1.css')}}">
|
|
||||||
<script type="text/javascript" src="{{url_for('static', filename='main_v1.js')}}"></script>
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui, maximum-scale=1.0, user-scalable=0">
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="column left" id="left-sb">
|
|
||||||
<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>
|
|
||||||
<p>
|
|
||||||
x: <input type="number" id="x_abs"><br>
|
|
||||||
y: <input type="number" id="y_abs"><br>
|
|
||||||
z: <input type="number" id="z_abs"><br>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<button type="button" onclick="setStagePositionsFromInput();">GO</button>
|
|
||||||
<button type="button" onclick="api.getState(updateStateValues);">Update</button>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Doubleclick to position: <input type="checkbox" id="clickPositionCheck" checked><br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<h3>Move</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<b>Up/down/left/right:</b> <br>
|
|
||||||
Move stage in x-y. <br>
|
|
||||||
<b>PgUp/PgDn: </b> <br>
|
|
||||||
Move stage in z/focus.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4>Velocity:</h4>
|
|
||||||
<div class="flexbox">
|
|
||||||
<div class="flexgrow">x-y:</div>
|
|
||||||
<div>
|
|
||||||
<input type="range" id="stageVelocityInput" min="50" max="200" oninput="clientStageParams.velocityXY = Number(this.value); updateClientValues();">
|
|
||||||
<input type="text" id="stageVelocityText" size="3" disabled>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flexbox">
|
|
||||||
<div class="flexgrow">z:</div>
|
|
||||||
<div>
|
|
||||||
<input type="range" id="focusVelocityInput" min="10" max="100" oninput="clientStageParams.velocityZ = Number(this.value); updateClientValues();">
|
|
||||||
<input type="text" id="focusVelocityText" size="3" disabled>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<p>Scroll to focus: <input type="checkbox" id="scrollFocusCheck" checked></p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="column middle">
|
|
||||||
<div id="left-sb-btn" class="sb-btn">
|
|
||||||
<button type="button" onclick="toggleClassToDiv('left-sb', 'hidden');">
|
|
||||||
<img src="{{url_for('static', filename='icons/baseline-settings-20px.svg')}}">
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div id="right-sb-btn" class="sb-btn">
|
|
||||||
<button type="button" onclick="toggleClassToDiv('right-sb', 'hidden');">
|
|
||||||
<img src="{{url_for('static', filename='icons/baseline-camera_alt-24px.svg')}}">
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="scrolltarget" id="streambox">No active stream</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="column right" id="right-sb">
|
|
||||||
<h2>Capture</h2>
|
|
||||||
Filename: <br>
|
|
||||||
<input type="text" id="captureFilenameInput" placeholder="Leave blank for default"><br>
|
|
||||||
Temporary: <input type="checkbox" id="captureTemporaryCheck"><br>
|
|
||||||
Full resolution: <input type="checkbox" id="captureFullResolutionCheck"><br>
|
|
||||||
Keep raw data: <input type="checkbox" id="captureBayerCheck"><br>
|
|
||||||
Resize capture: <input type="checkbox" id="captureResizeCheck" onclick="newCaptureResizeToggle(this);"><br>
|
|
||||||
<input type="number" id="captureWidthInput" value="640" style="width: 7em" disabled>
|
|
||||||
<input type="number" id="captureHeightInput" value="480" style="width: 7em" disabled><br>
|
|
||||||
|
|
||||||
<button type="button" onclick="newCaptureFromInput();">Capture</button>
|
|
||||||
|
|
||||||
<h2>Captures</h2>
|
|
||||||
<button type="button" onclick="updateCaptures();">Update</button>
|
|
||||||
<button type="button" onclick="deleteAllCaptures();">Delete all</button>
|
|
||||||
<div id="captures"></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue