@andyreagan/hedotools 3.0.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.
@@ -0,0 +1,576 @@
1
+ hedotools.map = function() {
2
+
3
+ var figure;
4
+
5
+ var setfigure = function(_) {
6
+ console.log("setting figure");
7
+ figure = _;
8
+ return hedotools.map;
9
+ }
10
+
11
+ var classColor = d3.scale.quantize()
12
+ .range([0,1,2,3,4,5,6])
13
+ .domain([50,1]);
14
+
15
+ var geoJson;
16
+
17
+ var setdata = function(_) {
18
+ geoJson = _;
19
+ return hedotools.map;
20
+ }
21
+
22
+ var plot = function() {
23
+ /*
24
+ plot the state map!
25
+
26
+ drawMap(figure,geoJson);
27
+ -figure is a d3 selection
28
+ -geoJson is the loaded us-states file
29
+ -stateHapps is the loaded csv (state,val)
30
+ */
31
+
32
+ //Width and height
33
+ var w = parseInt(figure.style('width'));
34
+ var h = w*650/900;
35
+
36
+ // remove an old figure if it exists
37
+ figure.select(".canvas").remove();
38
+
39
+ //Create SVG element
40
+ var canvas = figure
41
+ .append("svg")
42
+ .attr("class", "map canvas")
43
+ .attr("id", "mapsvg")
44
+ .attr("width", w)
45
+ .attr("height", h);
46
+
47
+ var selarray = [false,true],
48
+ selstrings = ["Reference","Comparison"],
49
+ selstringslen = selstrings.map(function(d) { return d.width(); }),
50
+ initialpadding = 5,
51
+ boxpadding = 5,
52
+ fullselboxwidth = selarray.length*boxpadding*2-boxpadding+initialpadding+d3.sum(selstringslen);
53
+
54
+ var legendscale = d3.scale.linear()
55
+ .domain([340,730])
56
+ .range([0,1]);
57
+
58
+ function makeSelector() {
59
+
60
+ canvas.append("text")
61
+ .attr({
62
+ "x": (w-70-fullselboxwidth-56),
63
+ "y": 54,
64
+ "fill": "grey",
65
+ })
66
+ .text("Selecting ");
67
+
68
+ var selgroup = canvas.append("g")
69
+ .attr({"class": "selgroup",
70
+ "transform": "translate("+(w-70-fullselboxwidth)+","+40+")",});
71
+
72
+ selgroup.append("rect")
73
+ .attr({"class": "selbox",
74
+ "x": 0,
75
+ "y": 0,
76
+ "rx": 3,
77
+ "ry": 3,
78
+ "width": fullselboxwidth,
79
+ "height": 19,
80
+ "fill": "#F8F8F8",
81
+ 'stroke-width': '0.5',
82
+ 'stroke': 'rgb(0,0,0)'});
83
+
84
+ selgroup.selectAll("rect.colorclick")
85
+ .data(selarray)
86
+ .enter()
87
+ .append("rect")
88
+ .attr({"class": function(d,i) { return "colorclick "+intStr[i]; },
89
+ "x": function(d,i) { if (i === 0) { return 0; }
90
+ else { return d3.sum(selstringslen.slice(0,i))+i*boxpadding+(i-1)*boxpadding+initialpadding; } },
91
+ "y": 0,
92
+ "rx": 3,
93
+ "ry": 3,
94
+ "width": function(d,i) { if (i === 0) { return selstringslen[i]+initialpadding+boxpadding; } else { return selstringslen[i]+boxpadding*2; }},
95
+ "height": 19,
96
+ "fill": "#F8F8F8", //http://www.w3schools.com/html/html_colors.asp
97
+ 'stroke-width': '0.5',
98
+ 'stroke': 'rgb(0,0,0)'});
99
+
100
+ selgroup.selectAll("text")
101
+ .data(selstrings)
102
+ .enter()
103
+ .append("text")
104
+ .attr({ "x": function(d,i) {
105
+ // start at 2
106
+ if (i==0) { return initialpadding; }
107
+ // then use 2+width+10+width+10+width...
108
+ // for default padding of 5 on L/R
109
+ else { return d3.sum(selstringslen.slice(0,i))+initialpadding+i*boxpadding*2; } },
110
+ "y": 14,
111
+ "class": function(d,i) { return "seltext "+intStr[i]; },
112
+ })
113
+ .text(function(d,i) { return d; });
114
+
115
+ selgroup.selectAll("rect.selclick")
116
+ .data(selarray)
117
+ .enter()
118
+ .append("rect")
119
+ .attr({"class": "selrect",
120
+ "x": function(d,i) { if (i === 0) { return 0; }
121
+ else { return d3.sum(selstringslen.slice(0,i))+i*boxpadding+(i-1)*boxpadding+initialpadding; } },
122
+ "y": 0,
123
+ "width": function(d,i) { if (i === 0) { return selstringslen[i]+initialpadding+boxpadding; } else { return selstringslen[i]+boxpadding*2; }},
124
+ "height": 19,
125
+ "fill": "white", //http://www.w3schools.com/html/html_colors.asp
126
+ "opacity": "0.0",})
127
+ .on("mousedown", function(d,i) {
128
+ if (stateSelType !== d) {
129
+ stateSelType = d;
130
+ activeHover = true;
131
+ d3.selectAll("text.seltext").attr("fill","black")
132
+ d3.select("text.seltext."+intStr[i]).attr("fill","white")
133
+ d3.selectAll("rect.colorclick").attr("fill","#F8F8F8").attr("stroke","rgb(0,0,0)")
134
+ d3.select("rect.colorclick."+intStr[i]).attr("fill","#428bca").attr("stroke","#428bca");
135
+ d3.select(".selbutton.one").attr("class","btn btn-default btn-xs pull-right selbutton one");
136
+ d3.select(".selbutton.two").attr("class","btn btn-default btn-xs pull-right selbutton two");
137
+ d3.select(".selbutton."+intStr[i]).attr("class","btn btn-primary btn-xs pull-right selbutton "+intStr[i]);
138
+ d3.selectAll(".state").attr("stroke-width",0.7);
139
+ }
140
+ });
141
+
142
+ selgroup.selectAll("line")
143
+ .data(selstrings.slice(0,selstrings.length-1))
144
+ .enter()
145
+ .append("line")
146
+ .attr("stroke","grey")
147
+ .attr("stroke-width","2")
148
+ .attr("x1", function(d,i) {
149
+ return d3.sum(selstringslen.slice(0,i+1))+i*boxpadding+(i+1)*boxpadding+initialpadding;
150
+ })
151
+ .attr("x2", function(d,i) {
152
+ return d3.sum(selstringslen.slice(0,i+1))+i*boxpadding+(i+1)*boxpadding+initialpadding;
153
+ })
154
+ .attr("y1", 0)
155
+ .attr("y2", 19);
156
+
157
+ if (stateSelType) {
158
+ var i = 1;
159
+ }
160
+ else {
161
+ var i = 0;
162
+ }
163
+
164
+ d3.selectAll("text.seltext").attr("fill","black")
165
+ d3.select("text.seltext."+intStr[i]).attr("fill","white")
166
+ d3.selectAll("rect.colorclick").attr("fill","#F8F8F8").attr("stroke","rgb(0,0,0)")
167
+ d3.select("rect.colorclick."+intStr[i]).attr("fill","#428bca").attr("stroke","#428bca");
168
+
169
+ }
170
+
171
+ function makeLegend(legendwidth,legendheight,textsize) {
172
+
173
+ var legendarray = [0,1,2,3,4,5,6],
174
+ legendstringslen = [legendwidth,legendwidth,legendwidth,legendwidth,legendwidth,legendwidth,legendwidth,],
175
+ initialpadding = 0,
176
+ boxpadding = 0.25,
177
+ fulllegendboxwidth = legendarray.length*boxpadding*2-boxpadding+initialpadding+d3.sum(legendstringslen);
178
+
179
+ var legendgroup = canvas.append("g")
180
+ .attr({"class": "legendgroup",
181
+ "transform": "translate("+(w-50-fulllegendboxwidth)+","+(h-legendheight-legendheight-2)+")",});
182
+
183
+ legendgroup.selectAll("rect.legendrect")
184
+ .data(legendarray)
185
+ .enter()
186
+ .append("rect")
187
+ .attr({"class": function(d,i) { return "q"+i+"-8"; },
188
+ "x": function(d,i) { if (i === 0) { return 0; }
189
+ else { return d3.sum(legendstringslen.slice(0,i))+i*boxpadding+(i-1)*boxpadding+initialpadding; } },
190
+ "y": 0,
191
+ // "rx": 3,
192
+ // "ry": 3,
193
+ "width": function(d,i) { return legendstringslen[i]; },
194
+ "height": legendheight,
195
+ 'stroke-width': '1',
196
+ 'stroke': 'rgb(0,0,0)'});
197
+
198
+ legendgroup.selectAll("text.legendtext")
199
+ .data(["less happy","happier"])
200
+ .enter()
201
+ .append("text")
202
+ .attr({"x": function(d,i) {
203
+ if (i==0) { return 0; }
204
+ else { return fulllegendboxwidth-d.width(textsize+"px arial"); } },
205
+ "y": legendheight+legendheight,
206
+ "class": function(d,i) { return "legendtext"; },
207
+ "font-size": textsize+"px",
208
+ })
209
+ .text(function(d,i) { return d; });
210
+ }
211
+
212
+ var scaleFactor = legendscale(w);
213
+
214
+ makeLegend((20+10*scaleFactor),(8+5*scaleFactor),(9+3*scaleFactor));
215
+
216
+ //Define map projection
217
+ var projection = d3.geo.albersUsa()
218
+ .translate([w/2, h/2])
219
+ .scale(w*1.3);
220
+ //.scale(1000);
221
+
222
+ //Define path generator
223
+ var path = d3.geo.path()
224
+ .projection(projection);
225
+
226
+ var numColors = 20,
227
+ hueRange = [240,60], // in degrees
228
+ // see http://hslpicker.com/#ffd900
229
+ saturation = 1, // full
230
+ lightness = 0.5; // half
231
+ var colors = Array(numColors);
232
+ var colorStrings = Array(numColors);
233
+ for (i = 0; i<numColors; i++) {
234
+ colors[i] = hslToRgb((hueRange[0]+(hueRange[1]-hueRange[0])/(numColors-1)*i)/360, saturation, lightness);
235
+ colorStrings[i] = "rgb(" + colors[i][0] + "," + colors[i][1] + "," + colors[i][2] + ")"
236
+ }
237
+ // console.log(colors);
238
+ // console.log(colorStrings);
239
+
240
+ //Define quantize scale to sort data values into buckets of color
241
+ color = d3.scale.quantize()
242
+ //.range(["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"]);
243
+ .range(colorStrings)
244
+ .domain([
245
+ d3.min(allData, function(d) { return d.avhapps; }),
246
+ d3.max(allData, function(d) { return d.avhapps; })
247
+ ]);
248
+
249
+ //Colors taken from colorbrewer.js, included in the D3 download
250
+
251
+ // do the sorting
252
+ indices = Array(allData.length-1);
253
+ for (var i = 0; i < allData.length-1; i++) { indices[i] = i; }
254
+ indices.sort(function(a,b) { return Math.abs(allData[a].avhapps) < Math.abs(allData[b].avhapps) ? 1 : Math.abs(allData[a].avhapps) > Math.abs(allData[b].avhapps) ? -1 : 0; });
255
+ sortedStates = Array(allData.length-1);
256
+ for (var i = 0; i < allData.length-1; i++) { sortedStates[i] = [i,indices[i],allStateNames[indices[i]]]; }
257
+ // console.log(sortedStates);
258
+ sortedStateList = Array(allData.length);
259
+ for (var i = 0; i < allData.length; i++) { sortedStateList[indices[i]] = i+1; }
260
+
261
+ stateFeatures = topojson.feature(geoJson,geoJson.objects.states).features;
262
+
263
+ //Bind data and create one path per GeoJSON feature
264
+ var states = canvas.selectAll("path")
265
+ .data(stateFeatures);
266
+
267
+ states.enter()
268
+ .append("path")
269
+ .attr("d", function(d,i) { return path(d.geometry); } )
270
+ .attr("id", function(d,i) { return d.properties.name; } )
271
+ .attr("class",function(d,i) { return "state map "+d.properties.name[0]+d.properties.name.split(" ")[d.properties.name.split(" ").length-1]+" "+"q"+classColor(sortedStateList[i])+"-8"; } )
272
+ .on("mousedown",state_clicked)
273
+ .on("mouseover",state_hover)
274
+ .on("mouseout",state_unhover);
275
+
276
+ states.exit().remove();
277
+
278
+ states
279
+ .attr("stroke","black")
280
+ .attr("stroke-width",".7");
281
+
282
+ function state_clicked(d,i) {
283
+ // next line verifies that the data and json line up
284
+ // console.log(d.properties.name); console.log(allData[i].name);
285
+
286
+ if (activeHover) {
287
+ // stop hovering
288
+ activeHover = false;
289
+ // remove the color
290
+ d3.selectAll(".state").style("fill",null);
291
+ if (stateSelType) {
292
+ // select the comparison
293
+ d3.selectAll(".state."+allData[i].name[0]+allData[i].name.split(" ")[allData[i].name.split(" ").length-1])
294
+ .attr("stroke-width",3);
295
+ }
296
+ else {
297
+ // toggle the reference
298
+ d3.selectAll(".state."+allData[i].name[0]+allData[i].name.split(" ")[allData[i].name.split(" ").length-1])
299
+ .attr("stroke-width",3);
300
+ }
301
+ }
302
+ else {
303
+ activeHover = true;
304
+ d3.selectAll(".state").attr("stroke-width",0.7);
305
+ }
306
+
307
+ //.text("Average Happiness h").append("tspan").attr("baseline-shift","sub").text("avg");
308
+
309
+
310
+
311
+ // if (shiftRef !== i) {
312
+ // //console.log("reference "+allData[i].name);
313
+ // shiftRef = i;
314
+ // d3.selectAll(".state.map").attr("stroke-width",".7");
315
+ // d3.selectAll(".state.list").attr("stroke","none");
316
+ // d3.selectAll(".state."+allData[i].name[0]+allData[i].name.split(" ")[allData[i].name.split(" ").length-1])
317
+ // .attr("stroke-width",3);
318
+ // }
319
+ // else {
320
+ // //console.log("reference everything");
321
+ // shiftRef = 51;
322
+ // d3.selectAll(".state.map").attr("stroke-width","0.7");
323
+ // d3.selectAll(".state.list").attr("stroke","none");
324
+ // //.attr("stroke-width",3);
325
+ // }
326
+
327
+ // if (shiftRef !== shiftComp) {
328
+ // shiftObj = shift(allData[shiftRef].freq,allData[shiftComp].freq,lens,words);
329
+ // plotShift(d3.select('#shift01'),shiftObj.sortedMag.slice(0,200),
330
+ // shiftObj.sortedType.slice(0,200),
331
+ // shiftObj.sortedWords.slice(0,200),
332
+ // shiftObj.sumTypes,
333
+ // shiftObj.refH,
334
+ // shiftObj.compH);
335
+ // }
336
+ }
337
+
338
+ function state_hover(d,i) {
339
+ var bbox = this.getBBox();
340
+ var x = Math.floor(bbox.x + bbox.width/2.0);
341
+ var y = Math.floor(bbox.y + bbox.height/2.0);
342
+ // console.log(x);
343
+ // console.log(y);
344
+
345
+ var wordsstring = "Words Used: "+commaSeparateNumber(d3.sum(allData[i].freq)),// +"/"+commaSeparateNumber(d3.sum(allData[i].rawFreq)),
346
+ wordsstring2 = "Total Words: "+commaSeparateNumber(d3.sum(allData[i].rawFreq)),
347
+ USwordsstring = "US Words Used: "+commaSeparateNumber(d3.sum(allData[51].freq)),// +"/"+commaSeparateNumber(d3.sum(allData[i].rawFreq)),
348
+ USwordsstring2 = "US Total Words: "+commaSeparateNumber(d3.sum(allData[51].rawFreq)),
349
+ happsstring = "Average Happiness: "+allData[i].avhapps.toFixed(2)
350
+ //hoverboxheight = 115,
351
+ hoverboxheight = 125+51,
352
+ hoverboxwidth = d3.max([wordsstring.width('13px arial'),happsstring.width('15px arial'),wordsstring2.width('13px arial'),USwordsstring.width('13px arial'),USwordsstring2.width('13px arial')])+20,
353
+ hoverboxxoffset = 60;
354
+ var hoverboxyoffset = 30;
355
+
356
+ // if it would wrap it over, move it to the left side
357
+ if ((x+hoverboxwidth+hoverboxxoffset)>w) {
358
+ hoverboxxoffset = -hoverboxxoffset-hoverboxwidth;
359
+ }
360
+
361
+ // if it would wrap it over, move it to the left side
362
+ if ((y-hoverboxheight/2-hoverboxyoffset)<0) {
363
+ hoverboxyoffset = -30;
364
+ }
365
+
366
+ var hovergroup = canvas.append("g").attr({
367
+ "class": "hoverinfogroup",
368
+ "transform": "translate("+(x+hoverboxxoffset)+","+(y-hoverboxheight/2-hoverboxyoffset)+")",});
369
+
370
+ var hoverbox = hovergroup.append("rect").attr({
371
+ "class": "hoverinfobox",
372
+ "x": 0,
373
+ "y": 0,
374
+ "width": hoverboxwidth,
375
+ "height": hoverboxheight,
376
+ "fill": "white",
377
+ "stroke": "black",
378
+ });
379
+
380
+ hovergroup.append("text").attr({
381
+ "class": "hoverinfotext",
382
+ "x": 10,
383
+ "y": 15,
384
+ "font-size": 15,
385
+ })
386
+ .text(allData[i].name);
387
+
388
+ hovergroup.append("line").attr({
389
+ "class": "hoverinfotext",
390
+ "x": 10,
391
+ "y": 15,
392
+ "font-size": 15,
393
+ })
394
+ .text(allData[i].name);
395
+
396
+ hovergroup.append("text").attr({
397
+ "class": "hoverinfotext",
398
+ "x": 10,
399
+ //"y": 55,
400
+ "y": 38,
401
+ "font-size": 17,
402
+ })
403
+ .text("Rank:"); // +"/51");
404
+
405
+ hovergroup.append("text").attr({
406
+ "class": "hoverinfotext",
407
+ "x": 59,
408
+ "y": 55,
409
+ "font-size": 40,
410
+ })
411
+ .text(sortedStateList[i]); // +"/51");
412
+
413
+ hovergroup.append("text").attr({
414
+ "class": "hoverinfotext",
415
+ "x": 105,
416
+ "y": 56,
417
+ "font-size": 20,
418
+ })
419
+ .text("out of 51");
420
+
421
+ hovergroup.append("text").attr({
422
+ "class": "hoverinfotext",
423
+ "x": 10,
424
+ //"y": 73,
425
+ "y": 79,
426
+ "font-size": 15,
427
+ })
428
+ .text(happsstring);
429
+
430
+ hovergroup.append("text").attr({
431
+ "class": "hoverinfotext",
432
+ "x": 10,
433
+ //"y": 89,
434
+ "y": 97,
435
+ "font-size": 13,
436
+ })
437
+ .text(wordsstring);
438
+
439
+ hovergroup.append("text").attr({
440
+ "class": "hoverinfotext",
441
+ "x": 10,
442
+ //"y": 106,
443
+ "y": 114,
444
+ "font-size": 13,
445
+ })
446
+ .text(wordsstring2);
447
+
448
+ hovergroup.append("text").attr({
449
+ "class": "hoverinfotext",
450
+ "x": 10,
451
+ //"y": 106,
452
+ "y": 131,
453
+ "font-size": 13,
454
+ })
455
+ .text("US Average Happiness: "+allData[51].avhapps.toFixed(2));
456
+
457
+ hovergroup.append("text").attr({
458
+ "class": "hoverinfotext",
459
+ "x": 10,
460
+ //"y": 89,
461
+ "y": 97+51,
462
+ "font-size": 13,
463
+ })
464
+ .text(USwordsstring);
465
+
466
+ hovergroup.append("text").attr({
467
+ "class": "hoverinfotext",
468
+ "x": 10,
469
+ //"y": 106,
470
+ "y": 114+51,
471
+ "font-size": 13,
472
+ })
473
+ .text(USwordsstring2);
474
+
475
+ if (activeHover) {
476
+ if (stateSelType) {
477
+ shiftComp = i;
478
+ d3.select(".complabel").text(allData[i].name);
479
+ compencoder.varval(allData[i].name);
480
+ }
481
+ else {
482
+ shiftRef = i;
483
+ d3.select(".reflabel").text(allData[i].name);
484
+ refencoder.varval(allData[i].name);
485
+ }
486
+
487
+ // next line verifies that the data and json line up
488
+ // console.log(d.properties.name); console.log(allData[i].name.split(" ")[allData[i].name.split(" ").length-1]);
489
+ d3.selectAll(".state."+allData[i].name[0]+allData[i].name.split(" ")[allData[i].name.split(" ").length-1]).style("fill","#428bca");
490
+
491
+ if (shiftRef !== shiftComp) {
492
+ hedotools.shifter.shift(allData[shiftRef].freq,allData[shiftComp].freq,lens,words);
493
+ var happysad = hedotools.shifter._compH() > hedotools.shifter._refH() ? "happier" : "less happy";
494
+ hedotools.shifter.setfigure(d3.select('#shift01')).setText(["Why "+allData[shiftComp].name+" is "+happysad+" than "+allData[shiftRef].name+":"]).plot();
495
+ }
496
+ }
497
+ }
498
+
499
+ function state_unhover(d,i) {
500
+
501
+ d3.select(".hoverinfogroup").remove();
502
+
503
+ if (activeHover) {
504
+ // next line verifies that the data and json line up
505
+ // console.log(d.properties.name); console.log(allData[i].name.split(" ")[allData[i].name.split(" ").length-1]);
506
+ // shiftComp = i;
507
+ //console.log(".state.list."+allData[i].name[0]+allData[i].name.split(" ")[allData[i].name.split(" ").length-1]);
508
+ //d3.selectAll(".state.list."+allData[i].name[0]+allData[i].name.split(" ")[allData[i].name.split(" ").length-1])
509
+ //.style("fill",null);
510
+ d3.select(this)
511
+ .style("fill",null);
512
+ }
513
+ }
514
+
515
+ function resizemap() {
516
+ w = parseInt(figure.style('width'));
517
+ h = w*650/900;
518
+ projection.translate([w/2, h/2]).scale(w*1.3);
519
+ canvas.selectAll("path").attr("d",path);
520
+ canvas.attr("width",w).attr("height",h);
521
+ };
522
+
523
+ d3.select(window).on("resize.map",resizemap);
524
+
525
+ };
526
+
527
+
528
+ /*
529
+ * Converts an HSL color value to RGB. Conversion formula
530
+ * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
531
+ * Assumes h, s, and l are contained in the set [0, 1] and
532
+ * returns r, g, and b in the set [0, 255].
533
+ *
534
+ * @param Number h The hue
535
+ * @param Number s The saturation
536
+ * @param Number l The lightness
537
+ * @return Array The RGB representation
538
+ */
539
+ function hslToRgb(h, s, l){
540
+ var r, g, b;
541
+
542
+ if(s == 0){
543
+ r = g = b = l; // achromatic
544
+ }else{
545
+ function hue2rgb(p, q, t){
546
+ if(t < 0) t += 1;
547
+ if(t > 1) t -= 1;
548
+ if(t < 1/6) return p + (q - p) * 6 * t;
549
+ if(t < 1/2) return q;
550
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
551
+ return p;
552
+ }
553
+
554
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
555
+ var p = 2 * l - q;
556
+ r = hue2rgb(p, q, h + 1/3);
557
+ g = hue2rgb(p, q, h);
558
+ b = hue2rgb(p, q, h - 1/3);
559
+ }
560
+
561
+ return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
562
+ }
563
+
564
+ var opublic = { setfigure: setfigure,
565
+ setdata: setdata,
566
+ plot: plot, };
567
+
568
+ return opublic;
569
+
570
+ };
571
+
572
+
573
+
574
+
575
+
576
+