Commit 740bf8fb authored by Joel Collins's avatar Joel Collins
Browse files

Restructured API demo

parent 2a52109c
Loading
Loading
Loading
Loading
+190 −0
Original line number Diff line number Diff line
// TODO: Remember a position and restore that position
// TODO: Right click to auto-focus, centered on that region

var baseURI = "/api/v1"

// 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 stageVelocity = 50;  
var focusVelocity = 20;

var requestLock = false;

// Microscope client-side callibration
//TODO: Move to serverside microscope property
var fovX =  4100;
var fovY = 3146;

window.onload = function() {
    getStagePositions()
}

function updateTextBoxes() {
    document.getElementById('stageVelocityText').value = stageVelocity;
    document.getElementById('focusVelocityText').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+"/position", null, updatePositionCallback)
}

function setStagePositions(x_abs, y_abs, z_abs) {
    // Make a position request
    function absMoveCallback(response, status) {
    if (status == 400) {
        alert("Stage cannot be moved further than the safe range.");
    }
    console.log(status, response);
    updateStagePositions(response);
    }
    safeRequest("POST", baseURI+"/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 == 400) {
        alert("Stage cannot be moved further than the safe range.");
    }
    console.log(status, response);
    updateStagePositions(response);
    }
    safeRequest("POST", baseURI+"/position", { "absolute": false, "x": x_rel, "y": y_rel, "z": z_rel}, relMoveCallback)
}

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);
    setStagePositions(x_abs, y_abs, z_abs)
}

// Standard callback for user-controller movement
function keyMoveCallback(response, status) {
    console.log(status, response);
    updateStagePositions(response);
}

// 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 * fovX;
    ySteps = yRelative * fovY;
    console.log(xSteps, ySteps, 0)
    // Make a position request
    moveStagePositions(xSteps, ySteps, 0)
    }
}

// Scroll-to-focus
window.addEventListener('wheel', function(e) {
    multiplier = 1/100;
    z_delta = e.deltaY * multiplier * focusVelocity;
    if (document.getElementById("scrollFocusCheck").checked == true) {
    console.log(z_delta);
    // Make a position request
    safeRequest("POST", baseURI+"/position", { "absolute": false, "z": z_delta}, keyMoveCallback)
    }
});

// Keyboard to move
addEventListener("keydown", function (e) {
    keysDown[e.keyCode] = true; //Add key to array
    console.log(keysDown)

    // 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 + stageVelocity;
        }
        if (rightKeyID in keysDown) {
        x_rel = x_rel - stageVelocity;
        }
        if (upKeyID in keysDown) {
        y_rel = y_rel + stageVelocity;
        }
        if (downKeyID in keysDown) {
        y_rel = y_rel - stageVelocity;
        }
        if (pgupKeyID in keysDown) {
        z_rel = z_rel - focusVelocity;
        }
        if (pgdnKeyID in keysDown) {
        z_rel = z_rel + focusVelocity;
        }

        // Make a position request
        moveStagePositions(x_rel, y_rel, z_rel)
    }

}, false);

addEventListener("keyup", function (e) {
    delete keysDown[e.keyCode]; //Remove key from array
}, false);

// Methods for making requests
function safeRequest(method, url, payload, callback) {
    if (requestLock == false) {
        var xhr = new XMLHttpRequest();   // new HttpRequest instance 
        xhr.open(method, url);
        requestLock = true;

        xhr.onload = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status !== 200) {
            console.error(xhr.statusText);
            } 
            callback(JSON.parse(xhr.responseText), xhr.status);
        }
        requestLock = false;
        };

        if (method == "POST" || method == "PUT") {
        xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        }

        xhr.send(JSON.stringify(payload));

    }
    else {
        console.log("Cannot start new request while previous requets is pending...")
    }
}
+65 −0
Original line number Diff line number Diff line
body {
    margin: 0;
    overflow: hidden;
    font-family: sans-serif;
    font-size: 14px;
}

* {
    box-sizing: border-box;
}

/* Preview sizing */
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;
}

.left{
    width: 250px;
    float: left;
}

.Right{
    width: 250px;
    float: right;
}

.middle {
  margin-left: 250px;
  margin-right: 250px;
  background-color: #d3d3d3;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

/* Columns within panels */

.left-col {
    float:left;
}
.right-col {
    float:right;
}
.clearfix::after {
    content: "";
    clear: both;
    display: table;
}
+77 −208
Original line number Diff line number Diff line
<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>

  </head>
  <body>
    <h1>OpenFlexure Microscope API Demo</h1>
    <img src="{{ url_for('stream') }}" ondblclick="clickHotspotImage(event)";>
    <br>

    x: <input type="number" id="x_abs">
    y: <input type="number" id="y_abs">
    z: <input type="number" id="z_abs">
    <div class="row">
      <div class="column left">
        <h2>Settings</h2>

        <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="getStagePositions();">Update</button>
    <br>

    Velocity:
    <br>
    x-y: <input type="range" name="stageVelocityInput" min="50" max="200" value="100" oninput="stageVelocity = Number(this.value);">
        </p>

        <p>
          Doubleclick to position: <input type="checkbox" id="clickPositionCheck" checked><br>
          <div class="clearfix">
              <div class="left-col">FOV width:</div> 
              <div class="right-col"> 
                <input type="text" id="fovXText" value="4100" size="4" onchange="fovX = Number(this.value); updateTextBoxes();">
              </div> 
          </div>

          <div class="clearfix">
              <div class="left-col">FOV height:</div> 
              <div class="right-col"> 
                  <input type="text" id="fovYText" value="3146" size="4" onchange="fovY = Number(this.value); updateTextBoxes();">
              </div> 
          </div>
        </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="clearfix">
          <div class="left-col">x-y:</div>
          <div class="right-col"> 
            <input type="range" name="stageVelocityInput" min="50" max="200" value="100" oninput="stageVelocity = Number(this.value); updateTextBoxes();">
            <input type="text" id="stageVelocityText" value="100" size="3" disabled>
    z: <input type="range" name="focusVelocityInput" min="10" max="100" value="20" oninput="focusVelocity = Number(this.value);">
          </div>
        </div>
        <div class="clearfix">
          <div class="left-col">z:</div>
          <div class="right-col"> 
            <input type="range" name="focusVelocityInput" min="10" max="100" value="20" oninput="focusVelocity = Number(this.value); updateTextBoxes();">
            <input type="text" id="focusVelocityText" value="20" size="3" disabled>
    <br>
          </div>
        </div>

    Scroll focus: <input type="checkbox" id="scrollFocusCheck" checked>
    <br>
    
    Click position: <input type="checkbox" id="clickPositionCheck" checked>
    x FOV: <input type="text" id="fovXText" value="4100" size="4" onchange="fovX = Number(this.value);">
    y FOV: <input type="text" id="fovYText" value="3146" size="4" onchange="fovY = Number(this.value);">
        <p>Scroll to focus: <input type="checkbox" id="scrollFocusCheck" checked></p>

      </div>

      <div class="column right">
        <h2>Captures</h2>
        <p>Not yet implemented.</p>
      </div>

  </body>
      <div class="column middle">
        <img src="/api/v1/stream" ondblclick="clickHotspotImage(event)" ;="" style="width: 100%;">
      </div>

    </div>

  <script>
    // TODO: Remember a position and restore that position
    // TODO: Right click to auto-focus, centered on that region

    // 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 stageVelocity = 50;  
    var focusVelocity = 20;

    var requestLock = false;

    // Microscope client-side callibration
    //TODO: Move to serverside microscope property
    var fovX =  4100;
    var fovY = 3146;

    window.onload = function() {
      getStagePositions()
    }

    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", "{{ url_for('position') }}", null, updatePositionCallback)
    }

    function setStagePositions(x_abs, y_abs, z_abs) {
      // Make a position request
      function absMoveCallback(response, status) {
        if (status == 400) {
          alert("Stage cannot be moved further than the safe range.");
        }
        console.log(status, response);
        updateStagePositions(response);
      }
      safeRequest("POST", "{{ url_for('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 == 400) {
          alert("Stage cannot be moved further than the safe range.");
        }
        console.log(status, response);
        updateStagePositions(response);
      }
      safeRequest("POST", "{{ url_for('position') }}", { "absolute": false, "x": x_rel, "y": y_rel, "z": z_rel}, relMoveCallback)
    }

    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);
      setStagePositions(x_abs, y_abs, z_abs)
    }

    // Standard callback for user-controller movement
    function keyMoveCallback(response, status) {
      console.log(status, response);
      updateStagePositions(response);
    }

    // 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 * fovX;
        ySteps = yRelative * fovY;
        console.log(xSteps, ySteps, 0)
        moveStagePositions(xSteps, ySteps, 0)
      }
    }

    // Scroll-to-focus
    window.addEventListener('wheel', function(e) {
      multiplier = 1/100;
      z_delta = e.deltaY * multiplier * focusVelocity;
      console.log(z_delta);
      if (document.getElementById("scrollFocusCheck").checked == true) {
        // Make a position request
        safeRequest("POST", "{{ url_for('position') }}", { "absolute": false, "z": z_delta}, keyMoveCallback)
      }
    });

    addEventListener("keydown", function (e) {
        keysDown[e.keyCode] = true; //Add key to array
        console.log(keysDown)

        // 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 + stageVelocity;
          }
          if (rightKeyID in keysDown) {
            x_rel = x_rel - stageVelocity;
          }
          if (upKeyID in keysDown) {
            y_rel = y_rel + stageVelocity;
          }
          if (downKeyID in keysDown) {
            y_rel = y_rel - stageVelocity;
          }
          if (pgupKeyID in keysDown) {
            z_rel = z_rel - focusVelocity;
          }
          if (pgdnKeyID in keysDown) {
            z_rel = z_rel + focusVelocity;
          }

          // Make a position request
          moveStagePositions(x_rel, y_rel, z_rel)
        }

    }, false);

    addEventListener("keyup", function (e) {
        delete keysDown[e.keyCode]; //Remove key from array
    }, false);
  
    // Methods for making requests
    function safeRequest(method, url, payload, callback) {
      if (requestLock == false) {
          var xhr = new XMLHttpRequest();   // new HttpRequest instance 
          xhr.open(method, url);
          requestLock = true;

          xhr.onload = function (e) {
            if (xhr.readyState === 4) {
              if (xhr.status !== 200) {
                console.error(xhr.statusText);
              } 
              callback(JSON.parse(xhr.responseText), xhr.status);
            }
            requestLock = false;
          };

          if (method == "POST" || method == "PUT") {
            xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
          }

          xhr.send(JSON.stringify(payload));

        }
        else {
          console.log("Cannot start new request while previous requets is pending...")
        }
    }

  </script>
  </body>

</html>