pict-section-form 1.0.138 → 1.0.139
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.
- package/docs/input_providers/009-chart.md +181 -0
- package/example_applications/complex_table/Complex-Tabular-Application.js +287 -120
- package/example_applications/complex_table/html/index.html +1 -0
- package/example_applications/complex_table/package.json +8 -2
- package/package.json +2 -2
- package/source/providers/Pict-Provider-DynamicSolver.js +17 -1
- package/source/providers/dynamictemplates/Pict-DynamicTemplates-DefaultFormTemplates.js +12 -0
- package/source/providers/inputs/Pict-Provider-Input-Chart.js +264 -0
- package/source/providers/layouts/Pict-Layout-Record.js +50 -1
- package/source/views/Pict-View-Form-Metacontroller.js +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Chart Input Type
|
|
2
|
+
|
|
3
|
+
Chart input types wrap one of a few charting libraries. This means the tech is
|
|
4
|
+
compatible with chart.js, c3 and d3 natively and more can be easily added.
|
|
5
|
+
|
|
6
|
+
## Defaults
|
|
7
|
+
|
|
8
|
+
By default charts use `chart.js` and are `bar` charts. They will try to cast
|
|
9
|
+
an array or object into a meaningful data set.
|
|
10
|
+
|
|
11
|
+
This means minimum viable config is something like the following:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"Scope": "ChartDemo",
|
|
16
|
+
|
|
17
|
+
"Descriptors":
|
|
18
|
+
{
|
|
19
|
+
"Chart.Display":
|
|
20
|
+
{
|
|
21
|
+
"Name": "MVP Chart",
|
|
22
|
+
"Hash": "MVPChart",
|
|
23
|
+
"DataType": "Object",
|
|
24
|
+
"PictForm":
|
|
25
|
+
{
|
|
26
|
+
"InputType": "Chart",
|
|
27
|
+
"ChartDataAddress": "City.Populations"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
And AppData has something like this:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"City":
|
|
39
|
+
{
|
|
40
|
+
"Populations":
|
|
41
|
+
{
|
|
42
|
+
"Seattle": 324230,
|
|
43
|
+
"Lynnwood": 2349,
|
|
44
|
+
"Burien": 1500,
|
|
45
|
+
"Tacoma": 23498,
|
|
46
|
+
"Olympia": 17984,
|
|
47
|
+
"Redmond": 8700,
|
|
48
|
+
"Kirkland": 9723,
|
|
49
|
+
"Bellevue": 11001
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
You will end up with a bar graph that has the X axis as cities, y axis as
|
|
56
|
+
populations and the series will be named "City.Populations" as such:
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## Data Addresses, Raw Objects and Configurable Programmability _(oh my!)_
|
|
61
|
+
|
|
62
|
+
There is a three tiered system to how the chart configuration is generated.
|
|
63
|
+
Because modern charting libraries rely almost entirely on configuration to
|
|
64
|
+
define behavior these days, we can manage the displays this way and only
|
|
65
|
+
rely on the pict-section-form library to broker data back-and-forth.
|
|
66
|
+
|
|
67
|
+
### Purely Raw Data
|
|
68
|
+
|
|
69
|
+
You can hard code any chart right into the form. There are three places
|
|
70
|
+
for raw form config:
|
|
71
|
+
|
|
72
|
+
* `ChartLabelsRaw` - the "labels" object for the chart
|
|
73
|
+
* `ChartDatasetsRaw` - the "data" object for the chart
|
|
74
|
+
* `ChartJSOptionsCorePrototype` - the chart.js config base
|
|
75
|
+
|
|
76
|
+
The input provider will use the `ChartJSOptionsCorePrototype` and then
|
|
77
|
+
decorate in the `labels` and `data` objects from their raw entries.
|
|
78
|
+
|
|
79
|
+
Chaining always does the following:
|
|
80
|
+
|
|
81
|
+
1. If there is a `Raw`
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"SimpleGraphExampleRawData":
|
|
86
|
+
{
|
|
87
|
+
Name: "OrderCaloryGraph",
|
|
88
|
+
Hash: "OrderCaloryGraph",
|
|
89
|
+
|
|
90
|
+
DataType: "Object",
|
|
91
|
+
PictForm:
|
|
92
|
+
{
|
|
93
|
+
Section: "Chart",
|
|
94
|
+
Group: "SimpleChart",
|
|
95
|
+
|
|
96
|
+
Row: 1,
|
|
97
|
+
Width: 12,
|
|
98
|
+
|
|
99
|
+
InputType: "Chart",
|
|
100
|
+
|
|
101
|
+
ChartLabelsRaw: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
|
102
|
+
|
|
103
|
+
ChartDatasetsRaw: [
|
|
104
|
+
{
|
|
105
|
+
label: 'Awesomeness',
|
|
106
|
+
data: [ 1500, 1200, 800, 1700, 900, 2000 ]
|
|
107
|
+
}],
|
|
108
|
+
|
|
109
|
+
ChartJSOptionsCorePrototype:
|
|
110
|
+
{
|
|
111
|
+
type: 'bar'
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Purely Raw Data
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"SimpleGraphExampleRawData":
|
|
123
|
+
{
|
|
124
|
+
Name: "OrderCaloryGraph",
|
|
125
|
+
Hash: "OrderCaloryGraph",
|
|
126
|
+
|
|
127
|
+
DataType: "Object",
|
|
128
|
+
PictForm:
|
|
129
|
+
{
|
|
130
|
+
Section: "Chart",
|
|
131
|
+
Group: "SimpleChart",
|
|
132
|
+
Row: 1,
|
|
133
|
+
Width: 12,
|
|
134
|
+
InputType: "Chart",
|
|
135
|
+
|
|
136
|
+
ChartType: "bar",
|
|
137
|
+
|
|
138
|
+
// This allows you to scope data for the chart separately from appdata
|
|
139
|
+
ChartDataScope: "Form",
|
|
140
|
+
|
|
141
|
+
ChartDataAddress: "FruitData.FruityVice",
|
|
142
|
+
|
|
143
|
+
ChartLabelsAddress: "FruitData.FruityVice",
|
|
144
|
+
ChartLabelsRaw: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
|
145
|
+
|
|
146
|
+
ChartDatasetsAddress: "FruitData.FruityVice",
|
|
147
|
+
ChartDatasetsConfig:
|
|
148
|
+
{
|
|
149
|
+
Calories:
|
|
150
|
+
{
|
|
151
|
+
ChartLabel: "Calories",
|
|
152
|
+
DataSolver: "Data = {~D:Record.nutritions.calories~}",
|
|
153
|
+
DataTemplate: "{~D:Record.SolverResult~}", // Could also be something from the solver postfix stack
|
|
154
|
+
DataCorePrototype:
|
|
155
|
+
{
|
|
156
|
+
borderWidth: 1
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
ChartDatasetsRaw: [
|
|
161
|
+
{
|
|
162
|
+
label: 'Awesomeness',
|
|
163
|
+
data: [ 1500, 1200, 800, 1700, 900, 2000 ]
|
|
164
|
+
}],
|
|
165
|
+
|
|
166
|
+
// Do anything you want here!!
|
|
167
|
+
ChartJSOptionsCorePrototype:
|
|
168
|
+
{
|
|
169
|
+
type: 'bar',
|
|
170
|
+
options: {
|
|
171
|
+
scales: {
|
|
172
|
+
y: {
|
|
173
|
+
beginAtZero: true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
@@ -24,45 +24,45 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
24
24
|
Scope: "SuperComplexTabularForm",
|
|
25
25
|
|
|
26
26
|
PickLists:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
27
|
+
[
|
|
28
|
+
{
|
|
29
|
+
Hash: "Families",
|
|
30
|
+
ListAddress: "AppData.FruitMetaLists.Families",
|
|
31
|
+
ListSourceAddress: "FruitData.FruityVice[]",
|
|
32
|
+
TextTemplate: "{~D:Record.family~}",
|
|
33
|
+
IDTemplate: "{~D:Record.family~}",
|
|
34
|
+
Unique: true,
|
|
35
|
+
Sorted: true,
|
|
36
|
+
UpdateFrequency: "Once",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
Hash: "Orders",
|
|
40
|
+
ListAddress: "AppData.FruitMetaLists.Orders",
|
|
41
|
+
ListSourceAddress: "FruitData.FruityVice[]",
|
|
42
|
+
TextTemplate: "{~D:Record.order~}",
|
|
43
|
+
IDTemplate: "{~D:Record.order~}",
|
|
44
|
+
Unique: true,
|
|
45
|
+
UpdateFrequency: "Once",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
Hash: "Genuses",
|
|
49
|
+
ListAddress: "AppData.FruitMetaLists.Genuses",
|
|
50
|
+
ListSourceAddress: "FruitData.FruityVice[]",
|
|
51
|
+
TextTemplate: "{~D:Record.genus~}",
|
|
52
|
+
IDTemplate: "{~D:Record.genus~}",
|
|
53
|
+
Sorted: true,
|
|
54
|
+
UpdateFrequency: "Always",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
Hash: "Books",
|
|
58
|
+
ListAddress: "AppData.AuthorsBooks",
|
|
59
|
+
ListSourceAddress: "Books[]",
|
|
60
|
+
TextTemplate: "{~D:Record.Title~}",
|
|
61
|
+
IDTemplate: "{~D:Record.IDBook~}",
|
|
62
|
+
Sorted: true,
|
|
63
|
+
UpdateFrequency: "Always",
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
66
|
|
|
67
67
|
Sections: [
|
|
68
68
|
{
|
|
@@ -70,27 +70,27 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
70
70
|
Name: "Fruit-based Recipe",
|
|
71
71
|
|
|
72
72
|
Solvers:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
[
|
|
74
|
+
"TotalFruitCalories = SUM(FruitNutritionCalories)",
|
|
75
|
+
"AverageFruitCalories = MEAN(FruitNutritionCalories)",
|
|
76
|
+
{
|
|
77
|
+
Ordinal: 99,
|
|
78
|
+
Expression: "AverageFatPercent = MEAN(FruitPercentTotalFat)",
|
|
79
|
+
},
|
|
80
|
+
"RecipeCounterSurfaceArea = RecipeCounterWidth * RecipeCounterDepth",
|
|
81
|
+
"RecipeCounterVolume = RecipeCounterSurfaceArea * RecipeVerticalClearance",
|
|
82
|
+
`InspirationLink = CONCAT("https://www.google.com/search?q=", RecipeName, " recipe")`,
|
|
83
|
+
'cumulativeSummationResult = cumulativeSummation(getvalue("AppData.FruitData.FruityVice"), "nutritions.calories", "SummedCalories")'
|
|
84
|
+
],
|
|
85
85
|
|
|
86
86
|
MetaTemplates:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
[
|
|
88
|
+
{
|
|
89
|
+
//onclick="{~D:Record.Macro.DataRequestFunction~}"
|
|
90
|
+
"HashPostfix": "-Template-Wrap-Prefix",
|
|
91
|
+
"Template": "<h1>Rectangular Area Solver Micro-app</h1><div><a href=\"#\" onclick=\"{~Pict~}.PictApplication.solve()\">[ solve ]</a> <a href=\"#\" onclick=\"{~P~}.views.PictFormMetacontroller.showSupportViewInlineEditor()\">[ debug ]</a></div><hr />"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
94
|
|
|
95
95
|
Groups: [
|
|
96
96
|
{
|
|
@@ -101,13 +101,13 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
101
101
|
{
|
|
102
102
|
Hash: "StatisticsTabs",
|
|
103
103
|
Name: "Select a Statistics Section",
|
|
104
|
-
// ShowTitle: true
|
|
104
|
+
// ShowTitle: true
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
Hash: "Statistics",
|
|
108
108
|
Name: "Statistics",
|
|
109
109
|
Layout: "Vertical",
|
|
110
|
-
// ShowTitle: true
|
|
110
|
+
// ShowTitle: true
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
Hash: "FruitStatistics",
|
|
@@ -157,18 +157,18 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
157
157
|
],
|
|
158
158
|
|
|
159
159
|
PickLists:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
160
|
+
[
|
|
161
|
+
{
|
|
162
|
+
Hash: "Families",
|
|
163
|
+
ListAddress: "AppData.FruitMetaLists.Families",
|
|
164
|
+
ListSourceAddress: "FruitData.FruityVice[]",
|
|
165
|
+
TextTemplate: "{~D:Record.family~}",
|
|
166
|
+
IDTemplate: "{~D:Record.family~}",
|
|
167
|
+
Unique: true,
|
|
168
|
+
Sorted: true,
|
|
169
|
+
UpdateFrequency: "Once",
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
172
|
RecordSetAddress: "FruitData.FruityVice",
|
|
173
173
|
RecordManifest: "FruitEditor",
|
|
174
174
|
},
|
|
@@ -209,12 +209,12 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
209
209
|
Name: "Recipe Type",
|
|
210
210
|
Hash: "RecipeType",
|
|
211
211
|
DataType: "String",
|
|
212
|
-
PictForm:
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
212
|
+
PictForm:
|
|
213
|
+
{
|
|
214
|
+
Section: "Recipe",
|
|
215
|
+
Group: "Recipe",
|
|
216
|
+
Row: 1
|
|
217
|
+
},
|
|
218
218
|
},
|
|
219
219
|
RecipeDescription: {
|
|
220
220
|
Name: "Description",
|
|
@@ -244,7 +244,8 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
244
244
|
Name: "Last Prepared",
|
|
245
245
|
Hash: "LastPrepared",
|
|
246
246
|
DataType: "DateTime",
|
|
247
|
-
PictForm: {
|
|
247
|
+
PictForm: {
|
|
248
|
+
Section: "Recipe", Group: "Recipe", Row: 4,
|
|
248
249
|
"Providers": ["Pict-Input-DateTime"]
|
|
249
250
|
},
|
|
250
251
|
},
|
|
@@ -254,28 +255,28 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
254
255
|
Hash: "IDAuthor",
|
|
255
256
|
DataType: "Number",
|
|
256
257
|
PictForm: {
|
|
257
|
-
Section: "Book", Group: "Author", Row: 1, Width: 1,
|
|
258
|
+
Section: "Book", Group: "Author", Row: 1, Width: 1,
|
|
258
259
|
// This performs an entity bundle request whenever a value is selected.
|
|
259
260
|
Providers: ["Pict-Input-EntityBundleRequest", "Pict-Input-AutofillTriggerGroup"],
|
|
260
261
|
EntitiesBundle: [
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
262
|
+
{
|
|
263
|
+
"Entity": "Author",
|
|
264
|
+
"Filter": "FBV~IDAuthor~EQ~{~D:Record.Value~}",
|
|
265
|
+
"Destination": "AppData.CurrentAuthor",
|
|
266
|
+
// This marshals a single record
|
|
267
|
+
"SingleRecord": true
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"Entity": "BookAuthorJoin",
|
|
271
|
+
"Filter": "FBV~IDAuthor~EQ~{~D:AppData.CurrentAuthor.IDAuthor~}",
|
|
272
|
+
"Destination": "AppData.BookAuthorJoins"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"Entity": "Book",
|
|
276
|
+
"Filter": "FBL~IDBook~INN~{~PJU:,^IDBook^AppData.BookAuthorJoins~}",
|
|
277
|
+
"Destination": "AppData.Books"
|
|
278
|
+
}
|
|
279
|
+
],
|
|
279
280
|
EntityBundleTriggerGroup: "BookTriggerGroup"
|
|
280
281
|
}
|
|
281
282
|
},
|
|
@@ -288,11 +289,11 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
288
289
|
// This performs an entity bundle request whenever a value is selected.
|
|
289
290
|
Providers: ["Pict-Input-AutofillTriggerGroup"],
|
|
290
291
|
AutofillTriggerGroup:
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
292
|
+
{
|
|
293
|
+
TriggerGroupHash: "BookTriggerGroup",
|
|
294
|
+
TriggerAddress: "AppData.CurrentAuthor.Name",
|
|
295
|
+
MarshalEmptyValues: true
|
|
296
|
+
}
|
|
296
297
|
}
|
|
297
298
|
},
|
|
298
299
|
|
|
@@ -310,15 +311,178 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
310
311
|
Section: "Book",
|
|
311
312
|
Group: "Book",
|
|
312
313
|
Row: 1, Width: 1,
|
|
313
|
-
InputType:"Option",
|
|
314
|
+
InputType: "Option",
|
|
314
315
|
SelectOptionsPickList: "Books",
|
|
315
316
|
// This performs an entity bundle request whenever a value is selected.
|
|
316
317
|
Providers: ["Pict-Input-Select", "Pict-Input-AutofillTriggerGroup"],
|
|
317
318
|
AutofillTriggerGroup:
|
|
319
|
+
{
|
|
320
|
+
TriggerGroupHash: "BookTriggerGroup",
|
|
321
|
+
SelectOptionsRefresh: true
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
"SimpleGraphExampleRawDataOne":
|
|
327
|
+
{
|
|
328
|
+
Name: "SimpleGraphExampleOne",
|
|
329
|
+
Hash: "SimpleGraphExampleOne",
|
|
330
|
+
|
|
331
|
+
DataType: "Object",
|
|
332
|
+
PictForm:
|
|
333
|
+
{
|
|
334
|
+
Section: "Chart",
|
|
335
|
+
Group: "SimpleChart",
|
|
336
|
+
|
|
337
|
+
Row: 1,
|
|
338
|
+
Width: 3,
|
|
339
|
+
|
|
340
|
+
InputType: "Chart",
|
|
341
|
+
|
|
342
|
+
ChartLabelsRaw: ['Red', 'Green', 'Yellow', 'Grey', 'Blue'],
|
|
343
|
+
|
|
344
|
+
ChartDatasetsRaw: [{
|
|
345
|
+
label: 'My First Dataset',
|
|
346
|
+
data: [11, 16, 7, 3, 14],
|
|
347
|
+
backgroundColor:
|
|
348
|
+
[
|
|
349
|
+
'rgb(255, 99, 132)',
|
|
350
|
+
'rgb(75, 192, 192)',
|
|
351
|
+
'rgb(255, 205, 86)',
|
|
352
|
+
'rgb(201, 203, 207)',
|
|
353
|
+
'rgb(54, 162, 235)'
|
|
354
|
+
]
|
|
355
|
+
}],
|
|
356
|
+
|
|
357
|
+
ChartJSOptionsCorePrototype:
|
|
358
|
+
{
|
|
359
|
+
type: 'polarArea'
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
"SimpleGraphExampleRawDataTwo":
|
|
365
|
+
{
|
|
366
|
+
Name: "SimpleGraphExampleTwo",
|
|
367
|
+
Hash: "SimpleGraphExampleTwo",
|
|
368
|
+
|
|
369
|
+
DataType: "Object",
|
|
370
|
+
PictForm:
|
|
371
|
+
{
|
|
372
|
+
Section: "Chart",
|
|
373
|
+
Group: "SimpleChart",
|
|
374
|
+
|
|
375
|
+
Row: 2,
|
|
376
|
+
Width: 6,
|
|
377
|
+
|
|
378
|
+
InputType: "Chart",
|
|
379
|
+
|
|
380
|
+
ChartType: "bar",
|
|
381
|
+
ChartLabelsSolver: `objectkeystoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.calories"))`,
|
|
382
|
+
ChartDataSolvers:
|
|
383
|
+
[
|
|
384
|
+
{
|
|
385
|
+
Label: 'Calories',
|
|
386
|
+
DataSolver: `objectvaluestoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.calories"))`
|
|
387
|
+
}
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
"SimpleGraphExampleRawDataThree":
|
|
393
|
+
{
|
|
394
|
+
Name: "SimpleGraphExampleThree",
|
|
395
|
+
Hash: "SimpleGraphExampleThree",
|
|
396
|
+
|
|
397
|
+
DataType: "Object",
|
|
398
|
+
PictForm:
|
|
399
|
+
{
|
|
400
|
+
Section: "Chart",
|
|
401
|
+
Group: "SimpleChart",
|
|
402
|
+
|
|
403
|
+
Row: 2,
|
|
404
|
+
Width: 6,
|
|
405
|
+
|
|
406
|
+
InputType: "Chart",
|
|
407
|
+
|
|
408
|
+
ChartType: "bar",
|
|
409
|
+
ChartLabelsSolver: `objectkeystoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.fat"))`,
|
|
410
|
+
ChartDataSolvers:
|
|
411
|
+
[
|
|
412
|
+
{
|
|
413
|
+
Label: 'Fat',
|
|
414
|
+
DataSolver: `objectvaluestoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.fat"))`
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
Label: 'Carbohydrates',
|
|
418
|
+
DataSolver: `objectvaluestoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.carbohydrates"))`
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
Label: 'Protein',
|
|
422
|
+
DataSolver: `objectvaluestoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.protein"))`
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
Label: 'Sugars',
|
|
426
|
+
DataSolver: `objectvaluestoarray(aggregationhistogrambyobject(FruitGrid, "name", "nutritions.sugar"))`
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
"WideGraphExample": {
|
|
433
|
+
Name: "WideGraphExample",
|
|
434
|
+
Hash: "WideGraphExample",
|
|
435
|
+
DataType: "Object",
|
|
436
|
+
PictForm:
|
|
437
|
+
{
|
|
438
|
+
Section: "Chart",
|
|
439
|
+
Group: "SimpleChart",
|
|
440
|
+
Row: 3,
|
|
441
|
+
Width: 12,
|
|
442
|
+
InputType: "Chart",
|
|
443
|
+
|
|
444
|
+
//ChartType: "Bar",
|
|
445
|
+
|
|
446
|
+
// This allows you to scope data for the chart separately from appdata
|
|
447
|
+
ChartDataScope: "Form",
|
|
448
|
+
|
|
449
|
+
ChartDataAddress: "FruitData.FruityVice",
|
|
450
|
+
|
|
451
|
+
ChartLabelsAddress: "FruitData.FruityVice",
|
|
452
|
+
ChartLabelsRaw: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
|
453
|
+
|
|
454
|
+
ChartDatasetsAddress: "FruitData.FruityVice",
|
|
455
|
+
ChartDatasetsConfig:
|
|
456
|
+
{
|
|
457
|
+
Calories:
|
|
318
458
|
{
|
|
319
|
-
|
|
320
|
-
|
|
459
|
+
ChartLabel: "Calories",
|
|
460
|
+
DataSolver: "Data = {~D:Record.nutritions.calories~}",
|
|
461
|
+
DataTemplate: "{~D:Record.SolverResult~}", // Could also be something from the solver postfix stack
|
|
462
|
+
DataCorePrototype:
|
|
463
|
+
{
|
|
464
|
+
borderWidth: 1
|
|
465
|
+
}
|
|
321
466
|
}
|
|
467
|
+
},
|
|
468
|
+
ChartDatasetsRaw: [
|
|
469
|
+
{
|
|
470
|
+
label: 'Awesomeness',
|
|
471
|
+
data: [1500, 1200, 800, 1700, 900, 2000]
|
|
472
|
+
}],
|
|
473
|
+
|
|
474
|
+
// Do anything you want here!!
|
|
475
|
+
ChartJSOptionsCorePrototype:
|
|
476
|
+
{
|
|
477
|
+
type: 'bar',
|
|
478
|
+
options: {
|
|
479
|
+
scales: {
|
|
480
|
+
y: {
|
|
481
|
+
beginAtZero: true
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
322
486
|
}
|
|
323
487
|
},
|
|
324
488
|
|
|
@@ -328,7 +492,7 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
328
492
|
DataType: "String",
|
|
329
493
|
PictForm: {
|
|
330
494
|
Section: "Recipe",
|
|
331
|
-
Group: "StatisticsTabs",
|
|
495
|
+
Group: "StatisticsTabs",
|
|
332
496
|
InputType: "TabGroupSelector",
|
|
333
497
|
// The default when there is no state is the first entry here.
|
|
334
498
|
// If you want to set a default, you can just do it in the state address though.
|
|
@@ -356,11 +520,12 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
356
520
|
Hash: "RecipeFeeds",
|
|
357
521
|
DataType: "PreciseNumber",
|
|
358
522
|
Default: "1",
|
|
359
|
-
PictForm: {
|
|
523
|
+
PictForm: {
|
|
524
|
+
Section: "Recipe", Group: "Statistics", Row: 1, Width: 1,
|
|
360
525
|
"ExtraDescription": "How many people does this recipe feed?",
|
|
361
|
-
"InputType":"Option",
|
|
526
|
+
"InputType": "Option",
|
|
362
527
|
"Providers": ["CustomDataProvider", "Pict-Input-Select"],
|
|
363
|
-
"SelectOptions": [{"id":"few", "text":"Few"}, {"id":"some", "text":"Some"}, {"id":"many", "text":"Many"}]
|
|
528
|
+
"SelectOptions": [{ "id": "few", "text": "Few" }, { "id": "some", "text": "Some" }, { "id": "many", "text": "Many" }]
|
|
364
529
|
},
|
|
365
530
|
},
|
|
366
531
|
"Recipe.TotalCalories": {
|
|
@@ -373,7 +538,7 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
373
538
|
Group: "Statistics",
|
|
374
539
|
Row: 1,
|
|
375
540
|
Width: 1
|
|
376
|
-
|
|
541
|
+
},
|
|
377
542
|
},
|
|
378
543
|
|
|
379
544
|
"Recipe.CounterWidth": {
|
|
@@ -622,9 +787,11 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
622
787
|
Name: "Family",
|
|
623
788
|
Hash: "Family",
|
|
624
789
|
DataType: "String",
|
|
625
|
-
PictForm: {
|
|
790
|
+
PictForm: {
|
|
791
|
+
Section: "FruitGrid", Group: "FruitGrid", "InputType": "Option",
|
|
626
792
|
"Providers": ["Pict-Input-Select"],
|
|
627
|
-
"SelectOptionsPickList": "Families"
|
|
793
|
+
"SelectOptionsPickList": "Families"
|
|
794
|
+
}
|
|
628
795
|
},
|
|
629
796
|
order: {
|
|
630
797
|
Name: "Order",
|
|
@@ -642,13 +809,13 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
642
809
|
Name: "Last Watered",
|
|
643
810
|
Hash: "LastWatered",
|
|
644
811
|
DataType: "DateTime",
|
|
645
|
-
PictForm: { Section: "FruitGrid", Group: "FruitGrid", "InputType":"DateTime", "Providers": ["Pict-Input-DateTime"]},
|
|
812
|
+
PictForm: { Section: "FruitGrid", Group: "FruitGrid", "InputType": "DateTime", "Providers": ["Pict-Input-DateTime"] },
|
|
646
813
|
},
|
|
647
814
|
"nutritions.calories": {
|
|
648
815
|
Name: "Calories",
|
|
649
816
|
Hash: "Calories",
|
|
650
817
|
DataType: "Number",
|
|
651
|
-
PictForm: { Section: "FruitGrid", Group: "FruitGrid"},
|
|
818
|
+
PictForm: { Section: "FruitGrid", Group: "FruitGrid" },
|
|
652
819
|
},
|
|
653
820
|
"SummedCalories": {
|
|
654
821
|
Name: "Summed Calories (cumulative)",
|
|
@@ -696,11 +863,11 @@ module.exports.default_configuration.pict_configuration = {
|
|
|
696
863
|
// This performs an entity bundle request whenever a value is selected.
|
|
697
864
|
Providers: ["Pict-Input-AutofillTriggerGroup"],
|
|
698
865
|
AutofillTriggerGroup:
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
866
|
+
{
|
|
867
|
+
TriggerGroupHash: "BookTriggerGroup",
|
|
868
|
+
TriggerAddress: "AppData.CurrentAuthor.Name",
|
|
869
|
+
MarshalEmptyValues: true
|
|
870
|
+
}
|
|
704
871
|
}
|
|
705
872
|
},
|
|
706
873
|
},
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<title>Complex Table.</title>
|
|
5
5
|
<style id="PICT-CSS"></style>
|
|
6
6
|
<script src="./pict.js" type="text/javascript"></script>
|
|
7
|
+
<script src="./chart.umd.js"></script>
|
|
7
8
|
<script type="text/javascript">Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(ComplexTabularApplication, 0)});</script>
|
|
8
9
|
<!-- CSS placed here to simulate an external collection where we can leverage existing class names/patterns -->
|
|
9
10
|
<style type="text/css">
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
},
|
|
10
10
|
"author": "steven",
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"devDependencies": {},
|
|
13
12
|
"copyFilesSettings": {
|
|
14
13
|
"whenFileExists": "overwrite"
|
|
15
14
|
},
|
|
@@ -21,6 +20,13 @@
|
|
|
21
20
|
{
|
|
22
21
|
"from": "../../node_modules/pict/dist/*",
|
|
23
22
|
"to": "./dist/"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"from": "./node_modules/chart.js/dist/chart.umd*",
|
|
26
|
+
"to": "./dist/"
|
|
24
27
|
}
|
|
25
|
-
]
|
|
28
|
+
],
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"chart.js": "^4.5.1"
|
|
31
|
+
}
|
|
26
32
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-form",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.139",
|
|
4
4
|
"description": "Pict dynamic form sections",
|
|
5
5
|
"main": "source/Pict-Section-Form.js",
|
|
6
6
|
"directories": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"browser-env": "^3.3.0",
|
|
32
32
|
"eslint": "^9.38.0",
|
|
33
33
|
"jquery": "^3.7.1",
|
|
34
|
-
"pict": "^1.0.
|
|
34
|
+
"pict": "^1.0.318",
|
|
35
35
|
"pict-application": "^1.0.29",
|
|
36
36
|
"pict-service-commandlineutility": "^1.0.15",
|
|
37
37
|
"quackage": "^1.0.42",
|
|
@@ -16,6 +16,7 @@ const libInputHTML = require('./inputs/Pict-Provider-Input-HTML.js');
|
|
|
16
16
|
const libInputPreciseNumber = require('./inputs/Pict-Provider-Input-PreciseNumber.js');
|
|
17
17
|
const libInputLink = require('./inputs/Pict-Provider-Input-Link.js');
|
|
18
18
|
const libInputTemplatedEntityLookup = require('./inputs/Pict-Provider-Input-TemplatedEntityLookup.js');
|
|
19
|
+
const libInputChart = require('./inputs/Pict-Provider-Input-Chart.js');
|
|
19
20
|
|
|
20
21
|
/** @type {Record<string, any>} */
|
|
21
22
|
const _DefaultProviderConfiguration = (
|
|
@@ -74,7 +75,22 @@ class PictDynamicSolver extends libPictProvider
|
|
|
74
75
|
this.pict.addProviderSingleton('Pict-Input-PreciseNumber', libInputPreciseNumber.default_configuration, libInputPreciseNumber);
|
|
75
76
|
this.pict.addProviderSingleton('Pict-Input-TemplatedEntityLookup', libInputTemplatedEntityLookup.default_configuration, libInputTemplatedEntityLookup);
|
|
76
77
|
this.pict.addProviderSingleton('Pict-Input-Link', libInputLink.default_configuration, libInputLink);
|
|
77
|
-
this.pict.addProviderSingleton('Pict-Input-
|
|
78
|
+
this.pict.addProviderSingleton('Pict-Input-Chart', libInputChart.default_configuration, libInputChart);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
runSolver(pSolverExpression)
|
|
82
|
+
{
|
|
83
|
+
let tmpViewMarshalDestinationObject = this.pict.resolveStateFromAddress(this.pict.views.PictFormMetacontroller.viewMarshalDestination);
|
|
84
|
+
|
|
85
|
+
if ((typeof(tmpViewMarshalDestinationObject) !== 'object') || (tmpViewMarshalDestinationObject === null))
|
|
86
|
+
{
|
|
87
|
+
tmpViewMarshalDestinationObject = this.pict.AppData;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let tmpResultsObject = {};
|
|
91
|
+
let tmpSolutionValue = this.fable.ExpressionParser.solve(pSolverExpression, tmpViewMarshalDestinationObject, tmpResultsObject,this.pict.manifest);
|
|
92
|
+
|
|
93
|
+
return tmpSolutionValue;
|
|
78
94
|
}
|
|
79
95
|
|
|
80
96
|
/**
|
|
@@ -248,6 +248,18 @@ Glug glug glug Oo... -->
|
|
|
248
248
|
<!-- InputType Link {~D:Record.Hash~} {~D:Record.DataType~} -->
|
|
249
249
|
<input type="hidden" {~D:Record.Macro.InputFullProperties~} value="">
|
|
250
250
|
<a id="INPUT-FOR-{~D:Record.Macro.RawHTMLID~}">{~D:Record.Name~}</a>
|
|
251
|
+
`
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"HashPostfix": "-Template-Input-InputType-Chart",
|
|
255
|
+
"DefaultInputExtensions": ["Pict-Input-Chart"],
|
|
256
|
+
"Template": /*HTML*/`
|
|
257
|
+
<!-- InputType Chart {~D:Record.Hash~} {~D:Record.DataType~} -->
|
|
258
|
+
<div style="width:{~DWAF:Record.PictForm.QuantizedWidth:100~}%; display:inline-block;">
|
|
259
|
+
<input type="hidden" id="CONFIG-FOR-{~D:Record.Macro.RawHTMLID~}" value="">
|
|
260
|
+
<h3><span>{~D:Record.Name~}:</span></h3>
|
|
261
|
+
<div style="width:100%;"><canvas id="CANVAS-FOR-{~D:Record.Macro.RawHTMLID~}" {~D:Record.Macro.InputFullProperties~}></canvas></div>
|
|
262
|
+
</div>
|
|
251
263
|
`
|
|
252
264
|
},
|
|
253
265
|
{
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
const libPictSectionInputExtension = require('../Pict-Provider-InputExtension.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CustomInputHandler class.
|
|
5
|
+
*
|
|
6
|
+
* @class
|
|
7
|
+
* @extends libPictSectionInputExtension
|
|
8
|
+
* @memberof providers.inputs
|
|
9
|
+
*/
|
|
10
|
+
class CustomInputHandler extends libPictSectionInputExtension
|
|
11
|
+
{
|
|
12
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
13
|
+
{
|
|
14
|
+
super(pFable, pOptions, pServiceHash);
|
|
15
|
+
|
|
16
|
+
/** @type {import('pict')} */
|
|
17
|
+
this.pict;
|
|
18
|
+
/** @type {import('pict')} */
|
|
19
|
+
this.fable;
|
|
20
|
+
/** @type {any} */
|
|
21
|
+
this.log;
|
|
22
|
+
|
|
23
|
+
this.currentChartObjects = {};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getInputChartConfiguration(pView, pInput, pValue)
|
|
27
|
+
{
|
|
28
|
+
let tmpView = pView;
|
|
29
|
+
let tmpInput = pInput;
|
|
30
|
+
let tmpValue = pValue;
|
|
31
|
+
|
|
32
|
+
if (!('PictForm' in tmpInput))
|
|
33
|
+
{
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let tmpPictform = pInput.PictForm;
|
|
38
|
+
|
|
39
|
+
let tmpChartConfiguration = (typeof(tmpPictform.ChartJSOptionsCorePrototype) === 'object') ? tmpPictform.ChartJSOptionsCorePrototype : {};
|
|
40
|
+
|
|
41
|
+
// Vet the most important two properties for defaults
|
|
42
|
+
if (!('type' in tmpChartConfiguration))
|
|
43
|
+
{
|
|
44
|
+
tmpChartConfiguration.type = (typeof(tmpPictform.ChartType) === 'string') ? tmpPictform.ChartType : 'bar';
|
|
45
|
+
}
|
|
46
|
+
if (!('data' in tmpChartConfiguration))
|
|
47
|
+
{
|
|
48
|
+
tmpChartConfiguration.data = {};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// See if there is a data solution configuration
|
|
52
|
+
|
|
53
|
+
// Start with Raw / defaults for labels and data
|
|
54
|
+
if (!('labels' in tmpChartConfiguration))
|
|
55
|
+
{
|
|
56
|
+
tmpChartConfiguration.data.labels = [];
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(tmpPictform.ChartLabelsRaw))
|
|
59
|
+
{
|
|
60
|
+
tmpChartConfiguration.data.labels = tmpPictform.ChartLabelsRaw;
|
|
61
|
+
}
|
|
62
|
+
// Now do the configuration-based population behaviors
|
|
63
|
+
|
|
64
|
+
if (`ChartLabelsSolver` in tmpPictform)
|
|
65
|
+
{
|
|
66
|
+
let tmpSolvedLabels = this.pict.providers.DynamicSolver.runSolver(tmpPictform.ChartLabelsSolver);
|
|
67
|
+
if (Array.isArray(tmpSolvedLabels))
|
|
68
|
+
{
|
|
69
|
+
// TODO: This may need to get complex for multiple sets of labels?
|
|
70
|
+
tmpChartConfiguration.data.labels = tmpSolvedLabels;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!('datasets' in tmpChartConfiguration))
|
|
75
|
+
{
|
|
76
|
+
tmpChartConfiguration.data.datasets = [];
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(tmpPictform.ChartDatasetsRaw))
|
|
79
|
+
{
|
|
80
|
+
tmpChartConfiguration.data.datasets = tmpChartConfiguration.data.datasets.concat(tmpPictform.ChartDatasetsRaw);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Now see if there are any non-raw datasets to add
|
|
84
|
+
if (`ChartDataSolvers` in tmpPictform)
|
|
85
|
+
{
|
|
86
|
+
for (let i = 0; i < tmpPictform.ChartDataSolvers.length; i++)
|
|
87
|
+
{
|
|
88
|
+
let tmpDatasetSolverConfig = tmpPictform.ChartDataSolvers[i];
|
|
89
|
+
// TODO: Cache and check if it's changed before making it initialize data in the control again
|
|
90
|
+
let tmpDataSetSolved = this.pict.providers.DynamicSolver.runSolver(tmpDatasetSolverConfig.DataSolver);
|
|
91
|
+
if (!'Label' in tmpDatasetSolverConfig)
|
|
92
|
+
{
|
|
93
|
+
tmpDatasetSolverConfig.Label = `Dataset ${i+1}`;
|
|
94
|
+
}
|
|
95
|
+
let tmpNewDataset = {
|
|
96
|
+
label: tmpDatasetSolverConfig.Label,
|
|
97
|
+
data: (Array.isArray(tmpDataSetSolved)) ? tmpDataSetSolved : []
|
|
98
|
+
};
|
|
99
|
+
tmpChartConfiguration.data.datasets.push(tmpNewDataset);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return tmpChartConfiguration;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
initializeChartVisualization(pView, pGroup, pRow, pInput, pValue, pHTMLSelector)
|
|
108
|
+
{
|
|
109
|
+
// Stuff the config into a hidden element for reference
|
|
110
|
+
let tmpConfigStorageLocation = `#CONFIG-FOR-${pInput.Macro.RawHTMLID}`;
|
|
111
|
+
let tmpChartConfiguration = this.getInputChartConfiguration(pView, pInput, pValue);
|
|
112
|
+
this.pict.ContentAssignment.assignContent(tmpConfigStorageLocation, JSON.stringify(tmpChartConfiguration));
|
|
113
|
+
|
|
114
|
+
let tmpChartCanvasElementSelector = `#CANVAS-FOR-${pInput.Macro.RawHTMLID}`;
|
|
115
|
+
let tmpChartCanvasElement = this.pict.ContentAssignment.getElement(tmpChartCanvasElementSelector);
|
|
116
|
+
if ((!Array.isArray(tmpChartCanvasElement)) || (tmpChartCanvasElement.length < 1))
|
|
117
|
+
{
|
|
118
|
+
this.log.warn(`Chart canvas element not found for input ${tmpChartCanvasElementSelector}`);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
tmpChartCanvasElement = tmpChartCanvasElement[0]
|
|
122
|
+
|
|
123
|
+
// Check if there is a window.Chart which is the Chart.js library
|
|
124
|
+
if (typeof(window.Chart) !== 'function')
|
|
125
|
+
{
|
|
126
|
+
this.log.warn(`Chart.js library not loaded for input ${tmpChartCanvasElementSelector}`);
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
{
|
|
130
|
+
this.currentChartObjects[`Object-For-${pInput.Macro.RawHTMLID}`] = new window.Chart(tmpChartCanvasElement, tmpChartConfiguration);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Initializes the input element for the Pict provider select input.
|
|
136
|
+
*
|
|
137
|
+
* @param {Object} pView - The view object.
|
|
138
|
+
* @param {Object} pGroup - The group object.
|
|
139
|
+
* @param {Object} pRow - The row object.
|
|
140
|
+
* @param {Object} pInput - The input object.
|
|
141
|
+
* @param {any} pValue - The input value.
|
|
142
|
+
* @param {string} pHTMLSelector - The HTML selector.
|
|
143
|
+
* @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
|
|
144
|
+
* @returns {boolean} - Returns true if the input element is successfully initialized, false otherwise.
|
|
145
|
+
*/
|
|
146
|
+
onInputInitialize(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID)
|
|
147
|
+
{
|
|
148
|
+
this.initializeChartVisualization(pView, pGroup, pRow, pInput, pValue, pHTMLSelector);
|
|
149
|
+
return super.onInputInitialize(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Initializes a tabular input element.
|
|
154
|
+
*
|
|
155
|
+
* @param {Object} pView - The view object.
|
|
156
|
+
* @param {Object} pGroup - The group object.
|
|
157
|
+
* @param {Object} pInput - The input object.
|
|
158
|
+
* @param {any} pValue - The input value.
|
|
159
|
+
* @param {string} pHTMLSelector - The HTML selector.
|
|
160
|
+
* @param {number} pRowIndex - The index of the row.
|
|
161
|
+
* @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
|
|
162
|
+
* @returns {any} - The result of the initialization.
|
|
163
|
+
*/
|
|
164
|
+
onInputInitializeTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID)
|
|
165
|
+
{
|
|
166
|
+
return super.onInputInitializeTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Handles the change event for the data in the select input.
|
|
171
|
+
*
|
|
172
|
+
* @param {Object} pView - The view object.
|
|
173
|
+
* @param {Object} pInput - The input object.
|
|
174
|
+
* @param {any} pValue - The new value of the input.
|
|
175
|
+
* @param {string} pHTMLSelector - The HTML selector of the input.
|
|
176
|
+
* @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
|
|
177
|
+
* @returns {any} - The result of the super.onDataChange method.
|
|
178
|
+
*/
|
|
179
|
+
onDataChange(pView, pInput, pValue, pHTMLSelector, pTransactionGUID)
|
|
180
|
+
{
|
|
181
|
+
return super.onDataChange(pView, pInput, pValue, pHTMLSelector, pTransactionGUID);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Handles the change event for tabular data.
|
|
186
|
+
*
|
|
187
|
+
* @param {Object} pView - The view object.
|
|
188
|
+
* @param {Object} pInput - The input object.
|
|
189
|
+
* @param {any} pValue - The new value.
|
|
190
|
+
* @param {string} pHTMLSelector - The HTML selector.
|
|
191
|
+
* @param {number} pRowIndex - The index of the row.
|
|
192
|
+
* @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
|
|
193
|
+
* @returns {any} - The result of the super method.
|
|
194
|
+
*/
|
|
195
|
+
onDataChangeTabular(pView, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID)
|
|
196
|
+
{
|
|
197
|
+
return super.onDataChangeTabular(pView, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Marshals data to the form for the given input.
|
|
202
|
+
*
|
|
203
|
+
* @param {Object} pView - The view object.
|
|
204
|
+
* @param {Object} pGroup - The group object.
|
|
205
|
+
* @param {Object} pRow - The row object.
|
|
206
|
+
* @param {Object} pInput - The input object.
|
|
207
|
+
* @param {any} pValue - The value to be marshaled.
|
|
208
|
+
* @param {string} pHTMLSelector - The HTML selector.
|
|
209
|
+
* @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
|
|
210
|
+
* @returns {boolean} - Returns true if the value is successfully marshaled to the form, otherwise false.
|
|
211
|
+
*/
|
|
212
|
+
onDataMarshalToForm(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID)
|
|
213
|
+
{
|
|
214
|
+
return super.onDataMarshalToForm(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Marshals data to a form in tabular format.
|
|
219
|
+
*
|
|
220
|
+
* @param {Object} pView - The view object.
|
|
221
|
+
* @param {Object} pGroup - The group object.
|
|
222
|
+
* @param {Object} pInput - The input object.
|
|
223
|
+
* @param {any} pValue - The value parameter.
|
|
224
|
+
* @param {string} pHTMLSelector - The HTML selector parameter.
|
|
225
|
+
* @param {number} pRowIndex - The row index parameter.
|
|
226
|
+
* @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
|
|
227
|
+
* @returns {any} - The result of the data marshaling.
|
|
228
|
+
*/
|
|
229
|
+
onDataMarshalToFormTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID)
|
|
230
|
+
{
|
|
231
|
+
return super.onDataMarshalToFormTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Handles the data request event for a select input in the PictProviderInputSelect class.
|
|
236
|
+
*
|
|
237
|
+
* @param {Object} pView - The view object.
|
|
238
|
+
* @param {Object} pInput - The input object.
|
|
239
|
+
* @param {any} pValue - The value object.
|
|
240
|
+
* @param {string} pHTMLSelector - The HTML selector object.
|
|
241
|
+
* @returns {any} - The result of the onDataRequest method.
|
|
242
|
+
*/
|
|
243
|
+
onDataRequest(pView, pInput, pValue, pHTMLSelector)
|
|
244
|
+
{
|
|
245
|
+
return super.onDataRequest(pView, pInput, pValue, pHTMLSelector);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Handles the data request event for a tabular input.
|
|
250
|
+
*
|
|
251
|
+
* @param {Object} pView - The view object.
|
|
252
|
+
* @param {Object} pInput - The input object.
|
|
253
|
+
* @param {any} pValue - The value object.
|
|
254
|
+
* @param {string} pHTMLSelector - The HTML selector.
|
|
255
|
+
* @param {number} pRowIndex - The row index.
|
|
256
|
+
* @returns {any} - The result of the data request.
|
|
257
|
+
*/
|
|
258
|
+
onDataRequestTabular(pView, pInput, pValue, pHTMLSelector, pRowIndex)
|
|
259
|
+
{
|
|
260
|
+
return super.onDataRequestTabular(pView, pInput, pValue, pHTMLSelector, pRowIndex);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
module.exports = CustomInputHandler;
|
|
@@ -37,7 +37,9 @@ class RecordLayout extends libPictSectionGroupLayout
|
|
|
37
37
|
tmpTemplate += tmpMetatemplateGenerator.getMetatemplateTemplateReference(pView, `-Template-Group-Prefix`, `getGroup("${pGroup.GroupIndex}")`);
|
|
38
38
|
for (let j = 0; j < pGroup.Rows.length; j++)
|
|
39
39
|
{
|
|
40
|
-
|
|
40
|
+
// TODO: Validate that the row exists? Bootstrap seems to have it here.
|
|
41
|
+
let tmpRow = pGroup.Rows[j]
|
|
42
|
+
tmpRow.WidthTotalRaw = 0;
|
|
41
43
|
|
|
42
44
|
tmpTemplate += tmpMetatemplateGenerator.getMetatemplateTemplateReference(pView, `-Template-Row-Prefix`, `getGroup("${pGroup.GroupIndex}")`);
|
|
43
45
|
|
|
@@ -48,9 +50,56 @@ class RecordLayout extends libPictSectionGroupLayout
|
|
|
48
50
|
tmpInput.PictForm.InputIndex = k;
|
|
49
51
|
tmpInput.PictForm.GroupIndex = pGroup.GroupIndex;
|
|
50
52
|
tmpInput.PictForm.RowIndex = j;
|
|
53
|
+
let tmpInputWidth = 1;
|
|
54
|
+
try
|
|
55
|
+
{
|
|
56
|
+
tmpInputWidth = Math.abs(parseFloat(tmpInput.PictForm.Width));
|
|
57
|
+
}
|
|
58
|
+
catch (pParseError)
|
|
59
|
+
{
|
|
60
|
+
tmpInputWidth = 1;
|
|
61
|
+
}
|
|
62
|
+
if (!tmpInputWidth || isNaN(tmpInputWidth) || tmpInputWidth <= 0)
|
|
63
|
+
{
|
|
64
|
+
tmpInputWidth = 1;
|
|
65
|
+
}
|
|
66
|
+
tmpInput.PictForm.RawWidth = tmpInputWidth;
|
|
67
|
+
tmpRow.WidthTotalRaw += tmpInputWidth;
|
|
68
|
+
|
|
69
|
+
//tmpTemplate += tmpMetatemplateGenerator.getInputMetatemplateTemplateReference(pView, tmpInput.DataType, tmpInput.PictForm.InputType, `getInput("${pGroup.GroupIndex}","${j}","${k}")`);
|
|
70
|
+
}
|
|
71
|
+
// Now that we've gotten all the raw widths for the row, quantize them properly.
|
|
72
|
+
// Default by quantizing to 99 percentage units wide
|
|
73
|
+
let tmpGroupQuantizedWidth = 95;
|
|
74
|
+
if ('WidthQuantization' in pGroup)
|
|
75
|
+
{
|
|
76
|
+
try
|
|
77
|
+
{
|
|
78
|
+
tmpGroupQuantizedWidth = Math.abs(parseInt(pGroup.WidthQuantization));
|
|
79
|
+
if (!tmpGroupQuantizedWidth || isNaN(tmpGroupQuantizedWidth) || tmpGroupQuantizedWidth <= 0)
|
|
80
|
+
{
|
|
81
|
+
tmpGroupQuantizedWidth = 95;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch(pParseError)
|
|
85
|
+
{
|
|
86
|
+
// TODO: UGH THIS IS NaN at the moment.......
|
|
87
|
+
tmpGroupQuantizedWidth = 95;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if ('WidthQuantization' in this.pict.PictApplication.options)
|
|
91
|
+
{
|
|
92
|
+
tmpGroupQuantizedWidth = this.pict.PictApplication.options.WidthQuantization;
|
|
93
|
+
}
|
|
94
|
+
for (let k = 0; k < tmpRow.Inputs.length; k++)
|
|
95
|
+
{
|
|
96
|
+
let tmpInput = tmpRow.Inputs[k];
|
|
97
|
+
tmpInput.PictForm.QuantizedWidth = Math.round((tmpInput.PictForm.RawWidth / tmpRow.WidthTotalRaw) * tmpGroupQuantizedWidth);
|
|
98
|
+
//this.fable.log.trace(`Quantized input width for Group ${pGroup.GroupIndex} Row ${j} Input ${k} (${tmpInput.Name}) to ${tmpInput.PictForm.QuantizedWidth} (Raw: ${tmpInput.PictForm.RawWidth} / Total Raw: ${tmpRow.WidthTotalRaw} / Group Quantization: ${tmpGroupQuantizedWidth})`);
|
|
51
99
|
|
|
52
100
|
tmpTemplate += tmpMetatemplateGenerator.getInputMetatemplateTemplateReference(pView, tmpInput.DataType, tmpInput.PictForm.InputType, `getInput("${pGroup.GroupIndex}","${j}","${k}")`);
|
|
53
101
|
}
|
|
102
|
+
|
|
54
103
|
tmpTemplate += tmpMetatemplateGenerator.getMetatemplateTemplateReference(pView, `-Template-Row-Postfix`, `getGroup("${pGroup.GroupIndex}")`);
|
|
55
104
|
}
|
|
56
105
|
tmpTemplate += tmpMetatemplateGenerator.getMetatemplateTemplateReference(pView, `-Template-Group-Postfix`, `getGroup("${pGroup.GroupIndex}")`);
|
|
@@ -903,7 +903,7 @@ class PictFormMetacontroller extends libPictViewClass
|
|
|
903
903
|
{
|
|
904
904
|
let tmpDescriptor = tmpManifest.elementDescriptors[tmpDescriptorKeys[i]];
|
|
905
905
|
|
|
906
|
-
if (tmpDescriptor
|
|
906
|
+
if (tmpDescriptor)
|
|
907
907
|
{
|
|
908
908
|
this.pict.manifest.addDescriptor(tmpDescriptorKeys[i], tmpDescriptor);
|
|
909
909
|
}
|