ons_openapi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
})();
|