@abi-software/simulationvuer 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,28 @@
1
- import Vue from "vue";
2
1
  import { evaluateValue } from "./common.js";
3
2
 
4
- export function prepareForUi(parent) {
3
+ export function initialiseUi(parent) {
4
+ // Initialise some input-related data.
5
+
5
6
  let index = -1;
7
+ let isPreviousDiscrete = true;
8
+
9
+ parent.simulationUiInformation.input.forEach((input) => {
10
+ let isDiscrete = input.possibleValues !== undefined;
11
+
12
+ parent.firstScalarInput[++index] = !isDiscrete && isPreviousDiscrete;
13
+
14
+ isPreviousDiscrete = isDiscrete;
15
+ });
16
+
17
+ // Initialise some output-related data.
6
18
 
7
- parent.json.output.data.forEach((data) => {
19
+ parent.simulationUiInformation.output.data.forEach((data) => {
8
20
  parent.simulationDataId[data.id] = data.name;
9
21
  });
10
22
 
11
- parent.json.output.plots.forEach((outputPlot) => {
23
+ index = -1;
24
+
25
+ parent.simulationUiInformation.output.plots.forEach((outputPlot) => {
12
26
  ++index;
13
27
 
14
28
  parent.layout[index] = {
@@ -34,240 +48,33 @@ export function prepareForUi(parent) {
34
48
  });
35
49
  }
36
50
 
37
- const VueContainer = Vue.extend({
38
- template: `
39
- <div class="sliders-and-fields"/>
40
- `,
41
- });
42
-
43
- const VueInputNumber = Vue.extend({
44
- methods: {
45
- emitSynchroniseSliderAndInputNumber: function(value) {
46
- this.$emit("synchroniseSliderAndInputNumber", this.index, value);
47
- }
48
- },
49
- props: {
50
- disabled: Boolean,
51
- index: Number,
52
- maximumValue: Number,
53
- minimumValue: Number,
54
- parent: Object,
55
- vModel: Number,
56
- },
57
- template: `
58
- <el-input-number class="scalar" size="mini" v-model="vModel" :controls="false" :disabled="disabled" :max="maximumValue" :min="minimumValue" @change="emitSynchroniseSliderAndInputNumber" />
59
- `,
60
- });
51
+ export function finaliseUi(parent) {
52
+ // Finalise our UI, but only if we haven't already done so, we are mounted,
53
+ // and we have some valid simulation UI information.
61
54
 
62
- const VueLabel = Vue.extend({
63
- props: {
64
- classes: String,
65
- label: String,
66
- },
67
- template: `
68
- <p :class="classes">{{ label }}</p>
69
- `,
70
- });
71
-
72
- const VueSelect = Vue.extend({
73
- methods: {
74
- emitSelectionChanged: function(value) {
75
- this.$emit("selectionChanged", this.index, value);
76
- }
77
- },
78
- props: {
79
- index: Number,
80
- parent: Object,
81
- possibleValues: Array,
82
- vModel: Number,
83
- },
84
- template: `
85
- <el-select class="discrete" popper-class="discrete-popper" size="mini" v-model="vModel" :popper-append-to-body="false" @change="emitSelectionChanged">
86
- <el-option v-for="possibleValue in possibleValues" :key="possibleValue.value" :label="possibleValue.name" :value="possibleValue.value" />
87
- </el-select>
88
- `,
89
- });
90
-
91
- const VueSlider = Vue.extend({
92
- methods: {
93
- emitSynchroniseSliderAndInputNumber: function(value) {
94
- this.$emit("synchroniseSliderAndInputNumber", this.index, value);
95
- }
96
- },
97
- props: {
98
- disabled: Boolean,
99
- index: Number,
100
- maximumValue: Number,
101
- parent: Object,
102
- vModel: Number,
103
- },
104
- template: `
105
- <el-slider v-model="vModel" :disabled="disabled" :max="maximumValue" :show-input="false" :show-tooltip="false" @input="emitSynchroniseSliderAndInputNumber" />
106
- `,
107
- });
108
-
109
- export default class Ui {
110
- discreteElements = [];
111
- scalarElements = [];
112
-
113
- setVueAttributes(root, element) {
114
- root.attributes.forEach((attribute) => {
115
- element.setAttribute(attribute.nodeName, attribute.nodeValue);
116
- });
117
-
118
- element.children.forEach((childElement) => {
119
- this.setVueAttributes(root, childElement);
120
- });
121
- }
122
-
123
- addVueElement(root, parent, element) {
124
- element.$mount();
125
-
126
- this.setVueAttributes(root, element.$el);
127
-
128
- parent.appendChild(element.$el);
129
- }
130
-
131
- selectionChanged() {
132
- // Enable/disable all the scalar elements.
55
+ if (!parent.hasFinalisedUi && parent.isMounted && parent.hasValidSimulationUiInformation) {
56
+ // Configure the PlotVuer's.
133
57
 
134
- let ui = (this instanceof Ui)?this:this.parent;
58
+ parent.$refs.output.classList.add("x" + parent.simulationUiInformation.output.plots.length);
135
59
 
136
- ui.scalarElements.forEach((scalarElement) => {
137
- let enabled = scalarElement.enabled;
60
+ // Make sure that our UI is up to date.
138
61
 
139
- if (enabled !== undefined) {
140
- let disabled = !evaluateValue(ui, enabled);
62
+ updateUi(parent);
141
63
 
142
- scalarElement.slider.disabled = disabled;
143
- scalarElement.input_number.disabled = disabled;
144
- }
145
- });
64
+ parent.hasFinalisedUi = true;
146
65
  }
66
+ }
147
67
 
148
- synchroniseSliderAndInputNumber(index, value) {
149
- // Make sure that both a slider and its corresponding input number have
150
- // the same value.
151
-
152
- this.parent.scalarElements[index].slider.vModel = value;
153
- this.parent.scalarElements[index].input_number.vModel = value;
154
- }
155
-
156
- constructor(parent) {
157
- // Generate the UI for the input fields.
158
-
159
- let inputRoot = parent.$refs.input;
160
- let isPreviousDiscrete = true;
161
- let slidersAndFieldsContainer = undefined;
162
- let firstScalarInput = true;
163
- let discreteElementIndex = -1;
164
- let scalarElementIndex = -1;
165
-
166
- parent.json.input.forEach((input) => {
167
- // Determine whether we are dealing with a discrete or a scalar input.
168
-
169
- let isDiscrete = input.possibleValues !== undefined;
170
-
171
- // Determine our element mode and create a container for our sliders and
172
- // input numbers, if needed.
173
-
174
- if (!isDiscrete && isPreviousDiscrete) {
175
- slidersAndFieldsContainer = new VueContainer();
176
-
177
- this.addVueElement(inputRoot, inputRoot, slidersAndFieldsContainer);
178
- }
179
-
180
- isPreviousDiscrete = isDiscrete;
181
-
182
- // Add the Label.
183
-
184
- let label = new VueLabel({
185
- propsData: {
186
- classes: "default " + (isDiscrete?"discrete":firstScalarInput?"first-scalar":"scalar"),
187
- label: input.name,
188
- }
189
- });
190
-
191
- this.addVueElement(inputRoot, isDiscrete?inputRoot:slidersAndFieldsContainer.$el, label);
192
-
193
- firstScalarInput = isDiscrete;
194
-
195
- // Add a drop-down list or a slider and a text box depending on whether
196
- // we are dealing with a discrete or a scalar input.
197
-
198
- if (isDiscrete) {
199
- // Add the drop-down list.
200
-
201
- ++discreteElementIndex;
202
-
203
- let select = new VueSelect({
204
- propsData: {
205
- index: discreteElementIndex,
206
- parent: this,
207
- possibleValues: input.possibleValues,
208
- vModel: input.defaultValue,
209
- },
210
- });
211
-
212
- this.addVueElement(inputRoot, inputRoot, select);
213
-
214
- select.$on("selectionChanged", this.selectionChanged);
215
-
216
- // Keep track of the select and its id.
217
-
218
- this.discreteElements[discreteElementIndex] = {
219
- id: input.id,
220
- select: select,
221
- };
222
- } else {
223
- // Add the slider and input number.
224
-
225
- ++scalarElementIndex;
226
-
227
- let slider = new VueSlider({
228
- propsData: {
229
- index: scalarElementIndex,
230
- maximumValue: input.maximumValue,
231
- parent: this,
232
- vModel: input.defaultValue,
233
- },
234
- });
235
- let inputNumber = new VueInputNumber({
236
- propsData: {
237
- index: scalarElementIndex,
238
- maximumValue: input.maximumValue,
239
- minimumValue: input.minimumValue,
240
- parent: this,
241
- vModel: input.defaultValue,
242
- },
243
- });
244
-
245
- this.addVueElement(inputRoot, slidersAndFieldsContainer.$el, slider);
246
- this.addVueElement(inputRoot, slidersAndFieldsContainer.$el, inputNumber);
247
-
248
- slider.$on("synchroniseSliderAndInputNumber", this.synchroniseSliderAndInputNumber);
249
- inputNumber.$on("synchroniseSliderAndInputNumber", this.synchroniseSliderAndInputNumber);
68
+ export function updateUi(parent) {
69
+ // Enable/disable all the elements.
70
+ // Note: we do this using $nextTick() to be ensure that the UI has been fully
71
+ // mounted.
250
72
 
251
- // Keep track of the slider and input number.
73
+ parent.$nextTick(() => {
74
+ let index = -1;
252
75
 
253
- this.scalarElements[scalarElementIndex] = {
254
- enabled: input.enabled,
255
- id: input.id,
256
- input_number: inputNumber,
257
- slider: slider,
258
- };
259
- }
76
+ parent.simulationUiInformation.input.forEach((input) => {
77
+ parent.$children[++index].enabled = (input.enabled === undefined)?true:evaluateValue(parent, input.enabled);
260
78
  });
261
-
262
- // Configure the PlotVuer's.
263
- // Note: the PlotVuer's are created in SimulationVuer.vue since we can't
264
- // create them dynamically. So, all we need to do here is to configure
265
- // them.
266
-
267
- parent.$refs.output.classList.add("x" + parent.json.output.plots.length);
268
-
269
- // Enable/disable all the elements by pretending that a selection changed.
270
-
271
- this.selectionChanged();
272
- }
79
+ });
273
80
  }
package/vue.config.js CHANGED
@@ -5,6 +5,5 @@ module.exports = {
5
5
  if (process.env.NODE_ENV === 'production') {
6
6
  config.externals = [nodeExternals({})];
7
7
  }
8
- },
9
- runtimeCompiler: true
8
+ }
10
9
  }
@@ -1,139 +0,0 @@
1
- export function jsonForNormalModel() {
2
- return {
3
- input: [
4
- {
5
- defaultValue: 0,
6
- id: "sm",
7
- name: "Simulation mode",
8
- possibleValues: [
9
- {
10
- name: "Normal sinus rhythm",
11
- value: 0,
12
- },
13
- {
14
- name: "Stellate stimulation",
15
- value: 1,
16
- },
17
- {
18
- name: "Vagal stimulation",
19
- value: 2,
20
- },
21
- ],
22
- },
23
- {
24
- defaultValue: 0,
25
- enabled: "(sm == 1) || (sm == 2)",
26
- id: "sl",
27
- maximumValue: 10,
28
- minimumValue: 0,
29
- name: "Stimulation level",
30
- },
31
- ],
32
- output: {
33
- data: [
34
- {
35
- id: "time",
36
- name: "environment/time",
37
- },
38
- {
39
- id: "vm",
40
- name: "Membrane/V",
41
- },
42
- ],
43
- plots: [
44
- {
45
- xAxisTitle: "Time (s)",
46
- xValue: "time",
47
- yAxisTitle: "Membrane potential (mV)",
48
- yValue: "vm",
49
- },
50
- ],
51
- },
52
- parameters: [
53
- {
54
- name: "Rate_modulation_experiments/Iso_1_uM",
55
- value: "(sm == 0) ? 0.0 : 1.0",
56
- },
57
- {
58
- name: "Rate_modulation_experiments/ACh",
59
- value: "(sm == 0) ? 0.0 : (sm === 1) ? (1.0 - 0.1 * sl) * 22.0e-6 : 22.0e-6 + 0.1 * sl * (38.0e-6 - 22.0e-6)",
60
- },
61
- ],
62
- simulation: {
63
- endingPoint: 3.0,
64
- pointInterval: 0.001,
65
- },
66
- };
67
- }
68
-
69
- export function jsonForCompositeModel() {
70
- return {
71
- input: [
72
- {
73
- defaultValue: 300,
74
- id: "sf",
75
- maximumValue: 1000,
76
- minimumValue: 0,
77
- name: "Spike frequency",
78
- },
79
- {
80
- defaultValue: 10,
81
- id: "sn",
82
- maximumValue: 30,
83
- minimumValue: 0,
84
- name: "Spike number",
85
- },
86
- {
87
- defaultValue: 10,
88
- id: "sa",
89
- maximumValue: 30,
90
- minimumValue: 0,
91
- name: "Spike amplitude",
92
- },
93
- ],
94
- output: {
95
- data: [
96
- {
97
- id: "sa",
98
- name: "Brain_stem/w",
99
- },
100
- {
101
- id: "time",
102
- name: "environment/time",
103
- },
104
- {
105
- id: "vm",
106
- name: "Membrane/V",
107
- },
108
- ],
109
- plots: [
110
- {
111
- xAxisTitle: "Time (s)",
112
- xValue: "time",
113
- yAxisTitle: "Spike amplitude",
114
- yValue: "100.0 * sa",
115
- },
116
- {
117
- xAxisTitle: "Time (s)",
118
- xValue: "time",
119
- yAxisTitle: "Membrane potential (mV)",
120
- yValue: "vm",
121
- },
122
- ],
123
- },
124
- parameters: [
125
- {
126
- name: "Brain_stem/t_period",
127
- value: "sf",
128
- },
129
- {
130
- name: "Brain_stem/w_n",
131
- value: "sn",
132
- },
133
- {
134
- name: "Brain_stem/w_value",
135
- value: "0.01 * sa",
136
- },
137
- ],
138
- };
139
- }