vaporous 0.0.11 → 0.0.12
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/Vaporous.js +2 -2
- package/package.json +1 -1
- package/src/http.js +50 -45
- package/src/processing.js +7 -4
- package/src/statistics.js +3 -1
- package/src/transformations.js +12 -11
- package/src/visualization.js +4 -2
- package/Vaporous_generation.html +0 -324
- package/gym.html +0 -328
- package/sensors.html +0 -325
package/Vaporous.js
CHANGED
|
@@ -238,8 +238,8 @@ class Vaporous {
|
|
|
238
238
|
* @param {string} target - Field name containing array to expand
|
|
239
239
|
* @returns {Vaporous} - Returns this instance for chaining
|
|
240
240
|
*/
|
|
241
|
-
mvexpand(
|
|
242
|
-
return transformations.mvexpand.call(this,
|
|
241
|
+
mvexpand(...targets) {
|
|
242
|
+
return transformations.mvexpand.call(this, targets);
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// ========================================
|
package/package.json
CHANGED
package/src/http.js
CHANGED
|
@@ -3,59 +3,64 @@ const httpsLib = require('https')
|
|
|
3
3
|
const { HttpProxyAgent } = require('http-proxy-agent')
|
|
4
4
|
const { HttpsProxyAgent } = require('https-proxy-agent')
|
|
5
5
|
|
|
6
|
+
const request = async ({ uri, method, headers, body, options = {} }) => {
|
|
7
|
+
const response = await new Promise((resolve, reject) => {
|
|
8
|
+
const isHTTPs = uri.startsWith('https')
|
|
9
|
+
const lib = isHTTPs ? httpsLib : httpLib
|
|
10
|
+
const { hostname, port, pathname, search } = new URL(uri)
|
|
11
|
+
const path = pathname + (search || '')
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
const options = {
|
|
14
|
+
method,
|
|
15
|
+
hostname,
|
|
16
|
+
port,
|
|
17
|
+
path,
|
|
18
|
+
headers
|
|
19
|
+
}
|
|
8
20
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
method: _http_req_method,
|
|
23
|
-
hostname,
|
|
24
|
-
port,
|
|
25
|
-
path,
|
|
26
|
-
headers: _http_req_headers
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const proxy = process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy
|
|
30
|
-
|
|
31
|
-
if (proxy) {
|
|
32
|
-
const isHttps = _http_req_uri.startsWith('https')
|
|
33
|
-
options.agent = isHttps ? new HttpsProxyAgent(proxy) : new HttpProxyAgent(proxy)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const req = lib.request(options, res => {
|
|
37
|
-
let body = '';
|
|
38
|
-
|
|
39
|
-
res.on('data', data => {
|
|
40
|
-
body += data
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
res.on('end', () => {
|
|
44
|
-
event._http_res_body = body
|
|
45
|
-
event._http_res_status = res.statusCode
|
|
46
|
-
event._http_res_headers = res.headers
|
|
47
|
-
resolve(body)
|
|
48
|
-
})
|
|
21
|
+
const proxy = isHTTPs ? (process.env.https_proxy || process.env.HTTPS_PROXY) : (process.env.http_proxy || process.env.HTTP_PROXY)
|
|
22
|
+
|
|
23
|
+
if (proxy) options.agent = isHTTPs ? new HttpsProxyAgent(proxy) : new HttpProxyAgent(proxy)
|
|
24
|
+
|
|
25
|
+
const req = lib.request(options, res => {
|
|
26
|
+
let body = '';
|
|
27
|
+
|
|
28
|
+
res.on('data', data => {
|
|
29
|
+
body += data
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
res.on('end', () => {
|
|
33
|
+
resolve({ body, statusCode: res.statusCode, headers: res.headers })
|
|
49
34
|
})
|
|
35
|
+
})
|
|
50
36
|
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
if (body) req.write(body)
|
|
38
|
+
req.end()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (response.statusCode === 307) {
|
|
42
|
+
return request({ uri: response.headers.location, method, headers, body, options })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return response;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function load_http() {
|
|
49
|
+
|
|
50
|
+
for (let event of this.events) {
|
|
51
|
+
const res = await request({
|
|
52
|
+
uri: event._http_req_uri,
|
|
53
|
+
method: event._http_req_method,
|
|
54
|
+
headers: event._http_req_headers,
|
|
55
|
+
body: event._http_req_body
|
|
53
56
|
})
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
event._http_res_status = res.statusCode
|
|
59
|
+
event._http_res_headers = res.headers
|
|
60
|
+
event._http_res_body = res.body
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
return this
|
|
63
|
+
return this
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
module.exports = {
|
package/src/processing.js
CHANGED
|
@@ -31,8 +31,9 @@ async function parallel(target, { multiThread = false } = {}, callbackPath) {
|
|
|
31
31
|
const instance = new Vaporous({ loggers })
|
|
32
32
|
instance.events = thisEvent
|
|
33
33
|
|
|
34
|
-
const task =
|
|
35
|
-
tasks.push(task
|
|
34
|
+
const task = funct(instance).begin()
|
|
35
|
+
tasks.push(task)
|
|
36
|
+
await task
|
|
36
37
|
|
|
37
38
|
await processSingleThread()
|
|
38
39
|
}
|
|
@@ -135,9 +136,11 @@ async function recurse(funct) {
|
|
|
135
136
|
for (let event of this.events) {
|
|
136
137
|
const target = new Vaporous({ loggers: this.loggers })
|
|
137
138
|
target.events = [event]
|
|
139
|
+
event._recursion = true
|
|
138
140
|
|
|
139
141
|
const localRecursion = async (target) => {
|
|
140
|
-
const
|
|
142
|
+
const executionChain = funct(target)
|
|
143
|
+
const val = await executionChain.begin()
|
|
141
144
|
if (val.events[0]._recursion) return localRecursion(target)
|
|
142
145
|
return val
|
|
143
146
|
}
|
|
@@ -155,7 +158,7 @@ async function doIf(condition, callback) {
|
|
|
155
158
|
if (proceed) {
|
|
156
159
|
const clone = this.clone()
|
|
157
160
|
const task = await callback(clone)
|
|
158
|
-
task.begin()
|
|
161
|
+
await task.begin()
|
|
159
162
|
this.events = clone.events
|
|
160
163
|
}
|
|
161
164
|
return this;
|
package/src/statistics.js
CHANGED
|
@@ -41,7 +41,9 @@ module.exports = {
|
|
|
41
41
|
const reference = map[key]._statsRaw[aggregation.field]
|
|
42
42
|
|
|
43
43
|
if (aggregation.sortable) {
|
|
44
|
-
sortedCache[aggregation.field]
|
|
44
|
+
if (sortedCache[aggregation.field] === undefined) {
|
|
45
|
+
sortedCache[aggregation.field] = reference.slice().sort((a, b) => a - b)
|
|
46
|
+
}
|
|
45
47
|
result[outputField] = aggregation.calculate(sortedCache[aggregation.field])
|
|
46
48
|
} else {
|
|
47
49
|
result[outputField] = aggregation.calculate(reference)
|
package/src/transformations.js
CHANGED
|
@@ -60,27 +60,28 @@ module.exports = {
|
|
|
60
60
|
return this;
|
|
61
61
|
},
|
|
62
62
|
|
|
63
|
-
mvexpand(
|
|
63
|
+
mvexpand(targets) {
|
|
64
64
|
|
|
65
65
|
const arr = []
|
|
66
66
|
this.events.forEach(event => {
|
|
67
67
|
if (event instanceof Array) {
|
|
68
|
-
if (
|
|
68
|
+
if (targets.length !== 0) throw new Error('Cannot mvexpand on a target value when source data is array')
|
|
69
|
+
|
|
69
70
|
event.forEach((item, i) => {
|
|
70
|
-
item.
|
|
71
|
+
item._mvExpand = i
|
|
71
72
|
arr.push(item)
|
|
72
73
|
})
|
|
73
74
|
} else {
|
|
75
|
+
// Identify max iterations
|
|
76
|
+
const max = targets.reduce((prev, curr) => Math.max(prev, event[curr].length), 0)
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
...event,
|
|
80
|
-
[target]: item,
|
|
81
|
-
[`_mvExpand_${target}`]: i
|
|
78
|
+
for (let i = 0; i < max; i++) {
|
|
79
|
+
const obj = { ...event, _mvExpand: i }
|
|
80
|
+
targets.forEach(target => {
|
|
81
|
+
obj[target] = event[target][i]
|
|
82
82
|
})
|
|
83
|
-
|
|
83
|
+
arr.push(obj)
|
|
84
|
+
}
|
|
84
85
|
}
|
|
85
86
|
})
|
|
86
87
|
|
package/src/visualization.js
CHANGED
|
@@ -372,12 +372,14 @@ module.exports = {
|
|
|
372
372
|
return this;
|
|
373
373
|
},
|
|
374
374
|
|
|
375
|
-
render(location = './Vaporous_generation.html',
|
|
375
|
+
render(location = './Vaporous_generation.html', options = {}) {
|
|
376
376
|
|
|
377
377
|
|
|
378
378
|
const classSafe = (name) => name.replace(/[^a-zA-Z0-9]/g, "_")
|
|
379
379
|
|
|
380
|
-
if (
|
|
380
|
+
if (typeof options === 'function') options = options()
|
|
381
|
+
|
|
382
|
+
if (options.tabOrder) this.tabs = options.tabOrder
|
|
381
383
|
|
|
382
384
|
const createElement = (name, type, visualisationOptions, eventData, { trellis, trellisName = "", columnDefinitions }) => {
|
|
383
385
|
|
package/Vaporous_generation.html
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta name="viewport" content="width=device-width, initial-scale=0.5">
|
|
5
|
-
<style>
|
|
6
|
-
@import url('https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap');
|
|
7
|
-
|
|
8
|
-
/* Apply Roboto to all elements */
|
|
9
|
-
* {
|
|
10
|
-
font-family: 'Roboto', Arial, sans-serif !important;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
body {
|
|
14
|
-
font-family: 'Roboto', Arial, sans-serif;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/* Chart-specific styles */
|
|
18
|
-
.chart,
|
|
19
|
-
.chart-container,
|
|
20
|
-
canvas,
|
|
21
|
-
svg,
|
|
22
|
-
.chartjs-render-monitor {
|
|
23
|
-
font-family: 'Roboto', Arial, sans-serif !important;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* Third-party library overrides */
|
|
27
|
-
.ag-theme-quartz,
|
|
28
|
-
.ag-cell,
|
|
29
|
-
.ag-header-cell,
|
|
30
|
-
.tabulator,
|
|
31
|
-
.tabulator-cell,
|
|
32
|
-
.tabulator-header {
|
|
33
|
-
font-family: 'Roboto', Arial, sans-serif !important;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
body {
|
|
37
|
-
margin: 0;
|
|
38
|
-
padding: 16px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.tabBar {
|
|
42
|
-
display: flex;
|
|
43
|
-
overflow: auto;
|
|
44
|
-
box-shadow:
|
|
45
|
-
0 3px 12px rgba(0, 0, 0, 0.09),
|
|
46
|
-
0 6px 18px rgba(0, 0, 0, 0.06);
|
|
47
|
-
min-height: 32px;
|
|
48
|
-
margin-bottom: 24px;
|
|
49
|
-
margin-top: 8px;
|
|
50
|
-
margin-left: 8px;
|
|
51
|
-
margin-right: 8px;
|
|
52
|
-
position: relative;
|
|
53
|
-
background: #fff;
|
|
54
|
-
align-items: center;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.tabs {
|
|
58
|
-
border-radius: 8px;
|
|
59
|
-
padding: 8px 20px;
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
background: none;
|
|
62
|
-
border: none;
|
|
63
|
-
outline: none;
|
|
64
|
-
font-size: 1rem;
|
|
65
|
-
color: #555;
|
|
66
|
-
transition: all 0.3s ease-in-out;
|
|
67
|
-
text-align: center;
|
|
68
|
-
margin: 12px;
|
|
69
|
-
position: relative;
|
|
70
|
-
z-index: 1;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.tabs:not(.selectedTab):hover {
|
|
74
|
-
color: #1976d2;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.selectedTab {
|
|
78
|
-
color: #fff;
|
|
79
|
-
font-weight: bold;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.selectedTab::before {
|
|
83
|
-
content: '';
|
|
84
|
-
position: absolute;
|
|
85
|
-
background: #1976d2;
|
|
86
|
-
border-radius: 8px;
|
|
87
|
-
z-index: -1;
|
|
88
|
-
top: 0;
|
|
89
|
-
left: 0;
|
|
90
|
-
width: 100%;
|
|
91
|
-
height: 100%;
|
|
92
|
-
transition: transform 0.3s ease-in-out;
|
|
93
|
-
box-shadow:
|
|
94
|
-
0 4px 16px rgba(25, 118, 210, 0.3),
|
|
95
|
-
0 8px 24px rgba(25, 118, 210, 0.2);
|
|
96
|
-
animation: slideInFromLeft 0.3s ease-in-out forwards;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.selectedTab.slideFromRight::before {
|
|
100
|
-
animation: slideInFromRight 0.3s ease-in-out forwards;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
@keyframes slideInFromLeft {
|
|
104
|
-
0% {
|
|
105
|
-
transform: translateX(-100%);
|
|
106
|
-
opacity: 0;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
100% {
|
|
110
|
-
transform: translateX(0);
|
|
111
|
-
opacity: 1;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
@keyframes slideInFromRight {
|
|
116
|
-
0% {
|
|
117
|
-
transform: translateX(100%);
|
|
118
|
-
opacity: 0;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
100% {
|
|
122
|
-
transform: translateX(0);
|
|
123
|
-
opacity: 1;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
#content {
|
|
128
|
-
display: flex;
|
|
129
|
-
flex-wrap: wrap;
|
|
130
|
-
padding: 0px;
|
|
131
|
-
gap: 8px;
|
|
132
|
-
justify-content: flex-start;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.parentHolder {
|
|
136
|
-
display: flex;
|
|
137
|
-
margin: 2px;
|
|
138
|
-
border: 1px solid #d3d3d3;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.parentHolder::after {
|
|
142
|
-
border: 2px solid red;
|
|
143
|
-
/* Change color and width as needed */
|
|
144
|
-
pointer-events: none;
|
|
145
|
-
z-index: 2;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
.tabContent {
|
|
149
|
-
opacity: 1;
|
|
150
|
-
transition: opacity 0.3s,
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.graphTitle {
|
|
154
|
-
opacity: 0.7;
|
|
155
|
-
text-align: center;
|
|
156
|
-
display: 'flex';
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.tableHolder {
|
|
160
|
-
margin-top: 8px;
|
|
161
|
-
width: 100%;
|
|
162
|
-
/* height: 600px; */
|
|
163
|
-
/* overflow: auto; */
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
#extendedDescription {
|
|
167
|
-
text-align: center;
|
|
168
|
-
opacity: 0.7;
|
|
169
|
-
margin-bottom: 16px;
|
|
170
|
-
}
|
|
171
|
-
</style>
|
|
172
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
173
|
-
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community@34.2.0/dist/ag-grid-community.min.js"></script>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
<script type="text/javascript">
|
|
177
|
-
|
|
178
|
-
const classSafe = (name) => name.replace(/[^a-zA-Z0-9]/g, "_")
|
|
179
|
-
|
|
180
|
-
var selectedTab = classSafe("User Stats")
|
|
181
|
-
var previousTab = null
|
|
182
|
-
const tokens = {}
|
|
183
|
-
const visualisationData = [[{"columnDefinitions":[{"field":"gender"},{"field":"avgHeight"}],"rowData":[{"gender":"female","avgHeight":177.5666666666667},{"gender":"male","avgHeight":173.15249999999997}],"title":"Average height"}],[{"type":"line","data":{"labels":["female","male"],"datasets":[{"label":"avgHeight","data":[177.5666666666667,173.15249999999997],"pointRadius":0}]},"options":{"scales":{"y":{"type":"linear","display":true,"position":"left","min":173.15249999999997,"max":[177.5666666666667]},"x":{"type":"category","ticks":{"display":false}}},"responsive":true,"plugins":{"legend":{"display":true,"position":"bottom"},"title":{"display":false,"text":"Average height"}}}}]]
|
|
184
|
-
const tabOrder = ["User_Stats"]
|
|
185
|
-
|
|
186
|
-
const _sort = (order, data, ...keys) => {
|
|
187
|
-
return data.sort((a, b) => {
|
|
188
|
-
let directive = 0;
|
|
189
|
-
|
|
190
|
-
keys.some(key => {
|
|
191
|
-
directive = typeof a[key] === 'number' ? a[key] - b[key] : a[key].localeCompare(b[key])
|
|
192
|
-
if (order === 'dsc') directive = directive * -1
|
|
193
|
-
if (directive !== 0) return true;
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
return directive;
|
|
197
|
-
})
|
|
198
|
-
}
|
|
199
|
-
const createElement = (name, type, visualisationOptions, eventData, { trellis, trellisName = "", columnDefinitions }) => {
|
|
200
|
-
|
|
201
|
-
if (classSafe(visualisationOptions.tab) !== selectedTab) return;
|
|
202
|
-
|
|
203
|
-
if (visualisationOptions.extendedDescription) {
|
|
204
|
-
const descriptions = document.getElementById('extendedDescription')
|
|
205
|
-
const thisDescription = document.createElement('div')
|
|
206
|
-
thisDescription.innerHTML = visualisationOptions.extendedDescription
|
|
207
|
-
descriptions.appendChild(thisDescription)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
eventData = visualisationData[eventData]
|
|
211
|
-
|
|
212
|
-
// TODO: migrate trellis functionality from here to tograph
|
|
213
|
-
if (trellis) {
|
|
214
|
-
let pairs = trellisName.map((name, i) => [name, eventData[i]]);
|
|
215
|
-
pairs = pairs.sort((a, b) => a[0].localeCompare(b[0]))
|
|
216
|
-
|
|
217
|
-
// Unzip back into separate arrays
|
|
218
|
-
trellisName = pairs.map(p => p[0]);
|
|
219
|
-
eventData = pairs.map(p => p[1]);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const columnCount = visualisationOptions.columns || 2
|
|
223
|
-
|
|
224
|
-
eventData.forEach((trellisData, i) => {
|
|
225
|
-
const parentHolder = document.createElement('div')
|
|
226
|
-
|
|
227
|
-
const titleDiv = document.createElement('div')
|
|
228
|
-
titleDiv.classList.add('graphTitle')
|
|
229
|
-
parentHolder.appendChild(titleDiv)
|
|
230
|
-
|
|
231
|
-
if (trellisData.options) {
|
|
232
|
-
titleDiv.textContent = trellisData.options.plugins.title.text
|
|
233
|
-
} else {
|
|
234
|
-
titleDiv.textContent = trellisData.title
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
document.getElementById('content').appendChild(parentHolder)
|
|
238
|
-
|
|
239
|
-
parentHolder.style = `flex: 0 0 calc(${100 / columnCount}% - 8px); max-width: calc(${100 / columnCount}% - 8px);`
|
|
240
|
-
if (type === 'Table') {
|
|
241
|
-
const tableDiv = document.createElement('div')
|
|
242
|
-
tableDiv.classList.add('tableHolder')
|
|
243
|
-
document.documentElement.style.setProperty("--ag-spacing", `4px`);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Need to do column defintiions here
|
|
247
|
-
parentHolder.appendChild(tableDiv)
|
|
248
|
-
new agGrid.createGrid(tableDiv, {
|
|
249
|
-
suppressFieldDotNotation: true,
|
|
250
|
-
rowData: trellisData.rowData,
|
|
251
|
-
// Columns to be displayed (Should match rowData properties)
|
|
252
|
-
columnDefs: trellisData.columnDefinitions,
|
|
253
|
-
defaultColDef: {
|
|
254
|
-
flex: 1,
|
|
255
|
-
resizable: true,
|
|
256
|
-
sortable: true,
|
|
257
|
-
filter: true
|
|
258
|
-
},
|
|
259
|
-
domLayout: 'autoHeight',
|
|
260
|
-
enableCellTextSelection: true,
|
|
261
|
-
// suppressHorizontalScroll: false,
|
|
262
|
-
// autoSizeStrategy: {
|
|
263
|
-
// type: 'fitGridWidth',
|
|
264
|
-
// defaultMinWidth: 100
|
|
265
|
-
// }
|
|
266
|
-
});
|
|
267
|
-
} else {
|
|
268
|
-
const graphEntity = document.createElement('canvas')
|
|
269
|
-
parentHolder.appendChild(graphEntity)
|
|
270
|
-
new Chart(graphEntity, trellisData)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
})
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function drawVis(tab) {
|
|
277
|
-
if (tab) {
|
|
278
|
-
if (selectedTab) {
|
|
279
|
-
document.getElementById(selectedTab).classList.remove('selectedTab')
|
|
280
|
-
document.getElementById(selectedTab).classList.remove('slideFromRight')
|
|
281
|
-
previousTab = selectedTab
|
|
282
|
-
}
|
|
283
|
-
selectedTab = tab
|
|
284
|
-
} else if (true) {
|
|
285
|
-
selectedTab = classSafe('User Stats')
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (selectedTab) {
|
|
289
|
-
const selectedElement = document.getElementById(selectedTab)
|
|
290
|
-
selectedElement.classList.add('selectedTab')
|
|
291
|
-
|
|
292
|
-
// Determine slide direction based on tab positions
|
|
293
|
-
if (previousTab) {
|
|
294
|
-
const previousIndex = tabOrder.indexOf(previousTab)
|
|
295
|
-
const currentIndex = tabOrder.indexOf(selectedTab)
|
|
296
|
-
|
|
297
|
-
if (currentIndex < previousIndex) {
|
|
298
|
-
// Moving to left tab, slide from right
|
|
299
|
-
selectedElement.classList.add('slideFromRight')
|
|
300
|
-
}
|
|
301
|
-
// For right movement or first load, use default slideFromLeft animation
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
document.getElementById('content').innerHTML = ''
|
|
305
|
-
document.getElementById('extendedDescription').innerHTML = ''
|
|
306
|
-
createElement('Average height', 'Table', {"tab":"User Stats","columns":2} ,0, {"xPrimary":"gender","columnDefinitions":[["gender","avgHeight"]]}),createElement('Average height', 'Line', {"tab":"User Stats","columns":2} ,1, {"xPrimary":"gender","columnDefinitions":[["gender","avgHeight"]]})
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
document.addEventListener("DOMContentLoaded", function(event) {
|
|
310
|
-
drawVis()
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
</script>
|
|
314
|
-
</head>
|
|
315
|
-
<body>
|
|
316
|
-
<div class='tabBar'>
|
|
317
|
-
<div id=User_Stats class='tabs' onclick="drawVis('User_Stats')">User Stats</div>
|
|
318
|
-
</div>
|
|
319
|
-
|
|
320
|
-
<div id='extendedDescription'></div>
|
|
321
|
-
<div id='content'></div>
|
|
322
|
-
</body>
|
|
323
|
-
</html>
|
|
324
|
-
|