ons_openapi 0.1.0
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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +218 -0
- data/lib/ons_openapi/classification.rb +10 -0
- data/lib/ons_openapi/collection.rb +151 -0
- data/lib/ons_openapi/concept.rb +6 -0
- data/lib/ons_openapi/connection.rb +65 -0
- data/lib/ons_openapi/context.rb +106 -0
- data/lib/ons_openapi/data_helper.rb +5 -0
- data/lib/ons_openapi/dimension.rb +46 -0
- data/lib/ons_openapi/geographical_hierarchy.rb +6 -0
- data/lib/ons_openapi/item.rb +13 -0
- data/lib/ons_openapi/name_helper.rb +7 -0
- data/lib/ons_openapi/url_helper.rb +12 -0
- data/lib/ons_openapi/value.rb +17 -0
- data/lib/ons_openapi.rb +65 -0
- data/vendor/json-stat.max.js +697 -0
- metadata +120 -0
@@ -0,0 +1,697 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
JSON-stat Javascript Toolkit v. 0.6.2 - with "window" code commented out
|
4
|
+
http://json-stat.org
|
5
|
+
https://github.com/badosa/JSON-stat
|
6
|
+
|
7
|
+
Copyright 2014 Xavier Badosa (http://xavierbadosa.com)
|
8
|
+
|
9
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
you may not use this file except in compliance with the License.
|
11
|
+
You may obtain a copy of the License at
|
12
|
+
|
13
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
|
15
|
+
Unless required by applicable law or agreed to in writing, software
|
16
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
18
|
+
or implied. See the License for the specific language governing
|
19
|
+
permissions and limitations under the License.
|
20
|
+
|
21
|
+
*/
|
22
|
+
|
23
|
+
var JSONstat = JSONstat || {};
|
24
|
+
|
25
|
+
JSONstat.version="0.6.2";
|
26
|
+
|
27
|
+
function JSONstat(resp,f){
|
28
|
+
// if(window===this){
|
29
|
+
return new JSONstat.jsonstat(resp,f);
|
30
|
+
// }
|
31
|
+
}
|
32
|
+
|
33
|
+
(function(){
|
34
|
+
"use strict";
|
35
|
+
function isArray(o) {
|
36
|
+
return Object.prototype.toString.call(o) === "[object Array]";
|
37
|
+
}
|
38
|
+
|
39
|
+
function jsonstat(o,f){
|
40
|
+
var xhr=function(uri, func){
|
41
|
+
var json, async=(func!==false);
|
42
|
+
// if(window.XDomainRequest && /^(http(s)?:)?\/\//.test(uri)){ //IE9 cross-domain (assuming access to same domain won't be specified using an absolute address). Not integrated because it'll will be removed someday...
|
43
|
+
// if(!async){ //JSONstat: IE9 sync cross-domain request? Sorry, not supported (only async if IE9 and cross-domain).
|
44
|
+
// return;
|
45
|
+
// }
|
46
|
+
// var req=new XDomainRequest();
|
47
|
+
// /*
|
48
|
+
// req.onerror=function(){
|
49
|
+
// return; //JSONstat: Can't access "+uri;
|
50
|
+
// }
|
51
|
+
// */
|
52
|
+
// req.onload=function(){
|
53
|
+
// json=JSON.parse(req.responseText);
|
54
|
+
// func.call(JSONstat(json));
|
55
|
+
// }
|
56
|
+
// req.open("GET", uri);
|
57
|
+
// req.send();
|
58
|
+
// } else { //Standard xhr
|
59
|
+
var req=new XMLHttpRequest();
|
60
|
+
req.onreadystatechange=function(){
|
61
|
+
if(req.readyState===4){
|
62
|
+
var s=req.status;
|
63
|
+
json=(s && req.responseText && (s>=200 && s<300 || s===304)) ? JSON.parse(req.responseText) : null;
|
64
|
+
if(async){
|
65
|
+
func.call(JSONstat(json));
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
req.open("GET",uri,async);
|
70
|
+
req.send(null);
|
71
|
+
if(!async){
|
72
|
+
return json;
|
73
|
+
}
|
74
|
+
// }
|
75
|
+
}
|
76
|
+
//sparse cube (value or status)
|
77
|
+
//If only one value/status is provided it means same for all (if more than one, then missing values/statuses are nulled).
|
78
|
+
function normalize(s,len){
|
79
|
+
var ret=[];
|
80
|
+
|
81
|
+
if(typeof s==="string"){
|
82
|
+
s=[s];
|
83
|
+
}
|
84
|
+
if(isArray(s)){
|
85
|
+
if(s.length===len){ //normal case
|
86
|
+
return s;
|
87
|
+
}
|
88
|
+
if(s.length===1){ //all obs same status
|
89
|
+
for(var l=0; l<len; l++){
|
90
|
+
ret.push(s[0]);
|
91
|
+
}
|
92
|
+
return ret;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
//It's an object (sparse cube) or an incomplete array that must be filled with nulls
|
97
|
+
for(var l=0; l<len; l++){
|
98
|
+
var e=(typeof s[l]==="undefined") ? null: s[l];
|
99
|
+
ret.push(e);
|
100
|
+
}
|
101
|
+
return ret;
|
102
|
+
}
|
103
|
+
|
104
|
+
this.length=0;
|
105
|
+
this.id=[];
|
106
|
+
if (o===null || typeof o==="undefined"){
|
107
|
+
return;
|
108
|
+
}
|
109
|
+
var type=o.type || "root";
|
110
|
+
switch(type){
|
111
|
+
case "root" :
|
112
|
+
this.type="root";
|
113
|
+
var i=[], ds=0;
|
114
|
+
|
115
|
+
//URI assumed
|
116
|
+
if (typeof o==="string" && o.length>0){
|
117
|
+
o=xhr(o, typeof f==="function"? f : false);//If second argument is function then async
|
118
|
+
}
|
119
|
+
|
120
|
+
// Wrong input object or wrong URI o connection problem
|
121
|
+
if(o===null || typeof o!=="object"){
|
122
|
+
return;
|
123
|
+
}
|
124
|
+
|
125
|
+
for (var prop in o){
|
126
|
+
ds++;
|
127
|
+
/* If sparse cube, we can't rely on value to check size
|
128
|
+
if (isArray(o[prop].value)){
|
129
|
+
a++;
|
130
|
+
}
|
131
|
+
*/
|
132
|
+
i.push(prop);
|
133
|
+
}
|
134
|
+
this.__tree__=o;
|
135
|
+
this.length=ds;
|
136
|
+
this.id=i;
|
137
|
+
break;
|
138
|
+
case "ds" :
|
139
|
+
this.type="ds";
|
140
|
+
if (!o.hasOwnProperty("__tree__")){
|
141
|
+
return;
|
142
|
+
}
|
143
|
+
var ot=o.__tree__;
|
144
|
+
this.__tree__=ot;
|
145
|
+
this.label=ot.label || null;
|
146
|
+
this.updated=ot.updated || null;
|
147
|
+
this.source=ot.source || null; //v.0.5.0
|
148
|
+
|
149
|
+
//Sparse cube (If toTable() removed, this logic can be moved inside Data()
|
150
|
+
//which is more efficient when retrieving a single value/status.
|
151
|
+
var dsize=0; //data size
|
152
|
+
if (ot.hasOwnProperty("value") && isArray(ot.value)){
|
153
|
+
dsize=ot.value.length;
|
154
|
+
}else{
|
155
|
+
if (ot.hasOwnProperty("status") && isArray(ot.status)){
|
156
|
+
dsize=ot.status.length;
|
157
|
+
}else{
|
158
|
+
if(ot.hasOwnProperty("dimension")) {
|
159
|
+
var size=this.__tree__.dimension.size, length=1;
|
160
|
+
for(var s=size.length; s--;){
|
161
|
+
length*=size[s];
|
162
|
+
}
|
163
|
+
dsize=length;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
this.value=normalize(ot.value,dsize);
|
169
|
+
this.status=(!(ot.hasOwnProperty("status"))) ? null : normalize(ot.status,dsize);
|
170
|
+
|
171
|
+
// if dimensions are defined, id and size arrays are required and must have equal length
|
172
|
+
if (ot.hasOwnProperty("dimension")){
|
173
|
+
if (
|
174
|
+
!(isArray(ot.dimension.id)) ||
|
175
|
+
!(isArray(ot.dimension.size)) ||
|
176
|
+
ot.dimension.id.length!=ot.dimension.size.length
|
177
|
+
){
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
var otd=ot.dimension;
|
181
|
+
this.length=otd.size.length;
|
182
|
+
this.id=otd.id;
|
183
|
+
this.role=otd.role; //0.3.5 Role added
|
184
|
+
this.n=dsize; //number of obs added in 0.4.2
|
185
|
+
|
186
|
+
//If only one category, no need of index according to the spec
|
187
|
+
//This actually will recreate an index even if there are more than one category and no index is provided
|
188
|
+
//but because there's no guarantee that properties are retrieved in a particular order (even though it worked in Ch,FF,IE,Sa,Op)
|
189
|
+
//(Main problem in fact is that you don't have to WRITE them in a particular order) the original order of categories could
|
190
|
+
//theoretically be changed. That's why the procedure will only be valid when there's only one category.
|
191
|
+
//Note: If toTable() is removed it would make more sense to move this loop inside Dimension() as it is not needed for Data().
|
192
|
+
for(var d=0, len=this.length; d<len; d++){
|
193
|
+
if (!(otd[otd.id[d]].category.hasOwnProperty("index"))){
|
194
|
+
var c=0;
|
195
|
+
otd[otd.id[d]].category.index={};
|
196
|
+
for (var prop in otd[otd.id[d]].category.label){
|
197
|
+
otd[otd.id[d]].category.index[prop]=c++;
|
198
|
+
}
|
199
|
+
}else{
|
200
|
+
// If index is array instead of object convert into object
|
201
|
+
// That is: we normalize it (instead of defining a function depending on
|
202
|
+
// index type to read categories -maybe in the future when indexOf can be
|
203
|
+
// assumed for all browsers and default is array instead of object-)
|
204
|
+
if(isArray(otd[otd.id[d]].category.index)){
|
205
|
+
var oindex={}, index=otd[otd.id[d]].category.index;
|
206
|
+
for (var i=0, ilen=index.length; i<ilen; i++){
|
207
|
+
oindex[index[i]]=i;
|
208
|
+
}
|
209
|
+
otd[otd.id[d]].category.index=oindex;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}else{
|
214
|
+
this.length=0;
|
215
|
+
}
|
216
|
+
break;
|
217
|
+
case "dim" :
|
218
|
+
this.type="dim";
|
219
|
+
var cats=[], ot=o.__tree__, otc=ot.category;
|
220
|
+
if (
|
221
|
+
!o.hasOwnProperty("__tree__") ||
|
222
|
+
!ot.hasOwnProperty("category") //Already tested in the Dimension() / Category() ? method
|
223
|
+
){
|
224
|
+
return;
|
225
|
+
}
|
226
|
+
|
227
|
+
//If no category label, use IDs
|
228
|
+
if(!otc.hasOwnProperty("label")){
|
229
|
+
otc.label={};
|
230
|
+
for (var prop in otc.index){
|
231
|
+
otc.label[prop]=prop;
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
//Array conversion
|
236
|
+
for (var prop in otc.index){
|
237
|
+
cats[otc.index[prop]]=prop; //0.4.3 cats.push(prop) won't do because order not in control when index was originally an array and was converted to object by the Toolkit.
|
238
|
+
}
|
239
|
+
|
240
|
+
this.__tree__=ot;
|
241
|
+
//When no dimension label, undefined is returned.
|
242
|
+
//Discarded options: null / dim
|
243
|
+
this.label=ot.label || null;
|
244
|
+
this.id=cats;
|
245
|
+
this.length=cats.length;
|
246
|
+
this.role=o.role;
|
247
|
+
this.hierarchy=otc.hasOwnProperty("child"); //0.6.0
|
248
|
+
break;
|
249
|
+
case "cat" :
|
250
|
+
var par=o.child;
|
251
|
+
this.type="cat";
|
252
|
+
|
253
|
+
//0.5.0 changed. It was autoreference: id. And length was 0 always
|
254
|
+
this.id=par;
|
255
|
+
this.length=(par===null) ? 0 : par.length;
|
256
|
+
|
257
|
+
this.index=o.index;
|
258
|
+
this.label=o.label;
|
259
|
+
this.unit=o.unit; //v.0.5.0
|
260
|
+
this.coordinates=o.coord; //v.0.5.0
|
261
|
+
break;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
jsonstat.prototype.Dataset=function(ds){
|
266
|
+
if (this===null || this.type!=="root"){
|
267
|
+
return null;
|
268
|
+
}
|
269
|
+
if(typeof ds==="undefined"){
|
270
|
+
var ar=[];
|
271
|
+
for(var c=0, len=this.id.length; c<len; c++){
|
272
|
+
ar.push(this.Dataset(this.id[c]));
|
273
|
+
}
|
274
|
+
return ar;
|
275
|
+
}
|
276
|
+
if(typeof ds==="number"){
|
277
|
+
var num=this.id[ds];
|
278
|
+
return (typeof num!=="undefined") ? this.Dataset(num) : null;
|
279
|
+
}
|
280
|
+
|
281
|
+
var tds=this.__tree__[ds];
|
282
|
+
if(typeof tds==="undefined"){
|
283
|
+
return null;
|
284
|
+
}
|
285
|
+
|
286
|
+
return new jsonstat({"type" : "ds", "__tree__": tds});
|
287
|
+
}
|
288
|
+
|
289
|
+
jsonstat.prototype.Dimension=function(dim){
|
290
|
+
function role(otd,dim){
|
291
|
+
var otdr=otd.role;
|
292
|
+
if(typeof otdr!="undefined"){
|
293
|
+
for(var prop in otdr){
|
294
|
+
for(var p=otdr[prop].length;p--;){
|
295
|
+
if(otdr[prop][p]===dim){
|
296
|
+
return prop;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
}
|
300
|
+
}
|
301
|
+
return null;
|
302
|
+
}
|
303
|
+
|
304
|
+
if (this===null || this.type!=="ds"){
|
305
|
+
return null;
|
306
|
+
}
|
307
|
+
if(typeof dim==="undefined"){
|
308
|
+
var ar=[];
|
309
|
+
for(var c=0, len=this.id.length; c<len; c++){
|
310
|
+
ar.push(this.Dimension(this.id[c]));
|
311
|
+
}
|
312
|
+
return ar;
|
313
|
+
}
|
314
|
+
if(typeof dim==="number"){
|
315
|
+
var num=this.id[dim];
|
316
|
+
return (typeof num!=="undefined") ? this.Dimension(num) : null;
|
317
|
+
}
|
318
|
+
|
319
|
+
var otd=this.__tree__.dimension;
|
320
|
+
if(typeof otd==="undefined"){
|
321
|
+
return null;
|
322
|
+
}
|
323
|
+
|
324
|
+
//currently only "role" is supported as filter criterion
|
325
|
+
if(typeof dim==="object"){
|
326
|
+
if(dim.hasOwnProperty("role")){
|
327
|
+
var ar=[];
|
328
|
+
for(var c=0, len=this.id.length; c<len; c++){
|
329
|
+
var oid=this.id[c];
|
330
|
+
if(role(otd,oid)===dim.role){
|
331
|
+
ar.push(this.Dimension(oid));
|
332
|
+
}
|
333
|
+
}
|
334
|
+
return (typeof ar[0]==="undefined") ? null : ar;
|
335
|
+
}else{
|
336
|
+
return null;
|
337
|
+
}
|
338
|
+
}
|
339
|
+
|
340
|
+
var otdd=otd[dim];
|
341
|
+
if(typeof otdd==="undefined"){
|
342
|
+
return null;
|
343
|
+
}
|
344
|
+
|
345
|
+
return new jsonstat({"type" : "dim", "__tree__": otdd, "role": role(otd,dim)});
|
346
|
+
}
|
347
|
+
|
348
|
+
jsonstat.prototype.Category=function(cat){
|
349
|
+
if (this===null || this.type!=="dim"){
|
350
|
+
return null;
|
351
|
+
}
|
352
|
+
if(typeof cat==="undefined"){
|
353
|
+
var ar=[];
|
354
|
+
for(var c=0, len=this.id.length; c<len; c++){
|
355
|
+
ar.push(this.Category(this.id[c]));
|
356
|
+
}
|
357
|
+
return ar;
|
358
|
+
}
|
359
|
+
if(typeof cat==="number"){
|
360
|
+
var num=this.id[cat];
|
361
|
+
return (typeof num!=="undefined") ? this.Category(num) : null;
|
362
|
+
}
|
363
|
+
|
364
|
+
var oc=this.__tree__.category;
|
365
|
+
if(typeof oc==="undefined"){
|
366
|
+
return null;
|
367
|
+
}
|
368
|
+
var index=oc.index[cat];
|
369
|
+
if(typeof index==="undefined"){
|
370
|
+
return null;
|
371
|
+
}
|
372
|
+
|
373
|
+
var unit=(oc["unit"] && oc["unit"][cat]) || null;
|
374
|
+
var coord=(oc["coordinates"] && oc["coordinates"][cat]) || null;
|
375
|
+
var child=(oc["child"] && oc["child"][cat]) || null;
|
376
|
+
return new jsonstat({"type" : "cat", "index": index, "label": oc.label[cat], "child" : child, "unit" : unit, "coord" : coord});
|
377
|
+
}
|
378
|
+
|
379
|
+
jsonstat.prototype.Data=function(e){
|
380
|
+
function firstprop(o){
|
381
|
+
for (var p in o) {
|
382
|
+
if(o.hasOwnProperty(p)){
|
383
|
+
return p;
|
384
|
+
}
|
385
|
+
}
|
386
|
+
}
|
387
|
+
function dimObj2Array(thisds, obj){
|
388
|
+
var a=[], dim=thisds.dimension, di=dim.id;
|
389
|
+
for (var d=0, len=di.length; d<len; d++){
|
390
|
+
var id=di[d], cat=obj[id];
|
391
|
+
//If dimension not defined and dim size=1, take first category (user not forced to specify single cat dimensions)
|
392
|
+
a.push(typeof cat==="string" ? cat : dim.size[d]===1 ? firstprop(dim[id].category.index) : null);
|
393
|
+
}
|
394
|
+
return a;
|
395
|
+
}
|
396
|
+
|
397
|
+
if(this===null || this.type!=="ds"){
|
398
|
+
return null;
|
399
|
+
}
|
400
|
+
|
401
|
+
if(typeof e==="undefined"){
|
402
|
+
//Before 0.4.2
|
403
|
+
//return {"value" : this.value, "status": this.status, "label": tree.label, "length" : this.value.length};
|
404
|
+
//Since 0.4.2: normalized as array of objects
|
405
|
+
for(var i=0, ret=[], len=this.value.length; i<len; i++){
|
406
|
+
ret.push(this.Data(i));
|
407
|
+
}
|
408
|
+
return ret;
|
409
|
+
}
|
410
|
+
|
411
|
+
//Data By Position in original array
|
412
|
+
if(typeof e==="number"){
|
413
|
+
var num=this.value[e];
|
414
|
+
return (typeof num!=="undefined") ?
|
415
|
+
{"value" : num, "status":
|
416
|
+
(this.status) ?
|
417
|
+
this.status[e]
|
418
|
+
:
|
419
|
+
null
|
420
|
+
}
|
421
|
+
:
|
422
|
+
null
|
423
|
+
; /* removed in 0.5.2.2 length: 1 {"value" : undefined, "status": undefined, "length" : 0};*/
|
424
|
+
}
|
425
|
+
|
426
|
+
var tree=this.__tree__, n=tree.dimension.size, dims=n.length //same as this.length;
|
427
|
+
|
428
|
+
//DataByPosition in every dim
|
429
|
+
//If more positions than needed are provided, they will be ignored.
|
430
|
+
//Less positions than needed will return undefined
|
431
|
+
if(isArray(e)){
|
432
|
+
if(this.length!==e.length){ //0.5.2.2
|
433
|
+
return null;
|
434
|
+
}
|
435
|
+
var mult=1,
|
436
|
+
res=0,
|
437
|
+
miss=[],
|
438
|
+
nmiss=[],
|
439
|
+
ret=[]
|
440
|
+
;
|
441
|
+
//Validate dim index
|
442
|
+
//And loop to find missing dimensions
|
443
|
+
for(var i=0; i<dims; i++){
|
444
|
+
if(typeof e[i]!=="undefined"){
|
445
|
+
if(typeof e[i]!=="number" || e[i]>=n[i]){
|
446
|
+
return null; /* removed in 0.5.2.2 {"value" : undefined, "status": undefined, "length" : 0};*/
|
447
|
+
}
|
448
|
+
//Used if normal case (miss.length===0)
|
449
|
+
mult*=(i>0) ? n[(dims-i)] : 1;
|
450
|
+
res+=mult*e[dims-i-1]; //simplified in 0.4.3
|
451
|
+
}else{
|
452
|
+
//Used if missing dimensions miss.length>0
|
453
|
+
miss.push(i); //missing dims
|
454
|
+
nmiss.push(n[i]); //missing dims size
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
//If all dims are specified, go ahead as usual.
|
459
|
+
//If one non-single dimension is missing create array of results
|
460
|
+
//If more than one non-single dimension is missing, WARNING
|
461
|
+
if(miss.length>1){
|
462
|
+
return null; /* removed in 0.5.2.2 {"value" : undefined, "status": undefined, "length" : 0};*/
|
463
|
+
}
|
464
|
+
if(miss.length===1){
|
465
|
+
for(var c=0, clen=nmiss[0]; c<clen; c++){
|
466
|
+
var na=[]; //new array
|
467
|
+
for(var i=0; i<dims; i++){
|
468
|
+
if(i!==miss[0]){
|
469
|
+
na.push(e[i]);
|
470
|
+
}else{
|
471
|
+
na.push(c);
|
472
|
+
}
|
473
|
+
}
|
474
|
+
ret.push(this.Data(na));
|
475
|
+
}
|
476
|
+
return ret;
|
477
|
+
}
|
478
|
+
|
479
|
+
//miss.length===0 (use previously computed res) //simplified in 0.4.3
|
480
|
+
return {"value" : this.value[res], "status": (this.status) ? this.status[res] : null/*, "length" : 1*/};
|
481
|
+
}
|
482
|
+
|
483
|
+
var id=dimObj2Array(tree, e);
|
484
|
+
var pos=[], otd=tree.dimension;
|
485
|
+
for(var i=0, len=id.length; i<len; i++){
|
486
|
+
pos.push(otd[otd.id[i]].category.index[id[i]]);
|
487
|
+
}
|
488
|
+
//Dimension cat undefined means a loop (by position) is necessary
|
489
|
+
return this.Data(pos);
|
490
|
+
}
|
491
|
+
|
492
|
+
/*
|
493
|
+
Transformation method: output in DataTable format (array or object)
|
494
|
+
Setup: opts={status: false, slabel: "Status", vlabel: "Value", field: "label", content: "label", type: "array"} (type values: "array" / "object" / "arrobj")
|
495
|
+
|
496
|
+
PENDING: use metric or any dim cat IDs instead of "value" and assign as many fields as metrics (pivot "by").
|
497
|
+
*/
|
498
|
+
jsonstat.prototype.toTable=function(opts, func){
|
499
|
+
if(this===null || this.type!=="ds"){
|
500
|
+
return null;
|
501
|
+
}
|
502
|
+
|
503
|
+
if(arguments.length==1 && typeof opts==="function"){
|
504
|
+
func=opts, opts=null;
|
505
|
+
}
|
506
|
+
var
|
507
|
+
dataset=this.__tree__,
|
508
|
+
opts=opts || {field: "label", content: "label", vlabel: "Value", slabel: "Status", type: "array", status: false} //default: use label for field names and content instead of "id"
|
509
|
+
;
|
510
|
+
|
511
|
+
if(typeof func==="function"){
|
512
|
+
var
|
513
|
+
totbl=this.toTable(opts),
|
514
|
+
ret=[],
|
515
|
+
i=(opts.type!=='array') ? 0 : 1 //first row is header in array and object
|
516
|
+
;
|
517
|
+
|
518
|
+
if(opts.type!=='object'){
|
519
|
+
var arr=totbl.slice(i);
|
520
|
+
}else{
|
521
|
+
var arr=totbl.rows.slice(0);
|
522
|
+
}
|
523
|
+
|
524
|
+
for(var r=0, len=arr.length; r<len; r++){
|
525
|
+
var a=func.call(
|
526
|
+
this, //0.5.3
|
527
|
+
arr[r], //Discarded for efficiency: (opts.type!=='object') ? arr[r] : arr[r].c,
|
528
|
+
r
|
529
|
+
);
|
530
|
+
if (typeof a!=="undefined"){
|
531
|
+
ret.push(a);
|
532
|
+
}
|
533
|
+
}
|
534
|
+
if (opts.type==='object'){
|
535
|
+
return {cols: totbl.cols, rows: ret};
|
536
|
+
}
|
537
|
+
if(opts.type==='array'){
|
538
|
+
ret.unshift(totbl[0]);
|
539
|
+
}
|
540
|
+
return ret;
|
541
|
+
}
|
542
|
+
|
543
|
+
//For example, as D3 input
|
544
|
+
if(opts.type==="arrobj"){
|
545
|
+
var
|
546
|
+
totbl=this.toTable({field: "id", content: opts.content, status: opts.status}),// At the moment, options besides "type" are not passed
|
547
|
+
tbl=[],
|
548
|
+
head=totbl.shift()
|
549
|
+
;
|
550
|
+
|
551
|
+
for(var i=0, len=totbl.length; i<len; i++){ //Can't be done with i-- as we want to keep the original order
|
552
|
+
var tblr={};
|
553
|
+
for(var j=totbl[i].length;j--;){
|
554
|
+
tblr[head[j]]=totbl[i][j];
|
555
|
+
}
|
556
|
+
tbl.push(tblr);
|
557
|
+
}
|
558
|
+
return tbl;
|
559
|
+
}
|
560
|
+
|
561
|
+
var useid=(opts.field==="id");
|
562
|
+
|
563
|
+
if(opts.type==="object"){
|
564
|
+
//Object
|
565
|
+
var
|
566
|
+
valuetype=(typeof this.value[0]==="number" || this.value[0]===null) ? "number" : "string", //cell type inferred from first cell. If null, number is assumed (naif)
|
567
|
+
addCol=function(dimid,dimlabel){
|
568
|
+
var label=(useid && dimid) || dimlabel || dimid; //if userid then id; else label; then id if not label
|
569
|
+
cols.push({id: dimid, label: label, type: "string"}); //currently not using datetime Google type (requires a Date object)
|
570
|
+
},
|
571
|
+
addColValue=function(str1,str2,status){
|
572
|
+
var
|
573
|
+
vlabel=(useid && "value") || str1|| "Value",
|
574
|
+
slabel=(useid && "status") || str2|| "Status"
|
575
|
+
;
|
576
|
+
if(status){
|
577
|
+
cols.push({id: "status", label: slabel, type: "string"});
|
578
|
+
}
|
579
|
+
cols.push({id: "value", label: vlabel, type: valuetype});
|
580
|
+
},
|
581
|
+
addRow=function(r){
|
582
|
+
row.push({v: r});
|
583
|
+
},
|
584
|
+
addRowValue=function(r){
|
585
|
+
//At the moment, no support for formatted values (f: formatted)
|
586
|
+
row.push({v: r});
|
587
|
+
rows.push({c: row});
|
588
|
+
}
|
589
|
+
;
|
590
|
+
}else{
|
591
|
+
//Array
|
592
|
+
var
|
593
|
+
addCol=function(dimid,dimlabel){
|
594
|
+
var colid=(useid && dimid) || dimlabel || dimid; //if userid then id; else label; then id if not label
|
595
|
+
cols.push(colid);
|
596
|
+
},
|
597
|
+
addColValue=function(str1,str2,status){
|
598
|
+
var
|
599
|
+
vlabel=(useid && "value") || str1 || "Value",
|
600
|
+
slabel=(useid && "status") || str2 || "Status"
|
601
|
+
;
|
602
|
+
if(status){
|
603
|
+
cols.push(slabel);
|
604
|
+
}
|
605
|
+
cols.push(vlabel);
|
606
|
+
table.push(cols);
|
607
|
+
},
|
608
|
+
addRow=function(r){
|
609
|
+
row.push(r);
|
610
|
+
},
|
611
|
+
addRowValue=function(r){
|
612
|
+
row.push(r);
|
613
|
+
table.push(row);
|
614
|
+
}
|
615
|
+
;
|
616
|
+
}
|
617
|
+
|
618
|
+
var dd=dataset.dimension, ddi=dd.id, ddil=ddi.length, dds=dd.size;
|
619
|
+
if (ddil!=dds.length){
|
620
|
+
return false;
|
621
|
+
}
|
622
|
+
var dim=[], total=1, m=1, mult=[], dimexp=[], label=[], table=[], cols=[], rows=[];
|
623
|
+
for (var i=0; i<ddil; i++){
|
624
|
+
var dimid=ddi[i],
|
625
|
+
dimlabel=dd[dimid].label
|
626
|
+
;
|
627
|
+
addCol(dimid,dimlabel); //Global cols
|
628
|
+
|
629
|
+
total*=dds[i];
|
630
|
+
m*=dds[i];
|
631
|
+
var cat=[];
|
632
|
+
for (var j=0; j<dds[i]; j++){
|
633
|
+
for (var catid in dd[ddi[i]].category.index){
|
634
|
+
if (dd[ddi[i]].category.index[catid]===j){
|
635
|
+
var rowid=(opts.content!=="id" && dd[ddi[i]].category.label) ? dd[ddi[i]].category.label[catid] : catid; //id if not label (Maybe move label normalization from "dim" to "ds"?)
|
636
|
+
cat.push(rowid);
|
637
|
+
}
|
638
|
+
}
|
639
|
+
}
|
640
|
+
dim.push(cat);
|
641
|
+
mult.push(m);
|
642
|
+
}
|
643
|
+
addColValue(opts.vlabel,opts.slabel,opts.status); //Global cols and table
|
644
|
+
|
645
|
+
//end of inversion: now use dim array
|
646
|
+
for (var d=0, len=dim.length; d<len; d++){
|
647
|
+
var catexp=[];
|
648
|
+
for (var c=0, len2=dim[d].length; c<len2; c++){
|
649
|
+
//get the label repetitions
|
650
|
+
for (var n=0; n<total/mult[d]; n++){
|
651
|
+
catexp.push(dim[d][c]);
|
652
|
+
}
|
653
|
+
}
|
654
|
+
dimexp.push(catexp);
|
655
|
+
}
|
656
|
+
for (var d=0, len=dimexp.length; d<len; d++){
|
657
|
+
var l=[], e=0;
|
658
|
+
for (var x=0; x<total; x++){
|
659
|
+
l.push(dimexp[d][e]);
|
660
|
+
e++;
|
661
|
+
if (e===dimexp[d].length){
|
662
|
+
e=0;
|
663
|
+
}
|
664
|
+
}
|
665
|
+
label.push(l);
|
666
|
+
}
|
667
|
+
for (var x=0; x<total; x++){
|
668
|
+
var row=[];
|
669
|
+
for (var d=0, len=dimexp.length; d<len; d++){
|
670
|
+
addRow(label[d][x]); //Global row
|
671
|
+
}
|
672
|
+
if(opts.status){
|
673
|
+
addRow(this.status[x]);
|
674
|
+
}
|
675
|
+
addRowValue(this.value[x]); //Global row, rows and table
|
676
|
+
}
|
677
|
+
|
678
|
+
if(opts.type==="object"){
|
679
|
+
return {cols: cols, rows: rows};
|
680
|
+
}else{
|
681
|
+
return table;
|
682
|
+
}
|
683
|
+
}
|
684
|
+
|
685
|
+
jsonstat.prototype.node=function(){
|
686
|
+
return this.__tree__;
|
687
|
+
}
|
688
|
+
|
689
|
+
jsonstat.prototype.toString=function(){
|
690
|
+
return this.type; //improve?
|
691
|
+
}
|
692
|
+
jsonstat.prototype.toValue=function(){
|
693
|
+
return this.length;
|
694
|
+
}
|
695
|
+
|
696
|
+
JSONstat.jsonstat=jsonstat;
|
697
|
+
})();
|