From 3ec9cc3497e0df458c259c25493caa74a5e7d649 Mon Sep 17 00:00:00 2001 From: Markus Grigull Date: Wed, 25 Jan 2017 12:54:34 +0100 Subject: [PATCH] Add missing files --- app/components/flow-plot.js | 27 +++ app/components/widget-plot.js | 205 ++++++++++++++++++ app/controllers/visualization/edit.js | 4 +- app/models/simulation-data.js | 25 ++- app/templates/components/flow-plot.hbs | 1 + app/templates/components/widget-plot.hbs | 56 +++++ .../integration/components/flow-plot-test.js | 24 ++ .../components/widget-plot-test.js | 24 ++ 8 files changed, 353 insertions(+), 13 deletions(-) create mode 100644 app/components/flow-plot.js create mode 100644 app/components/widget-plot.js create mode 100644 app/templates/components/flow-plot.hbs create mode 100644 app/templates/components/widget-plot.hbs create mode 100644 tests/integration/components/flow-plot-test.js create mode 100644 tests/integration/components/widget-plot-test.js diff --git a/app/components/flow-plot.js b/app/components/flow-plot.js new file mode 100644 index 0000000..01700ab --- /dev/null +++ b/app/components/flow-plot.js @@ -0,0 +1,27 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + tagName: 'div', + classNames: [ 'flow-plot' ], + attributeBindings: [ 'style' ], + + plot: null, + data: [], + options: {}, + height: '85%', + + setupPlot: Ember.on('didInsertElement', function() { + var plot = Ember.$.plot('#' + this.get('element').id, this.get('data'), this.get('options')); + this.set('plot', plot); + }), + + updateData: Ember.observer('data.@each', function() { + // update plot + var plot = Ember.$.plot('#' + this.get('element').id, this.get('data'), this.get('options')); + this.set('plot', plot); + }), + + style: Ember.computed('height', function() { + return Ember.String.htmlSafe("height: " + this.get('height') + ";"); + }) +}); diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js new file mode 100644 index 0000000..733c0da --- /dev/null +++ b/app/components/widget-plot.js @@ -0,0 +1,205 @@ +/** + * File: widget-value.js + * Author: Markus Grigull + * Date: 08.12.2016 + * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + **********************************************************************************/ + +import Ember from 'ember'; +import WidgetAbstract from './widget-abstract'; + +export default WidgetAbstract.extend({ + classNames: [ 'widgetPlot' ], + + plotData: Ember.A([]), + + plotOptions: { + series: { + lines: { + show: true, + lineWidth: 2 + }, + shadowSize: 0 + }, + xaxis: { + mode: 'time', + timeformat: '%M:%S', + /*min: firstTimestamp, + max: lastTimestamp,*/ + axisLabel: 'time [min]', + axisLabelUseCanvas: true + }/*, + yaxis: { + tickDecimals: 1, + axisLabel: this.data.get('type'), + axisLabelUseCanvas: true + }*/ + }, + + signals: Ember.A([]), + + _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', function() { + // get query for observer + let simulatorId = this.get('widget.widgetData.simulator'); + let query = 'data.' + simulatorId + '.sequence'; + + // get plot settings + let signals = this.get('widget.widgetData.signals'); + this.set('signals', signals); + + this.addObserver(query, function() { + // get values from array + let values = this.get('data.' + simulatorId + '.flotValues'); + var updatedValues = this.get('plotData'); + + // update values + var index = 0; + + this.get('signals').forEach(function(signal) { + updatedValues.replace(index, 1, Ember.A([ values[signal] ])); + index += 1; + }); + + this.set('plotData', updatedValues); + }); + })), + + doubleClick() { + if (this.get('editing') === true) { + // prepare modal + this.set('name', this.get('widget.name')); + this.set('errorMessage', null); + + // get signal mapping for simulation model + let self = this; + let simulatorid = this.get('widget.widgetData.simulator'); + + this.get('widget.visualization').then((visualization) => { + visualization.get('project').then((project) => { + project.get('simulation').then((simulation) => { + simulation.get('models').then((simulationModels) => { + // find simulation model by simulatorid + simulationModels.forEach(function(simulationModel) { + simulationModel.get('simulator').then((simulator) => { + if (simulator.get('simulatorid') === simulatorid) { + // set simulation model + self.set('simulationModel', simulationModel); + self.set('simulationModelName', simulationModel.get('name')); + + // set signals + let mapping = simulationModel.get('mapping'); + + // uncheck all signals + mapping.forEach(function(key) { + self.set(key + 'Checked', false); + }); + + self.get('signals').forEach(function(signal) { + self.set(mapping[signal] + 'Checked', true); + }); + } + }); + }); + }); + }); + }); + }); + + // show modal + this.set('isShowingModal', true); + } + }, + + actions: { + submitModal() { + // verify properties + let properties = this.getProperties('name'); + + if (properties['name'] === null || properties['name'] === "") { + this.set('errorMessage', 'Widget name is missing'); + return; + } + + // set simulator by simulation model name + let simulationModelName = this.get('simulationModelName'); + let self = this; + + this.get('widget.visualization').then((visualization) => { + visualization.get('project').then((project) => { + project.get('simulation').then((simulation) => { + simulation.get('models').then((simulationModels) => { + // find simulation model by name + simulationModels.forEach(function(simulationModel) { + if (simulationModel.get('name') === simulationModelName) { + simulationModel.get('simulator').then((simulator) => { + // set simulator + let widgetData = {}; + widgetData.simulator = simulator.get('simulatorid'); + + // set signals + let mapping = simulationModel.get('mapping'); + widgetData.signals = []; + + // uncheck all signals + for (var i = 0; i < mapping.length; i++) { + if (self.get(mapping[i] + 'Checked')) { + widgetData.signals.push(i); + } + } + + // save properties + properties['widgetData'] = widgetData; + + console.log(properties); + + self.get('widget').setProperties(properties); + + self.get('widget').save().then(function() { + self.set('isShowingModal', false); + }); + }); + } + }); + }); + }); + }); + }); + }, + + cancelModal() { + this.set('isShowingModal', false); + }, + + deleteModal() { + // delete widget + this.get('widget').destroyRecord(); + + this.set('isShowingModal', false); + }, + + selectSimulationModel(simulationModelName) { + // save simulation model + this.set('simulationModelName', simulationModelName); + + // get signal mapping for simulation model + let self = this; + + this.get('widget.visualization').then((visualization) => { + visualization.get('project').then((project) => { + project.get('simulation').then((simulation) => { + simulation.get('models').then((simulationModels) => { + // find simulation model by name + simulationModels.forEach(function(simulationModel) { + if (simulationModel.get('name') === simulationModelName) { + self.set('simulationModel', simulationModel); + } + }); + }); + }); + }); + }); + } + } +}); diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js index c6033a1..5d7556d 100644 --- a/app/controllers/visualization/edit.js +++ b/app/controllers/visualization/edit.js @@ -62,8 +62,8 @@ export default Ember.Controller.extend(FetchLiveDataMixin, { properties.type = 'widget-plot'; properties.name = 'Plot'; properties.width = 500; - properties.height = 200; - properties.widgetData = { signal: 0, simulator: defaultSimulatorid }; + properties.height = 400; + properties.widgetData = { signals: [0], simulator: defaultSimulatorid, type: 'multiple' }; } else { // DEBUG console.log('Add unknown widget ' + name); diff --git a/app/models/simulation-data.js b/app/models/simulation-data.js index 44eb110..b978222 100644 --- a/app/models/simulation-data.js +++ b/app/models/simulation-data.js @@ -24,19 +24,22 @@ export default Model.extend({ _flotValues: [], - historyValues: Ember.computed('_history', function() { - return this._history; - }), - - _history: [], - _updateHistories: Ember.observer('values', function() { - // save set of values with timestamp - this._flotValues.push([this.get('timestamp'), this.get('values')[0]]); + // update flot values + let values = this.get('values'); - // discard old values - while (this._flotValues.length > 100) { - this._flotValues.shift(); + // add empty arrays for each value + while (this._flotValues.length < values.length) { + this._flotValues.push([]); + } + + for (var i = 0; i < values.length; i++) { + this._flotValues[i].push([this.get('timestamp'), values[i]]); + + // discard old values + while (this._flotValues[i].length > 100) { + this._flotValues[i].shift(); + } } }) }); diff --git a/app/templates/components/flow-plot.hbs b/app/templates/components/flow-plot.hbs new file mode 100644 index 0000000..889d9ee --- /dev/null +++ b/app/templates/components/flow-plot.hbs @@ -0,0 +1 @@ +{{yield}} diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs new file mode 100644 index 0000000..3f04c8f --- /dev/null +++ b/app/templates/components/widget-plot.hbs @@ -0,0 +1,56 @@ +

{{widget.name}}

+ +{{flow-plot data=plotData options=plotOptions}} + +{{#if isShowingModal}} + {{#modal-dialog attachment="middle center" translucentOverlay=true}} +

Plot

+ +
+ + + + + + + + + + + + + + + + +
+ + + {{input id='name' placeholder='Enter widget name' value=name}} +
+ + + +
+ + + {{#each simulationModel.mapping as |signal|}} + +
+ {{/each}} +
+ + + +
+
+ + {{#if errorMessage}} +

Error: {{errorMessage}}

+ {{/if}} + {{/modal-dialog}} +{{/if}} diff --git a/tests/integration/components/flow-plot-test.js b/tests/integration/components/flow-plot-test.js new file mode 100644 index 0000000..949b9a7 --- /dev/null +++ b/tests/integration/components/flow-plot-test.js @@ -0,0 +1,24 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('flow-plot', 'Integration | Component | flow plot', { + integration: true +}); + +test('it renders', function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{flow-plot}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage: + this.render(hbs` + {{#flow-plot}} + template block text + {{/flow-plot}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +}); diff --git a/tests/integration/components/widget-plot-test.js b/tests/integration/components/widget-plot-test.js new file mode 100644 index 0000000..1b38f7a --- /dev/null +++ b/tests/integration/components/widget-plot-test.js @@ -0,0 +1,24 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('widget-plot', 'Integration | Component | widget plot', { + integration: true +}); + +test('it renders', function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{widget-plot}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage: + this.render(hbs` + {{#widget-plot}} + template block text + {{/widget-plot}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +});