diff --git a/agvis/static/index.html b/agvis/static/index.html deleted file mode 100644 index 505d65c..0000000 --- a/agvis/static/index.html +++ /dev/null @@ -1,249 +0,0 @@ - - - CURENT LTBWeb - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -
- diff --git a/agvis/static/js/ConfigControl.js b/agvis/static/js/ConfigControl.js index 1b92414..67230dc 100644 --- a/agvis/static/js/ConfigControl.js +++ b/agvis/static/js/ConfigControl.js @@ -108,28 +108,25 @@ function addSidebarConfig(win, options, sidebar) { }); - const opt_dimehost = document.querySelector(`#${table_id} input[name='opt_dimehost']`); - const opt_dimeport = document.querySelector(`#${table_id} input[name='opt_dimeport']`); - const opt_amin = document.querySelector(`#${table_id} input[name='opt_amin']`); - const opt_amax = document.querySelector(`#${table_id} input[name='opt_amax']`); - const opt_vmin = document.querySelector(`#${table_id} input[name='opt_vmin']`); - const opt_vmax = document.querySelector(`#${table_id} input[name='opt_vmax']`); - const opt_fmin = document.querySelector(`#${table_id} input[name='opt_fmin']`); - const opt_fmax = document.querySelector(`#${table_id} input[name='opt_fmax']`); - const opt_opacity = document.querySelector(`#${table_id} input[name='opt_opacity']`); - const opt_togglezones = document.querySelector(`#${table_id} input[name='opt_togglezones']`); + const opt_dimehost = document.querySelector(`#${table_id} input[name='opt_dimehost']`); + const opt_dimeport = document.querySelector(`#${table_id} input[name='opt_dimeport']`); + const opt_amin = document.querySelector(`#${table_id} input[name='opt_amin']`); + const opt_amax = document.querySelector(`#${table_id} input[name='opt_amax']`); + const opt_vmin = document.querySelector(`#${table_id} input[name='opt_vmin']`); + const opt_vmax = document.querySelector(`#${table_id} input[name='opt_vmax']`); + const opt_fmin = document.querySelector(`#${table_id} input[name='opt_fmin']`); + const opt_fmax = document.querySelector(`#${table_id} input[name='opt_fmax']`); + const opt_opacity = document.querySelector(`#${table_id} input[name='opt_opacity']`); + const opt_togglezones = document.querySelector(`#${table_id} input[name='opt_togglezones']`); const opt_togglebuslabels = document.querySelector(`#${table_id} input[name='opt_togglebuslabels']`); - - const opt_loadconfig = document.querySelector(`#${table_id} input[name='opt_loadconfig']`); - const opt_saveconfig = document.querySelector(`#${table_id} input[name='opt_saveconfig']`); - const opt_loadsimulation = document.querySelector(`#${table_id} input[name='opt_loadsimulation']`); - const opt_savesimulation = document.querySelector(`#${table_id} input[name='opt_savesimulation']`); - - const opt_alabel = document.querySelector(`#${table_id} span[name='opt_alabel']`); - const opt_vlabel = document.querySelector(`#${table_id} span[name='opt_vlabel']`); - const opt_flabel = document.querySelector(`#${table_id} span[name='opt_flabel']`); - - const ts_up = document.querySelector(`#${table_id} input[name='ts_up']`); + const opt_loadconfig = document.querySelector(`#${table_id} input[name='opt_loadconfig']`); + const opt_saveconfig = document.querySelector(`#${table_id} input[name='opt_saveconfig']`); + const opt_loadsimulation = document.querySelector(`#${table_id} input[name='opt_loadsimulation']`); + const opt_savesimulation = document.querySelector(`#${table_id} input[name='opt_savesimulation']`); + const opt_alabel = document.querySelector(`#${table_id} span[name='opt_alabel']`); + const opt_vlabel = document.querySelector(`#${table_id} span[name='opt_vlabel']`); + const opt_flabel = document.querySelector(`#${table_id} span[name='opt_flabel']`); + const ts_up = document.querySelector(`#${table_id} input[name='ts_up']`); //Updating function for Timestamp ts_up.onclick = function() { @@ -281,6 +278,8 @@ function addSidebarConfig(win, options, sidebar) { if (win.contourLayer.variableName === "theta") { win.contourLayer.updateRange(options.amin, options.amax); } + + win.legend.update(); } } @@ -299,6 +298,8 @@ function addSidebarConfig(win, options, sidebar) { if (win.contourLayer.variableName === "theta") { win.contourLayer.updateRange(options.amax, options.amax); } + + win.legend.update(); } }; @@ -317,6 +318,8 @@ function addSidebarConfig(win, options, sidebar) { if (win.contourLayer.variableName === "V") { win.contourLayer.updateRange(options.vmin, options.vmax); } + + win.legend.update(); } }; @@ -335,6 +338,8 @@ function addSidebarConfig(win, options, sidebar) { if (win.contourLayer.variableName === "V") { win.contourLayer.updateRange(options.vmin, options.vmax); } + + win.legend.update(); } } @@ -353,6 +358,8 @@ function addSidebarConfig(win, options, sidebar) { if (win.contourLayer.variableName === "freq") { win.contourLayer.updateRange(options.fmin, options.fmax); } + + win.legend.update(); } }; @@ -371,6 +378,8 @@ function addSidebarConfig(win, options, sidebar) { if (win.contourLayer.variableName === "freq") { win.contourLayer.updateRange(options.fmin, options.fmax); } + + win.legend.update(); } }; @@ -388,6 +397,8 @@ function addSidebarConfig(win, options, sidebar) { dt = dt.toUTCString(); document.cookie = `opacity${win.num}=${val};expires=${dt};path=/`; + + win.legend.update(); } }; diff --git a/agvis/static/js/Legend.js b/agvis/static/js/Legend.js new file mode 100644 index 0000000..547cceb --- /dev/null +++ b/agvis/static/js/Legend.js @@ -0,0 +1,167 @@ +/** + * ================================================================================================== + * File Name: Legend.js + * Author: Zack Malkmus + * Date: 9/6/2023 + * Description: Creates a draggable and updating legend for LTB AGVis + * ================================================================================================== + */ + +/** + * Create a new dynamic legend for AGVis. + * + * This class creates a new legend for AGVis that is draggable and updatable + * + * @author Zack Malkmus + * @param {Object} win - The AGVis window that the legend is associated with. + * @returns {Object} The new legend element. + */ +L.DynamicLegend = L.Control.extend({ + options: { + position: 'bottomright', + }, + + /** + * Initialize the legend. + * @memberof L.DynamicLegend + * @param {Object} win - The AGVis window that the legend is associated with. + * @returns {void} + * @constructor + */ + initialize: function(win) { + this.win = win; + }, + + /** + * Create the legend element. + * @memberof L.DynamicLegend + * @returns {Element} - The legend element. + */ + onAdd: function() { + // Legend Container + let div = L.DomUtil.create('div', 'info leaflet-bar'); + L.DomEvent.disableClickPropagation(div); + L.DomEvent.disableScrollPropagation(div); + div.style.backgroundColor = 'white'; + div.style.boxSizing = 'border-box'; + div.style.padding = '5px'; + div.style.paddingLeft = '15px'; + div.style.paddingRight = '15px'; + div.style.width = '300px'; + div.style.height = '75px'; + div.style.userSelect = 'none'; + + // Make the legend draggable + L.DomEvent.on(div, 'mousedown', this.onDragStart, this); + L.DomEvent.on(document, 'mousemove', this.onDrag, this); + L.DomEvent.on(document, 'mouseup', this.onDragEnd, this); + + // Title and Units labels + let topLabels = L.DomUtil.create('div', '', div); + topLabels.style.width = '100%'; + topLabels.style.height = '16px'; + + this.title = L.DomUtil.create('div', '', topLabels); + this.title.style.float = 'left'; + this.title.style.width = '45%'; + + this.units = L.DomUtil.create('div', '', topLabels); + this.units.style.float = 'right'; + this.units.style.width = '55%'; + + // Create Dynamic Gradient + let gradient = L.DomUtil.create('div', '', div); + gradient.style.backgroundImage = 'linear-gradient(to right, #0b00ff, #0044ff, #0044ff, #279eff, #41cef1, #41cef1, #ffffff, #ffb41e, #ffb41e, #ff9537, #ff4727, #ff4727, #ff0000)'; + gradient.style.width = '100%'; + gradient.style.height = '20px'; + gradient.style.border = '1px solid grey'; + gradient.style.borderRadius = '2px'; + + // Min and max labels + let bottomLabels = L.DomUtil.create('div', '', div); + bottomLabels.style.width = '100%'; + + this.min = L.DomUtil.create('div', '', bottomLabels); + this.min.style.float = 'left'; + + this.max = L.DomUtil.create('div', '', bottomLabels); + this.max.style.float = 'right'; + + // Initialize the legend values + this.update(); + + return div; + }, + + /** + * Set the legend to be draggable. + * @memberof L.DynamicLegend + * @param {Object} e - The event object. + * @returns {void} + */ + onDragStart: function (e) { + this.dragging = true; + this.dragStartX = e.clientX; + this.dragStartY = e.clientY; + this.originalX = parseInt(this._container.style.left) || 0; + this.originalY = parseInt(this._container.style.top) || 0; + + }, + + /** + * Update the legend position while dragging. + * @memberof L.DynamicLegend + * @param {Object} e - The event object. + * @returns {void} + */ + onDrag: function (e) { + if (!this.dragging) return; + + let deltaX = e.clientX - this.dragStartX; + let deltaY = e.clientY - this.dragStartY; + + this._container.style.left = this.originalX + deltaX + 'px'; + this._container.style.top = this.originalY + deltaY + 'px'; + + }, + + /** + * Stop dragging the legend. + * @memberof L.DynamicLegend + * @returns {void} + */ + onDragEnd: function () { + this.dragging = false; + }, + + /** + * Used to update the legend values when the user changes the state or min/max values of the state. + * @memberof L.DynamicLegend + * @returns {void} + * @see ConfigControl.js + * @see Window.js + */ + update: function() { + // Voltage Angle + if (this.win.state == this.win.states.angl) { + this.title.innerHTML = "V Angle"; + this.units.innerHTML = "(rad)"; + this.min.innerHTML = "" + this.win.options.amin + ""; + this.max.innerHTML = "" + this.win.options.amax + ""; + } + // Voltage Magnitude + else if (this.win.state == this.win.states.volt) { + this.title.innerHTML = "V Magnitude"; + this.units.innerHTML = "(p.u.)"; + this.min.innerHTML = "" + this.win.options.vmin + ""; + this.max.innerHTML = "" + this.win.options.vmax + ""; + } + // Frequency + else if (this.win.state == this.win.states.freq) { + this.title.innerHTML = "Frequency"; + this.units.innerHTML = "(p.u.)"; + this.min.innerHTML = "" + this.win.options.fmin + ""; + this.max.innerHTML = "" + this.win.options.fmax + ""; + } + }, +}); \ No newline at end of file diff --git a/agvis/static/js/Window.js b/agvis/static/js/Window.js index d5796ca..f0c1082 100644 --- a/agvis/static/js/Window.js +++ b/agvis/static/js/Window.js @@ -3,21 +3,25 @@ class Window { this.workspace = {}; this.history = {}; + // Keep track of the view state + this.states = { + angl: 0, + volt: 1, + freq: 2, + } + this.state = this.states.freq; + this.num = num; this.options = options; - this.multilayer = []; - this.multihistory = []; - this.mlayercur = 0; - this.mnumfree = 0; - - - + this.multilayer = []; + this.multihistory = []; + this.mlayercur = 0; + this.mnumfree = 0; //Loops every 17 milliseconds to update the animation for the independent simulation data //Animation step is associated with receiving info from DiME, so we have to use this for the bundled version setInterval(function(multilayer) { - let timestep = Number(Date.now()); for (let i = 0; i < multilayer.length; i++) { @@ -31,8 +35,6 @@ class Window { let pt = (timestep - multi.curtime) / 1000; multi.pbar.updatePlaybackBar(pt, timestep); multi.curtime = Number(timestep); - - } }, 17, this.multilayer); @@ -65,22 +67,16 @@ class Window { zoom: 5, }); - //this.map.timescale = 1.0; - //this.map.end_time = null; this.map.handshake = true; - + this.legend = new L.DynamicLegend(this, options).addTo(this.map); this.pbar = new PlaybackControl(this, options); - this.tileLayer = L.tileLayer(TILE_LAYER_URL).addTo(this.map); - this.zoneLayer = L.zoneLayer().addTo(this.map); this.topologyLayer = L.topologyLayer().addTo(this.map); this.contourLayer = L.contourLayer().addTo(this.map); this.communicationLayer = L.communicationLayer().addTo(this.map); this.searchLayer = L.searchLayer().addTo(this.map); - this.map.addControl(this.searchLayer.control); - this.simTimeBox = L.simTimeBox({ position: 'topright' }).addTo(this.map); // side bar @@ -274,9 +270,6 @@ class Window { let dt = (currentTime - firstTime) / 1000.0; - - - if (self.end_time !== null) { dt *= self.timescale; } @@ -285,8 +278,6 @@ class Window { self.pbar.updatePlaybackBar(self.time); - - self.workspace.currentTimeInSeconds = self.time; firstTime = currentTime; @@ -299,10 +290,7 @@ class Window { self.topologyLayer.update(self.workspace); self.contourLayer.update(self.workspace); self.searchLayer.update(self.workspace, self); - - - - + //console.log(self.workspace.Varvgs); if (self.workspace.Varvgs) { @@ -358,6 +346,8 @@ class Window { self.contourLayer.showVariable("theta"); self.contourLayer.updateRange(amin, amax); + self.state = self.states.angl; + self.legend.update(); }); const voltageButton = L.easyButton('V', function(btn, map) { @@ -366,6 +356,8 @@ class Window { self.contourLayer.showVariable("V"); self.contourLayer.updateRange(vmin, vmax); + self.state = self.states.volt; + self.legend.update(); }); const freqButton = L.easyButton('f', function(btn, map) { @@ -374,6 +366,8 @@ class Window { self.contourLayer.showVariable("freq"); self.contourLayer.updateRange(fmin, fmax); + self.state = self.states.freq; + self.legend.update(); }); /// Added toggle buttons for different layer views @@ -461,4 +455,4 @@ class Window { save() { return dime.dimebdumps({history: this.history, workspace: this.workspace}); } -} +} \ No newline at end of file diff --git a/agvis/templates/index.html b/agvis/templates/index.html index 68f8c96..51f4656 100644 --- a/agvis/templates/index.html +++ b/agvis/templates/index.html @@ -131,6 +131,7 @@ +