Skip to content

Commit

Permalink
Merge pull request #1108 from sandialabs/alex-timeseries
Browse files Browse the repository at this point in the history
Adding React and Redux to Timeseries. Using new color selector and grayscale color maps in Timeseries.
  • Loading branch information
Mletter1 committed May 1, 2023
2 parents 3b2c824 + 946cd16 commit b5dbc59
Show file tree
Hide file tree
Showing 27 changed files with 2,461 additions and 2,410 deletions.
43 changes: 41 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@fortawesome/fontawesome-svg-core": "^6",
"@fortawesome/free-solid-svg-icons": "^6",
"@fortawesome/react-fontawesome": "^0",
"@reduxjs/toolkit": "^1.9.3",
"bootstrap": "^4",
"buffer": "6.0.3",
"d3": "^3",
Expand Down Expand Up @@ -77,6 +78,7 @@
"@types/jest": "^29",
"@types/jquery": "^3.5.5",
"@types/jsdom": "^20",
"@types/lodash": "^4.14.191",
"@types/node": "^18",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
6 changes: 4 additions & 2 deletions web-server/components/ControlsDropdownColor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
// @ts-ignore
import ControlsDropdown from "components/ControlsDropdown";
import ColorMaps from "js/slycat-color-maps";
import d3 from "d3";

interface ControlsDropdownColorProps {
colormaps: typeof ColorMaps;
Expand All @@ -14,7 +16,7 @@ interface ControlsDropdownColorProps {
single: boolean;
button_style: string;
setColormap(colormap: string): void;
background: d3.RGBColor;
background?: d3.RGBColor;
}

/**
Expand Down Expand Up @@ -43,7 +45,7 @@ export default class ControlsDropdownColor extends React.Component<ControlsDropd
}
let background_color = colormap.background;
if (background_color === undefined) {
background_color = this.props.background;
background_color = this.props.background ? this.props.background : d3.rgb(255, 255, 255);
}
const width = 250;
const right_margin = 5;
Expand Down
File renamed without changes.
148 changes: 76 additions & 72 deletions web-server/js/slycat-bookmark-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,161 +2,165 @@
DE-NA0003525 with National Technology and Engineering Solutions of Sandia, LLC, the U.S. Government
retains certain rights in this software. */

import api_root from 'js/slycat-api-root';
import api_root from "js/slycat-api-root";
import URI from "urijs";
import _ from "lodash";
import _ from "lodash";

var module = {};
let manager = null;

module.current_bid = function(bid)
{
if(bid !== undefined) // Caller wants to set a new bid.
{
module.current_bid = function (bid) {
if (bid !== undefined) {
// Caller wants to set a new bid.
var new_location = URI(window.location).removeQuery("bid");

if(bid === null) // Caller is clearing the bid.
{
if (bid === null) {
// Caller is clearing the bid.
localStorage.removeItem(module.current_mid());
}
else // Caller is setting a non-null bid.
{
} // Caller is setting a non-null bid.
else {
localStorage[module.current_mid()] = bid;
new_location.addQuery("bid", bid);
}

window.location = new_location;
}
else // No bid was specified, so return the current bid (if any).
{
} // No bid was specified, so return the current bid (if any).
else {
return URI(window.location).query(true).bid;
}
}
};

module.current_mid = function()
{
module.current_mid = function () {
var uri = URI(window.location);
return uri.segment(-2) == "models" ? uri.segment(-1) : null;
}
};

module.create = function (pid, mid) {
// Return the existing manager if it exists
if (manager !== null) {
return manager;
}

module.create = function(pid, mid)
{
var manager = {};
manager = {};
var bid_callbacks = [];

var bid = null;
var current_location = URI(window.location);
if(current_location.query(true).bid == 'clear')
{
if (current_location.query(true).bid == "clear") {
// Remove the current model ID from localStorage to clear it
localStorage.removeItem(mid);
// Do nothing more to allow bookmark state to clear
}
else if(current_location.query(true).bid)
{
} else if (current_location.query(true).bid) {
bid = current_location.query(true).bid;
}
else if(localStorage.getItem(mid) != null)
{
} else if (localStorage.getItem(mid) != null) {
bid = localStorage.getItem(mid);
updateURL(bid);
}
var state = {}; // JSON object representing the state of the model UI
var req = null; // ajax request

// Updates the browser's URL with the bid (private)
function updateURL(bid)
{
function updateURL(bid) {
var new_location = URI(window.location).removeQuery("bid").addQuery("bid", bid);
window.history.replaceState( null, null, new_location.toString() );
_.each(bid_callbacks, function(callback)
{
window.history.replaceState(null, null, new_location.toString());
_.each(bid_callbacks, function (callback) {
callback(bid);
});
// Consider using window.history.pushState instead to enable back button navigation within the model
}

manager.bid = {};
manager.bid.subscribe = function(callback)
{
manager.bid.subscribe = function (callback) {
bid_callbacks.push(callback);
}
};

// Updates the bookmark state (privileged)
manager.updateState = function(params)
{
// State needs to be updated each time updateState is called
$.extend(state, params); // Consider using deep merge by adding true as the first parameter. However, deep merging does not work with bookmarking of expanded and collapsed dendrogram nodes since they are passed as arrays

manager.updateState = function (params) {
// State needs to be updated each time updateState is called.
// Consider using deep merge by adding true as the first parameter.
// However, deep merging does not work with bookmarking of expanded
// and collapsed dendrogram nodes since they are passed as arrays

$.extend(state, params);
// But we don't have to post the bookmark each time, so calling a seaparte postBookmark
// function that is debounced (or throttled in the future?) to limit number of POSTs to the backend
manager.postBookmark();
}
};

// Using debounce to only POST bookmark every 1/3 second (333 ms) so we don't
// Using debounce to only POST bookmark every 1/3 second (333 ms) so we don't
// inundate the server with dozens of requests per second when user does something
// that updates state often, like drag a pin around the screen.
manager.postBookmark = _.debounce(
// This is the function that POSTs a bookmark to the server
function(params)
{
function (params) {
// Store bookmark and update the bid
if(req)
req.abort();
if (req) req.abort();

req = $.ajax({
type : "POST",
url : api_root + "projects/" + pid + "/bookmarks",
contentType : "application/json",
type: "POST",
url: api_root + "projects/" + pid + "/bookmarks",
contentType: "application/json",
data: JSON.stringify(state),
processData: false,
success: function(result)
{
success: function (result) {
bid = result.id;
updateURL(bid);
// Store latest bid in local storage
if(mid != null)
localStorage[mid] = bid;
if (mid != null) localStorage[mid] = bid;
req = null;
},
});
},
// How long to wait before actually running that function.
},
// How long to wait before actually running that function.
// Debounce just waits this long and then executes the last call to postBookmark.
// But in the future we might want to use throttle function instead, which
// would call postBookmark every 333 seconds.
333
);

// Retrieves the state for the current bookmark id (asynchronous)
manager.getState = function(callback)
{
if($.isEmptyObject(state) && !(bid == null))
{
$.ajax(
{
manager.getState = function (callback) {
if ($.isEmptyObject(state) && !(bid == null)) {
$.ajax({
dataType: "json",
url: api_root + "bookmarks/" + bid,
async: true,
success: function(resp)
{
success: function (resp) {
state = resp;
callback(state);
},
error: function()
{
error: function () {
// Assume no state when we can't retrieve a bid
state = {};
callback(state);
},
});
}
else
{
} else {
callback(state);
}
}
};

// Retrieves the state for the current bookmark id using fetch (asynchronous)
manager.getStateFetch = async function () {
// If state is empty and bid is not null, then we need to fetch the state
if ($.isEmptyObject(state) && !(bid == null)) {
const response = await fetch(api_root + "bookmarks/" + bid);
// Assume no state when we can't retrieve a bid
if (!response.ok) {
state = {};
return state;
}
// If we can retrieve a bid, then we can set the state and return it
state = await response.json();
return state;
}
// If state is not empty, then we can just return the state
else {
return state;
}
};

return manager;
}
};

export default module;
Loading

0 comments on commit b5dbc59

Please sign in to comment.