-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
737 lines (631 loc) · 21.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Homework 1 Starter</title>
<!-- An AMD-loader like RequireJS is necessary for srlib's asynchronous modules -->
<script src="require.js"></script>
<!-- Load srlib following RequireJS -->
<script src="srlib.js"></script>
<!-- JQuery provides a very nice set of tools when dealing with AJAX requests -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript">
// This max value for this is 20000. If you go above it, it will limit to 20000. There are 10k arrows and 10k not arrows.
// I recommend starting small until all your features calculate correctly, because 20000 will take a few min to fetch and calculate.
maxResults = 20000;
//************* Turn 'selectSubset' variable to 'false' for evaluating ALL Features *************************************
var selectSubset = true;
// The interpretation will automatically be added to each row of csv data for you.
// Place the function names to calculate your features here. The function name will be the header of the csv file for that row.
featureFunctions = [ //Format: "feature"+id+{R:Rubine,L:Long,O:Others}
feature1R, // cosine of starting angle
feature2R, // sine of starting angle
feature3R, // Length of Bounding Box Diagonal
feature4R, // Angle of Bounding Box Diagonal
feature5R, // Start and Endpoint Distance
feature6R, // cosine of Angle from Start to Endpoint
feature7R, // sine of Angle from Start to Endpoint
feature8R, // Stroke Length
feature9R, // Total rotational change in a stroke
feature10R, // Absolute rotational change in a stroke
feature11R, // Smoothness/ Squared rotational change of the stroke.
feature12R, // Maximum speed
feature13R, // Total Time
feature14L, // Aspect [abs(Pi/4 - F4)]
feature15L, // Curviness
feature16L, // Total angle traversed / total length
feature17L, // Density metric 1 [F8 / F5]
feature18L, // Density metric 2 [F8 / F3]
feature19L, // Non-subjective openness [F5 / F3]
feature20L, // Area of bounding box
feature21L, // Log(area)
feature22L, // Total angle / total absolute angle [F9 / F10]
feature23L, // Log(total length)
feature24L, // Log(aspect)
feature25O, // Normalized Distance between Direction Extremes (NDDE)
feature26O, // Direction Change Ratio
feature27O, // Basic Arrows drawn having polyline feature
feature28O, // For multi-stroke sketch, Bounding Box length of Arrow Shaft / Total Bounding Box Length
feature29O, // Multiplication of number of Strokes and substrokes
feature30O, // Geometric similarity of arrow heads relative to shaft
feature31O // feature29 * feature30
];
// Creating separate array for selected features subset
featureSubset = [ //Format: "feature"+id+{R:Rubine,L:Long,O:Others}
//feature1R, // cosine of starting angle
//feature2R, // sine of starting angle
feature3R, // Length of Bounding Box Diagonal
//feature4R, // Angle of Bounding Box Diagonal
//feature5R, // Start and Endpoint Distance
//feature6R, // cosine of Angle from Start to Endpoint
//feature7R, // sine of Angle from Start to Endpoint
feature8R, // Stroke Length
feature9R, // Total rotational change in a stroke
feature10R, // Absolute rotational change in a stroke
feature11R, // Smoothness/ Squared rotational change of the stroke.
//feature12R, // Maximum speed
//feature13R, // Total Time
//feature14L, // Aspect [abs(Pi/4 - F4)]
feature15L, // Curviness
feature16L, // Total angle traversed / total length
feature17L, // Density metric 1 [F8 / F5]
feature18L, // Density metric 2 [F8 / F3]
//feature19L, // Non-subjective openness [F5 / F3]
//feature20L, // Area of bounding box
//feature21L, // Log(area)
feature22L, // Total angle / total absolute angle [F9 / F10]
feature23L, // Log(total length)
//feature24L, // Log(aspect)
feature25O, // Modified Normalized Distance between Direction Extremes
feature26O, // Direction Change Ratio
feature27O, // Basic Arrows drawn having polyline feature
feature28O, // For multi-stroke sketch, Bounding Box length of Arrow Shaft / Total Bounding Box Length
feature29O, // Multiplication of number of Strokes and substrokes
//feature30O, // Geometric similarity of arrow heads relative to shaft
//feature31O // feature29 * feature30
];
/* Define your feature functions here */
/* Each function only needs to return the feature value */
/* Basic structure is as follows
Input Json:
{
points: {id: {x: int, y: int, time: intString}, ...},
shapes: [{interpretation: string}], // Shapes should only have 1 entry and the interpretation is all you care about. Either arrow or something else
strokes: [{id: string, time: string, points: [pointId1, pointId2, ...]}, ...]
}
*/
var SStrokes = []; //Sampled strokes
var minX = Number.MAX_VALUE;
var minY = Number.MAX_VALUE;
var maxX = Number.MIN_VALUE;
var maxY = Number.MIN_VALUE;
// Storing Initial and Last points
var x0 = null, y0 = null, t0 = null, x2 = null, y2 = null, t2 = null, xL = null, yL = null, tL = null;
var distance0_2 = 0;
var BBlengthF3 = 0; // Length of Bounding Box
var DAngleF4 = 0;
var S2ElengthF5 = 0; // Start to Endpoint distance
var StrokelengthF8 = 0;
var rotationF9 = 0;
var absRotationF10 = 0;
var sqRotationF11 = 0;
var maxSpeedF12 = 0;
var aspectF14 = 0;
var curvinessF15 = 0;
var areaF20 = 0;
var minDirPoint = null;
var maxDirPoint = null;
var maxDirVal = Number.MIN_VALUE;
var minDirVal = Number.MAX_VALUE;
var DCRF26 = 0;
var maxStrokeBBlen = 0;
var Corners = [];
var subStrokeLenF29 = 0;
var similarityF30 = -1;
function preProcess(sketch) {
//console.log(sketch.id);
// find resample spacing or distance
var S = calculateRD(sketch);
//console.log("Resampling Distance = " + S);
// resample the points and store them sequentially
resample(sketch, S);
//console.log(SStrokes);
//console.log(sketch.points);
//Feature 1 & 2
distance0_2 = Math.sqrt(Math.pow((y2-y0),2) + Math.pow((x2-x0),2))
// Feature 3, 8 & 12 calculated already
//Feature 4
DAngleF4 = Math.atan2(maxY-minY, maxX-minX);
// Feature 5
S2ElengthF5 = Math.sqrt((yL-y0)*(yL-y0) + (xL-x0)*(xL-x0));
// Feature 9, 10, 11, 26 and Corners. All angular stuff
{
rotationF9 = 0;
absRotationF10 = 0;
sqRotationF11 = 0;
curvinessF15 = 0;
DCRF26 = 0;
Corners = [];
minDirPoint = null;
maxDirPoint = null;
maxDirVal = Number.MIN_VALUE;
minDirVal = Number.MAX_VALUE;
maxStrokeBBlen = 0;
for (var s=0; s< SStrokes.length; s++) {
var Spoints = SStrokes[s];
var skip = Math.floor(Spoints.length/20);
var maxChangeDCR = Number.MIN_VALUE;
var avgChangeSumDCR = 0;
Corners.push(Spoints[0]);
var xmin = Spoints[0].x;
var ymin = Spoints[0].y;
var xmax = Spoints[0].x;
var ymax = Spoints[0].y;
for(var i=1; i < Spoints.length-1 ; i++) {
delX = Spoints[i+1].x - Spoints[i].x;
delY = Spoints[i+1].y - Spoints[i].y;
delXprev = Spoints[i].x - Spoints[i-1].x;
delYprev = Spoints[i].y - Spoints[i-1].y;
// Math.atan2(y,x) takes care of corner cases for +Pi/2 & -Pi/2
var val = Math.atan2(delXprev*delY - delX*delYprev, delX*delXprev + delY*delYprev);
var absval = Math.abs(val);
if (!isNaN(val)) {
rotationF9 += val;
absRotationF10 += absval;
sqRotationF11 += Math.pow(val,2);
if (absval < (19*Math.PI)/180) {
curvinessF15 += absval;
}
//Direction Change Ratio cut off tail
if (i >= skip && i < Spoints.length - skip) {
if (maxChangeDCR < absval) maxChangeDCR = absval;
avgChangeSumDCR += absval;
//Corners
if (absval > (20*Math.PI)/180) {
Corners.push(Spoints[i]);
}
}
// Comparing for Stroke with max Bounding Box length
if (xmin > Spoints[i].x) xmin = Spoints[i].x;
if (ymin > Spoints[i].y) ymin = Spoints[i].y;
if (xmax < Spoints[i].x) xmax = Spoints[i].x;
if (ymax < Spoints[i].y) ymax = Spoints[i].y;
}
// Direction extremes
var dir = Math.atan2(delYprev, delXprev);
if (minDirVal > dir) {
minDirVal = dir;
minDirPoint = Spoints[i];
}
if (maxDirVal < dir) {
maxDirVal = dir;
maxDirPoint = Spoints[i];
}
}
// Last Point
Corners.push(Spoints[i]);
// Comparing Last Point for Stroke with max Bounding Box length
if (xmin > Spoints[i].x) xmin = Spoints[i].x;
if (ymin > Spoints[i].y) ymin = Spoints[i].y;
if (xmax < Spoints[i].x) xmax = Spoints[i].x;
if (ymax < Spoints[i].y) ymax = Spoints[i].y;
// Direction extremes
var dir = Math.atan2(Spoints[i].y - Spoints[i-1].y, Spoints[i].x - Spoints[i-1].x);
if (minDirVal > dir) {
minDirVal = dir;
minDirPoint = Spoints[i];
}
if (maxDirVal < dir) {
maxDirVal = dir;
maxDirPoint = Spoints[i];
}
// Calculate Stroke with max Bounding Box length
var bblen = Math.sqrt(Math.pow((ymax-ymin),2) + Math.pow((xmax-xmin),2));
if (maxStrokeBBlen < bblen) {
maxStrokeBBlen = bblen;
}
if (avgChangeSumDCR) {
DCRF26 += (maxChangeDCR * (Spoints.length - 2*skip))/ avgChangeSumDCR;
}
}
DCRF26 /= SStrokes.length; // Taking average over all the strokes
}
// Feature 14
aspectF14 = Math.abs(Math.PI/4 - DAngleF4);
// Feature 20
areaF20 = (maxX-minX)*(maxY-minY);
// Feature 29
if (sketch.substrokes.length) {
subStrokeLenF29 = sketch.strokes.length * sketch.substrokes.length;
} else {
subStrokeLenF29 = sketch.strokes.length;
}
// Feature 30
if (Corners.length) {
var maxLen = Number.MIN_VALUE;
var end = 0; // Shaft End Index, start being 0.
var perpMax1 = Number.MIN_VALUE;
var perpMax2 = Number.MIN_VALUE;
var ah1 = 0; //Arrow head 1
var ah2 = 0; //Arrow head 2
// Shaft Computation
for (var i=1; i<Corners.length; i++) {
var dis = Math.sqrt(Math.pow((Corners[i].y - Corners[0].y),2) + Math.pow((Corners[i].x - Corners[0].x),2));
if (maxLen < dis) {
maxLen = dis;
end = i;
}
}
// Arrow heads computation
for (var i=1; i<Corners.length ; i++) {
var disPerp = ((Corners[end].y - Corners[0].y)*Corners[i].x - (Corners[end].x - Corners[0].x)*Corners[i].y
+ Corners[end].x * Corners[0].y - Corners[end].y * Corners[0].x ) / maxLen;
if ((Math.abs(disPerp) > Math.abs(perpMax1)) && (Math.abs(disPerp) > Math.abs(perpMax2))) {
perpMax2 = perpMax1;
ah2 = ah1;
perpMax1 = disPerp;
ah1 = i;
} else if (Math.abs(disPerp) > Math.abs(perpMax2)) {
perpMax2 = disPerp;
ah2 = i;
}
}
// Similarity calculation
similarityF30 = Math.abs(
(perpMax1/ Math.sqrt(Math.pow((Corners[ah1].y - Corners[end].y),2) + Math.pow((Corners[ah1].x - Corners[end].x),2))) -
(perpMax2/ Math.sqrt(Math.pow((Corners[ah2].y - Corners[end].y),2) + Math.pow((Corners[ah2].x - Corners[end].x),2))) );
}
}
function calculateRD(sketch) { //Resampling Distance
minX = Number.MAX_VALUE;
minY = Number.MAX_VALUE;
maxX = Number.MIN_VALUE;
maxY = Number.MIN_VALUE;
for (var s=0; s< sketch.strokes.length; s++) {
for (var i=0; i<sketch.strokes[s].points.length; i++) {
var val = sketch.points[sketch.strokes[s].points[i]];
//console.log(val);
if(val) {
if (minX > val.x) minX = val.x;
if (minY > val.y) minY = val.y;
if (maxX < val.x) maxX = val.x;
if (maxY < val.y) maxY = val.y;
}
}
}
BBlengthF3 = Math.sqrt((maxY-minY)*(maxY-minY) + (maxX-minX)*(maxX-minX));
// Divide bounding box diagonal length by empirical factor 40
return BBlengthF3/40.0;
}
function resample(sketch, S) {
var D = 0;
SStrokes = []; // reinitialize for each sketch
x0 = null, y0 = null, t0 = null, x2 = null, y2 = null, t2 = null, xL = null, yL = null, tL = null; // nullify these values for each sketch
StrokelengthF8 = 0;
maxSpeedF12 = 0;
//reorder stroke array based on time stamp of first point
sketch.strokes.sort(function(a, b){
if (sketch.points[a.points[0]] && sketch.points[b.points[0]]) {
return sketch.points[a.points[0]].time - sketch.points[b.points[0]].time;
} else {
return 0;
}
});
for (var s=0; s< sketch.strokes.length; s++) {
if (sketch.strokes[s].points.length) {
var Spoints = [];
var prevX = sketch.points[sketch.strokes[s].points[0]].x;
var prevY = sketch.points[sketch.strokes[s].points[0]].y;
var prevT = sketch.points[sketch.strokes[s].points[0]].time;
if(!x0) {
x0 = prevX;
y0 = prevY;
t0 = prevT;
}
if (!x2 && sketch.strokes[s].points[2]) {
x2 = sketch.points[sketch.strokes[s].points[2]].x;
y2 = sketch.points[sketch.strokes[s].points[2]].y;
t2 = sketch.points[sketch.strokes[s].points[2]].time;
}
Spoints.push(JSON.parse('{ "x":' + prevX + ', "y":' + prevY + ', "t":' + prevT +'}')); //Initial point
var val = null;
for (var i=1; i<sketch.strokes[s].points.length; i++) {
val = sketch.points[sketch.strokes[s].points[i]];
if(val) {
if (!x2) {
x2 = val.x;
y2 = val.y;
t2 = val.time;
}
D = Math.sqrt((val.y-prevY)*(val.y-prevY) + (val.x-prevX)*(val.x-prevX));
//Resample if this point is beyond interspacing distance
if (D >= S) {
prevX = prevX + (val.x - prevX)*(S/D);
prevY = prevY + (val.y - prevY)*(S/D);
prevT = val.time;
Spoints.push(JSON.parse('{ "x":' + prevX + ', "y":' + prevY + ', "t":' + prevT +'}'));
}
var pval = sketch.points[sketch.strokes[s].points[i-1]];
if (pval) {
// Calculate Stroke Length
StrokelengthF8 += Math.sqrt((val.y-pval.y)*(val.y-pval.y) + (val.x-pval.x)*(val.x-pval.x));
// Calculate max Speed
if (val.time > pval.time) {
var speed = (Math.pow(val.x - pval.x, 2) + Math.pow(val.y - pval.y, 2))/ Math.pow(val.time - pval.time, 2);
if (speed > maxSpeedF12) {
maxSpeedF12 = speed;
}
} else {
//console.log("F12: Max Speed Feature anomaly T(i) "+ val.time + " & T(i-1) " + pval.time);
}
}
}
}
// Insert Last point
if(val){
xL = val.x;
yL = val.y;
tL = val.time;
Spoints.push(JSON.parse('{ "x":' + val.x + ', "y":' + val.y + ', "t":' + val.time +'}'));
}
if (Spoints.length) {
SStrokes.push(Spoints);
}
}
}
}
function feature1R(sketch) {
return (x2-x0)/distance0_2;
}
function feature2R(sketch) {
return (y2-y0)/distance0_2;
}
function feature3R(sketch) {
return BBlengthF3;
}
function feature4R(sketch) {
return DAngleF4;
}
function feature5R(sketch) {
return S2ElengthF5;
}
function feature6R(sketch) {
return (xL -x0)/S2ElengthF5;
}
function feature7R(sketch) {
return (yL -y0)/S2ElengthF5;
}
function feature8R(sketch) {
return StrokelengthF8;
}
function feature9R(sketch) {
return rotationF9;
}
function feature10R(sketch) {
return absRotationF10;
}
function feature11R(sketch) {
return sqRotationF11;
}
function feature12R(sketch) {
return maxSpeedF12;
}
function feature13R(sketch) {
return tL - t0;
}
function feature14L(sketch) {
return aspectF14;
}
function feature15L(sketch) {
return curvinessF15;
}
function feature16L(sketch) {
return rotationF9/StrokelengthF8;
}
function feature17L(sketch) {
return StrokelengthF8/S2ElengthF5;
}
function feature18L(sketch) {
return StrokelengthF8/BBlengthF3;
}
function feature19L(sketch) {
return S2ElengthF5/BBlengthF3;
}
function feature20L(sketch) {
return areaF20;
}
function feature21L(sketch) {
if (areaF20 == 0) {
return Number.MIN_VALUE;
} else {
return Math.log(areaF20);
}
}
function feature22L(sketch) {
if (absRotationF10 == 0) {
return Number.MAX_VALUE;
} else {
return rotationF9/absRotationF10;
}
}
function feature23L(sketch) {
if (StrokelengthF8 == 0) {
return Number.MIN_VALUE;
} else {
return Math.log(StrokelengthF8);
}
}
function feature24L(sketch) {
if (aspectF14 == 0) {
return Number.MIN_VALUE;
} else {
return Math.log(aspectF14);
}
}
function feature25O(sketch) {
if (minDirPoint && maxDirPoint) {
var calcStroke = false;
var nddeStrokeLen = 0;
for (var s=0; s< SStrokes.length; s++) {
var Spoints = SStrokes[s];
for(var i=1; i < Spoints.length ; i++) {
var val = Spoints[i];
if(calcStroke) {
var pval = Spoints[i-1];
nddeStrokeLen += Math.sqrt(Math.pow((val.y - pval.y),2) + Math.pow((val.x - pval.x),2));
}
if ((JSON.stringify(minDirPoint) == JSON.stringify(val)) ||
(JSON.stringify(maxDirPoint) == JSON.stringify(val)) ) {
calcStroke = !calcStroke;
}
}
}
return nddeStrokeLen/StrokelengthF8;
} else {
return -1;
}
}
function feature26O(sketch) {
return DCRF26;
}
function feature27O(sketch) {
return DCRF26*S2ElengthF5/StrokelengthF8;
}
function feature28O(sketch) {
//Only for multiple strokes
//if (SStrokes.length < 2) {
// return -1;
//} else {
return maxStrokeBBlen/BBlengthF3;
//}
}
function feature29O(sketch) {
return subStrokeLenF29;
}
function feature30O(sketch) {
return similarityF30;
}
function feature31O(sketch) {
return subStrokeLenF29 * similarityF30;
}
//
//
// Everything below here you shouldn't need to worry about.
//
//
// Begin processing once webpage loaded
$(document).ready(function() {
features = [[]];
// DO NOT REMOVE THESE LINES
if (selectSubset){
// For Subset Features
for (var i = 0; i < featureSubset.length; i++) {
var f = featureSubset[i];
features[0].push(f.name);
}
} else {
// For All Features
for (var i = 0; i < featureFunctions.length; i++) {
var f = featureFunctions[i];
features[0].push(f.name);
}
}
features[0].push('interpretation');
getSketchIds();
});
function calculateFeatures(sketch) {
var row = [];
// Perform preprocessing on sketch points
//console.log(sketch.points);
preProcess(sketch);
// Now just push back all the feature values in order.
if (selectSubset){
// For Subset Features
for (var i = 0; i < featureSubset.length; i++) {
var f = featureSubset[i];
row.push(f(sketch));
}
} else {
// For All Features
for (var i = 0; i < featureFunctions.length; i++) {
var f = featureFunctions[i];
row.push(f(sketch));
}
}
if (sketch.shapes[0].interpretation == 'arrow') {
row.push('arrow');
} else {
row.push('other');
}
// Finally push the row to the overall features array.
features.push(row);
}
function arrayToObj(array) {
var obj = {}
for (var i = 0; i < array.length; i++) {
var val = array[i];
var id = val.id;
delete val.id;
obj[id] = val;
}
return obj;
}
// Top answer from https://stackoverflow.com/questions/17836273/export-javascript-data-to-csv-file-without-server-interaction
function saveCSV() {
var csvRows = [];
for (var i = 0; i < features.length; i++) {
csvRows.push(features[i].join(','));
}
var csvString = csvRows.join('\n');
var csvData = new Blob([csvString], { type: 'text/csv' });
var csvURL = URL.createObjectURL(csvData);
var a = document.createElement('a');
a.href = csvURL;
a.target = '_blank';
a.download = 'features.csv';
document.body.appendChild(a);
a.click();
}
function getSketch() {
if (counter == sketchIds.length || counter == maxResults) { // Reached the last sketch.
saveCSV();
return;
}
var id = sketchIds[counter];
counter++;
$.ajax({
type: "GET",
url: "http://srl-prod1.cs.tamu.edu:7750/getSketches?id=" + id,
dataType: 'json',
contentType: "application/json",
success: function(res) {
var sketch = res[0];
// Visualizing the data
//var visual = counter + " ";
//sketch.points.forEach(function(point) {
// visual += "("+point.x+", "+ point.y+")";
//});
//console.log(visual);
sketch.points = arrayToObj(sketch.points);
document.getElementById('progress').textContent = 'Calculating features for sketch ' + counter + ' of ' + maxResults;
calculateFeatures(sketch);
getSketch();
}
});
}
// Load data, populating global list of sketchIds
var sketchIds;
var counter = 0;
function getSketchIds() {
$.ajax({url: "http://srl-prod1.cs.tamu.edu:7750/getIds?domain=SketchRec2017", success: function(result) {
sketchIds = result;
getSketch();
}});
}
</script>
</head>
<!-- The body consists simply of a canvas for drawing and a selection list; this display is for the user's benefit, not required -->
<body>
<div id='progress'>0</div>
</body>
</html>