From 69ece2bc0fde7500aa03584addf0e8d292ffdbe6 Mon Sep 17 00:00:00 2001 From: jaden <noreply@example.com> Date: Fri, 9 Jun 2017 16:30:16 +0200 Subject: [PATCH] move plot management to panel header, better styling --- .../static/experiments/js/utils.js | 32 ++++-- .../app/directives/edit/addItemsMenu.js | 13 ++- .../reports/app/directives/edit/plotItem.js | 64 ++++++++++- .../reports/app/directives/view/plotItem.js | 82 +++++++++++++- .../reports/app/services/plotService.js | 107 +++++++++++------- beat/web/reports/static/reports/css/style.css | 2 +- 6 files changed, 229 insertions(+), 71 deletions(-) diff --git a/beat/web/experiments/static/experiments/js/utils.js b/beat/web/experiments/static/experiments/js/utils.js index a27fb8994..7e3de93ba 100644 --- a/beat/web/experiments/static/experiments/js/utils.js +++ b/beat/web/experiments/static/experiments/js/utils.js @@ -111,11 +111,16 @@ beat.experiments.utils.displayPlot = function( container.appendChild(table_element); var tr = document.createElement('tr'); - table_element.appendChild(tr); - var td = document.createElement('td'); - td.appendChild(plotter_selector); - tr.appendChild(td); + + console.log(value); + if(!value.report_number){ + table_element.appendChild(tr); + + var td = document.createElement('td'); + td.appendChild(plotter_selector); + tr.appendChild(td); + } // adds image place holder var img = document.createElement('img'); @@ -169,11 +174,16 @@ beat.experiments.utils.displayPlot = function( container.appendChild(table_element); var tr = document.createElement('tr'); - table_element.appendChild(tr); - var td = document.createElement('td'); - td.appendChild(plotter_selector); - tr.appendChild(td); + + console.log(value); + if(!value.report_number){ + table_element.appendChild(tr); + + var td = document.createElement('td'); + td.appendChild(plotter_selector); + tr.appendChild(td); + } $.ajaxSetup({ beforeSend: function(xhr, settings) { @@ -195,9 +205,9 @@ beat.experiments.utils.displayPlot = function( var td_title = document.createElement('td'); td_title.className = 'td_title'; - const title_h2 = document.createElement('h2'); - title_h2.textContent = _data.legend; - td_title.appendChild(title_h2); + const title_h3 = document.createElement('h3'); + title_h3.textContent = _data.legend; + td_title.appendChild(title_h3); tr_title.appendChild(td_title); } // adds image place holder diff --git a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js index fdf783d97..e551dc117 100644 --- a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js +++ b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js @@ -26,7 +26,7 @@ * the button group for adding report items (plot, table, text) to a group */ angular.module('reportApp') -.directive("groupAddItemsMenu", ['ExperimentsService', 'GroupsService', function(ExperimentsService, GroupsService){ +.directive("groupAddItemsMenu", ['ExperimentsService', 'GroupsService', 'PlotService', function(ExperimentsService, GroupsService, PlotService){ return { scope: { group: '=' @@ -89,9 +89,16 @@ angular.module('reportApp') let content = { itemName: `${plot.label}`, name: plot.label, - type: plot.type + type: plot.type, + merged: true, + savedPlotter: '', + savedConfig: '' }; + content.savedPlotter = PlotService.getPlotter(content).name; + content.savedConfig = PlotService.getPlotterConfig(content).name; + console.log(content); + scope.group.addReportItem(id, content); }; @@ -142,5 +149,5 @@ angular.module('reportApp') </button> </div> ` - } + }; }]); diff --git a/beat/web/reports/static/reports/app/directives/edit/plotItem.js b/beat/web/reports/static/reports/app/directives/edit/plotItem.js index 2209328d4..614a6999e 100644 --- a/beat/web/reports/static/reports/app/directives/edit/plotItem.js +++ b/beat/web/reports/static/reports/app/directives/edit/plotItem.js @@ -66,7 +66,7 @@ angular.module('reportApp') // redo the render if(el && el.childNodes.length > 0){ el.innerHTML = ''; - PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig); + return PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig); } }; @@ -90,6 +90,21 @@ angular.module('reportApp') () => JSON.stringify(scope.group._aliases), updatePlot ); + + // if the user selected different plotter or config, rerender + scope.$watch( + () => `${scope.content.savedPlotter}|${scope.content.savedConfig}`, + updatePlot + ); + + scope.toggleMerged = () => { + scope.content.merged = !scope.content.merged; + updatePlot(); + }; + + scope.getPlotter = () => PlotService.getPlotter(scope.content); + scope.getPossiblePlotters = () => PlotService.plotters.filter(p => p.dataformat === scope.content.type).map(p => p.name); + scope.getPossibleConfigs = () => PlotService.getPossibleConfigs(scope.getPlotter()); }, template: ` <div id="{{domId}}-heading" class="panel-heading" role="tab"> @@ -117,11 +132,48 @@ angular.module('reportApp') <i class='fa fa-arrows fa-lg'></i> </span> </div> - <download-link - dom-id='{{ domId }}' - group='group' - item-id='itemId'> - </download-link> + <div class='btn-group' role='group'> + <download-link + class='btn-group' + dom-id='{{ domId }}' + group='group' + item-id='itemId'> + </download-link> + <button ng-if='group.experiments.length > 1' class='btn btn-default' ng-click='toggleMerged()'> + <span ng-if='content.merged'><i class='fa fa-expand'></i> Expand</span> + <span ng-if='!content.merged'><i class='fa fa-compress'></i> Merge</span> + </button> + <div class='btn-group' role='group'> + <button + ng-class='{disabled: getPossiblePlotters().length === 1}' + class='btn btn-default dropdown-toggle' + type="button" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false"> + Plotter: {{ content.savedPlotter }} + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li ng-click='content.savedPlotter = p' ng-repeat='p in getPossiblePlotters()'><a>{{ p }}</a></li> + </ul> + </div> + <div class='btn-group' role='group'> + <button + ng-class='{disabled: getPossibleConfigs().length === 1}' + class='btn btn-default dropdown-toggle' + type="button" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false"> + Config: {{ content.savedConfig }} + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li ng-click='content.savedConfig = c' ng-repeat='c in getPossibleConfigs()'><a>{{ c }}</a></li> + </ul> + </div> + </div> </h4> </div> <div id="collapse-{{domId}}" diff --git a/beat/web/reports/static/reports/app/directives/view/plotItem.js b/beat/web/reports/static/reports/app/directives/view/plotItem.js index efb9d6d08..41766da6b 100644 --- a/beat/web/reports/static/reports/app/directives/view/plotItem.js +++ b/beat/web/reports/static/reports/app/directives/view/plotItem.js @@ -54,6 +54,39 @@ angular.module('reportApp') $timeout(function() { PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig); }); + + let plotTimer; + + const updatePlot = () => { + clearTimeout(plotTimer); + + const queueUpdate = () => { + let el = document.querySelector(`#${scope.renderDivId}`); + // if the container is rendered and it already has had a render, + // redo the render + if(el && el.childNodes.length > 0){ + el.innerHTML = ''; + return PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig); + } + }; + + plotTimer = setTimeout(queueUpdate, 1000); + }; + + // if the user selected different plotter or config, rerender + scope.$watch( + () => `${scope.content.savedPlotter}|${scope.content.savedConfig}`, + updatePlot + ); + + scope.toggleMerged = () => { + scope.content.merged = !scope.content.merged; + updatePlot(); + }; + + scope.getPlotter = () => PlotService.getPlotter(scope.content); + scope.getPossiblePlotters = () => PlotService.plotters.filter(p => p.dataformat === scope.content.type).map(p => p.name); + scope.getPossibleConfigs = () => PlotService.getPossibleConfigs(scope.getPlotter()); }, template: ` <div id="{{domId}}-heading" class="panel-heading" role="tab"> @@ -66,13 +99,50 @@ angular.module('reportApp') href="#collapse-{{domId}}" aria-expanded="true" aria-controls="collapse-{{domId}}"> - {{ content.itemName }} </a> - <download-link - dom-id='{{ domId }}' - group='group' - item-id='itemId'> - </download-link> + {{ content.itemName }} + <div class='btn-group' role='group'> + <download-link + class='btn-group' + dom-id='{{ domId }}' + group='group' + item-id='itemId'> + </download-link> + <button ng-if='group.experiments.length > 1' class='btn btn-default' ng-click='toggleMerged()'> + <span ng-if='content.merged'><i class='fa fa-expand'></i> Expand</span> + <span ng-if='!content.merged'><i class='fa fa-compress'></i> Merge</span> + </button> + <div class='btn-group' role='group'> + <button + ng-class='{disabled: getPossiblePlotters().length === 1}' + class='btn btn-default dropdown-toggle' + type="button" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false"> + Plotter: {{ content.savedPlotter }} + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li ng-click='content.savedPlotter = p' ng-repeat='p in getPossiblePlotters()'><a>{{ p }}</a></li> + </ul> + </div> + <div class='btn-group' role='group'> + <button + ng-class='{disabled: getPossibleConfigs().length === 1}' + class='btn btn-default dropdown-toggle' + type="button" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false"> + Config: {{ content.savedConfig }} + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li ng-click='content.savedConfig = c' ng-repeat='c in getPossibleConfigs()'><a>{{ c }}</a></li> + </ul> + </div> + </div> </h4> </div> <div id="collapse-{{domId}}" diff --git a/beat/web/reports/static/reports/app/services/plotService.js b/beat/web/reports/static/reports/app/services/plotService.js index a80aa1d78..1422448a7 100644 --- a/beat/web/reports/static/reports/app/services/plotService.js +++ b/beat/web/reports/static/reports/app/services/plotService.js @@ -31,13 +31,13 @@ * - Rendering */ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlService){ - const ps = {}; - - // these are provided by ReportService - let plotters; - let defaultPlotters; - let plotterParameters; - let reportNumber; + const ps = { + // these are provided by ReportService + plotters: [], + defaultPlotters: [], + plotterParameters: [], + reportNumber: undefined + }; // this 'queue' idea is the solution to trying to load plots before we receive all the data // from the server that we need (report info, exp info, etc.). @@ -46,29 +46,53 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe const queue = []; let noQueueNeeded = false; - // constructs the payload to send to the server - const constructPlotInfo = (group, itemId) => { - console.log(group); - const content = group.reportItems.find(i => i.id === itemId).content; + const getDefaults = (plotType) => ps.defaultPlotters.find(p => p.dataformat === plotType); + // data to be used in to interact with the plot + // users can change the plotter used if theres more than 1 available for that + // plot type + const getPossiblePlotters = (itemContent) => + ps.plotters.filter(p => p.dataformat === itemContent.type).map(p => p.name); + + // users can choose which params to use if more than 1 available + // for that plotter + const getPossibleConfigs = (plotter) => + ps.plotterParameters.filter(pp => plotter.id === pp.plotter).map(pp => pp.name); + + const getPlotter = (itemContent) => { + const savedPlotterName = itemContent.savedPlotter; // defaults obj, in case we're using defaults - const defaults = defaultPlotters.find(p => p.dataformat === content.type); - if (!defaults) { - console.log(`No default plotter found for content type ${JSON.stringify(content.type)} out of:`); - console.log(defaultPlotters); - } + const defaults = getDefaults(itemContent.type); // a plot obj can have different plotters, - let plotter = plotters.find(p => p.name === content.savedPlotter) || plotters.find(p => p.name === defaults.plotter); + const plotter = ps.plotters.find(p => p.name === itemContent.savedPlotter) || + ps.plotters.find(p => p.name === defaults.plotter); + + return plotter; + }; - // which can each have different configurations (plotter parameter instances) - let config = plotterParameters.find(pp => pp.name === content.savedConfig) || plotterParameters.find(pp => pp.name === defaults.parameter); + const getPlotterConfig = (itemContent) => { + // defaults obj, in case we're using defaults + const defaults = getDefaults(itemContent.type); + + // each plotter obj can each have different configurations (plotter parameter instances) + const config = ps.plotterParameters.find(pp => pp.name === itemContent.savedConfig) || + ps.plotterParameters.find(pp => pp.name === defaults.parameter); + + return config; + }; + + // constructs the payload to send to the server + const constructPlotInfo = (group, itemId) => { + const content = group.reportItems.find(i => i.id === itemId).content; + const plotter = getPlotter(content); + const config = getPlotterConfig(content); - if(!content || !defaults || !plotter || !config){ + if(!content || !plotter || !config){ console.error(`plotter info not found: content: ${content} defaults: ${defaults} plotter: ${plotter} config: ${config}`); - console.log(plotters); - console.log(defaultPlotters); - console.log(plotterParameters); + console.log(ps.plotters); + console.log(ps.defaultPlotters); + console.log(ps.plotterParameters); return; } @@ -83,7 +107,7 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe // the data to be sent to the server const requestData = { - report_number: reportNumber, + report_number: ps.reportNumber, // exps in the group experiment: group.experiments, // group's analyzer @@ -101,29 +125,17 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe merged: content.merged === undefined ? true : content.merged }; - // data to be used in to interact with the plot - // users can change the plotter used if theres more than 1 available for that - // plot type - const possiblePlotters = plotters - .filter(p => p.dataformat === content.type) - .map(p => p.name) - ; - - // users can choose which params to use if more than 1 available - // for that plotter - const possibleParameters = plotterParameters - .filter(pp => plotter.id === pp.plotter) - .map(pp => pp.name) - ; + const possiblePlotters = getPossiblePlotters(content); + const possibleConfigs = getPossibleConfigs(plotter); console.log(`Request data:`); console.log(requestData); console.log(`possible plotters:`); console.log(possiblePlotters); console.log(`possible parameters:`); - console.log(possibleParameters); + console.log(possibleConfigs); - const returnStruct = [requestData, possiblePlotters, possibleParameters]; + const returnStruct = [requestData, possiblePlotters, possibleConfigs]; return returnStruct; }; @@ -204,10 +216,10 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe // processes the queue and sets the plotService state such that we dont need to use // the queue after this ps.processQueue = (rsPlotters, rsDefaultPlotters, rsPlotterParameters, rsReportNumber) => { - plotters = rsPlotters; - defaultPlotters = rsDefaultPlotters; - plotterParameters = rsPlotterParameters; - reportNumber = rsReportNumber; + rsPlotters.forEach(p => ps.plotters.push(p)); + rsDefaultPlotters.forEach(dp => ps.defaultPlotters.push(dp)); + rsPlotterParameters.forEach(pp => ps.plotterParameters.push(pp)); + ps.reportNumber = rsReportNumber; noQueueNeeded = true; const promises = queue.map(q => processItem(...q)); @@ -223,5 +235,12 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe // args: group, itemId, contentType ps.downloadPlot = (...args) => processDownload(...args); + ps.getPlotter = getPlotter; + ps.getPlotterConfig = getPlotterConfig; + ps.getPossiblePlotters = getPossiblePlotters; + ps.getPossibleConfigs = getPossibleConfigs; + + console.log(ps); + return ps; }]); diff --git a/beat/web/reports/static/reports/css/style.css b/beat/web/reports/static/reports/css/style.css index 0440251a9..8bbdc3678 100644 --- a/beat/web/reports/static/reports/css/style.css +++ b/beat/web/reports/static/reports/css/style.css @@ -211,7 +211,7 @@ div.report_commands div.report_buttons_bloc .publish_report:hover border-color: #4f85bb; } -.td_title > h2 { +.td_title > h3 { margin-left: 20px; margin-bottom: 0; } -- GitLab