@andyreagan/hedotools 7.1.0 → 7.2.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.
package/README.md CHANGED
@@ -90,49 +90,59 @@ hedotools.shifter
90
90
  See the [d3-shifterator README](https://github.com/andyreagan/d3-shifterator)
91
91
  for the full shifter API and a [live Observable example](https://observablehq.com/@andyreagan/d3-shifterator-v4).
92
92
 
93
+ Each module is an **invoked singleton** on the `hedotools` namespace (like
94
+ `hedotools.shifter`) — use it directly, don't call it as a factory:
95
+
93
96
  ### barchart
94
97
 
95
98
  ```js
96
- var bc = hedotools.barchart();
97
- bc.setfigure(d3.select("#barchart"));
98
- bc.setdata(data, geodata); // data: per-state values; geodata: geojson w/ properties.name
99
- bc._figheight(400);
100
- bc.plot();
99
+ hedotools.barchart.setfigure(d3.select("#barchart"));
100
+ hedotools.barchart.setdata(data, geodata); // data: per-state values; geodata: geojson w/ properties.name
101
+ hedotools.barchart._figheight(400);
102
+ hedotools.barchart.plot();
101
103
  ```
102
104
 
103
105
  ### map
104
106
 
105
107
  ```js
106
- var m = hedotools.map();
107
- m.setfigure(d3.select("#map"));
108
- m.setdata(geoJson); // us-states topojson
109
- m.plot();
108
+ hedotools.map.setfigure(d3.select("#map"));
109
+ hedotools.map.setdata(geoJson); // us-states topojson
110
+ hedotools.map.plot();
110
111
  ```
111
112
 
112
113
  ### lens
113
114
 
114
115
  ```js
115
- var l = hedotools.lens();
116
- l.setfigure(d3.select("#lens"));
117
- l.setdata(lens); // array of word-happiness scores
118
- l.plot();
116
+ hedotools.lens.setfigure(d3.select("#lens"));
117
+ hedotools.lens.setdata(lens); // array of word-happiness scores
118
+ hedotools.lens.plot();
119
119
  ```
120
120
 
121
+ The lens uses `hedotools.urllib` (bundled) to persist its range in the URL, and
122
+ its brush-move callback recomputes state happiness via `hedotools.computeHapps`
123
+ (also bundled) before redrawing the map/shift. Load the full bundle, or the
124
+ individual sources with `urllib` and `computeHapps` before `lens`.
125
+
121
126
  ### sankey
122
127
 
123
128
  ```js
124
- var s = hedotools.sankey();
125
- s.setfigure(d3.select("#sankey"));
126
- s.setdata(oldlist, newlist, stateNames); // two happiness vectors + names
127
- s.plot();
129
+ hedotools.sankey.setfigure(d3.select("#sankey"));
130
+ hedotools.sankey.setdata(oldlist, newlist, stateNames); // two happiness vectors + names
131
+ hedotools.sankey.plot();
128
132
  ```
129
133
 
130
- > **Note:** unlike the shifter, the four dashboard modules were written for the
134
+ `hedotools.nonsankey.js` is an alternate implementation (the cities-page
135
+ variant) that **also** defines `hedotools.sankey` — load it *instead of*
136
+ `hedotools.sankey.js`, never alongside. It ships as a loose file and is not in
137
+ the default bundle.
138
+
139
+ > **Note:** unlike the shifter, the dashboard modules were written for the
131
140
  > hedonometer.org pages and read page-level globals (e.g. `allData`, `lens`,
132
141
  > `words`, `shiftRef`/`shiftComp`, and the url encoders) in their interaction
133
142
  > handlers, where hovering/clicking drives a linked shift. They render
134
- > standalone from `setdata(...).plot()`, but the hover→shift wiring expects
135
- > those globals to be present. See `tests/browser/` for working fixtures.
143
+ > standalone from `setdata(...).plot()`, but the hover→shift wiring (and
144
+ > barchart's mousedown click-to-open) expects those globals to be present. See
145
+ > `tests/browser/` for working fixtures.
136
146
 
137
147
  ## Developing
138
148
 
package/bundle.sh CHANGED
@@ -22,9 +22,13 @@ here="$(cd "$(dirname "$0")" && pwd)"
22
22
  cd "$here"
23
23
  mkdir -p dist
24
24
 
25
+ # hedotools.nonsankey.js is deliberately NOT bundled: it is an alternate that
26
+ # also defines `hedotools.sankey` (the cities-page variant), so it is loaded
27
+ # INSTEAD of hedotools.sankey.js, never alongside it. It ships as a loose file.
25
28
  cat \
26
29
  js/hedotools.init.v4.js \
27
30
  js/hedotools.urllib.js \
31
+ js/hedotools.computeHapps.js \
28
32
  js/hedotools.barchart.js \
29
33
  js/hedotools.lens.js \
30
34
  js/hedotools.map.js \
@@ -3134,6 +3134,24 @@ hedotools.urllib = {
3134
3134
 
3135
3135
 
3136
3136
 
3137
+ hedotools.computeHapps = function() {
3138
+ var go = function () {
3139
+ for (var j=0; j<52; j++) {
3140
+ // compute total frequency
3141
+ var N = 0.0;
3142
+ for (var i=0; i<allData[j].freq.length; i++) {
3143
+ N += parseFloat(allData[j].freq[i]);
3144
+ }
3145
+ var happs = 0.0;
3146
+ for (var i=0; i<allData[j].freq.length; i++) {
3147
+ happs += parseFloat(allData[j].freq[i])*parseFloat(lens[i]);
3148
+ }
3149
+ allData[j].avhapps = happs/N;
3150
+ }
3151
+ }
3152
+ var opublic = { go: go, };
3153
+ return opublic;
3154
+ }();
3137
3155
  hedotools.barchartoncall = function() {
3138
3156
  var test = function(d,i) {
3139
3157
  // console.log(i);
@@ -3160,6 +3178,16 @@ hedotools.barchartoncall = function() {
3160
3178
  return opublic;
3161
3179
  }();
3162
3180
 
3181
+ // mousedown ("click-to-open") hook: an empty stub by default; the host page
3182
+ // overrides hedotools.barchartonclick.test to open the linked shift/modal.
3183
+ hedotools.barchartonclick = function() {
3184
+ var test = function(event,d) {
3185
+ }
3186
+ var opublic = { test: test,
3187
+ };
3188
+ return opublic;
3189
+ }();
3190
+
3163
3191
  // make the plot
3164
3192
  hedotools.barchart = function() {
3165
3193
  var figure;
@@ -3407,6 +3435,9 @@ hedotools.barchart = function() {
3407
3435
  .on('mouseout', function(event,d){
3408
3436
  var rectSelection = d3.select(this).style('opacity','1.0').style('stroke','rgb(100,100,100)').style('stroke-width','1.0');
3409
3437
  // var rectSelection = d3.select(this).style({opacity:'0.7'});
3438
+ })
3439
+ .on('mousedown', function(event,d){
3440
+ hedotools.barchartonclick.test(d,d[0]);
3410
3441
  });
3411
3442
 
3412
3443
  axes.selectAll("text.statetext")
@@ -3420,6 +3451,9 @@ hedotools.barchart = function() {
3420
3451
  .text(function(d,i) { return (i+1)+". "+d[2]; })
3421
3452
  .on('mouseover', function(event,d){
3422
3453
  hedotools.barchartoncall.test(d,d[0]);
3454
+ })
3455
+ .on('mousedown', function(event,d){
3456
+ hedotools.barchartonclick.test(d,d[0]);
3423
3457
  });
3424
3458
 
3425
3459
  // d3.select(window).on("resize.shiftplot",resizeshift);
@@ -3470,7 +3504,7 @@ hedotools.barchart = function() {
3470
3504
  plot: plot, };
3471
3505
 
3472
3506
  return opublic;
3473
- };
3507
+ }();
3474
3508
 
3475
3509
 
3476
3510
 
@@ -3827,7 +3861,7 @@ hedotools.lens = function() {
3827
3861
  };
3828
3862
 
3829
3863
  return opublic;
3830
- };
3864
+ }();
3831
3865
  hedotools.map = function() {
3832
3866
 
3833
3867
  var figure;
@@ -4382,7 +4416,7 @@ hedotools.map = function() {
4382
4416
 
4383
4417
  return opublic;
4384
4418
 
4385
- };
4419
+ }();
4386
4420
 
4387
4421
 
4388
4422
 
@@ -4935,7 +4969,7 @@ hedotools.sankey = function() {
4935
4969
  };
4936
4970
 
4937
4971
  return opublic;
4938
- };
4972
+ }();
4939
4973
 
4940
4974
 
4941
4975
 
package/dist/hedotools.js CHANGED
@@ -253,6 +253,24 @@ hedotools.urllib = {
253
253
 
254
254
 
255
255
 
256
+ hedotools.computeHapps = function() {
257
+ var go = function () {
258
+ for (var j=0; j<52; j++) {
259
+ // compute total frequency
260
+ var N = 0.0;
261
+ for (var i=0; i<allData[j].freq.length; i++) {
262
+ N += parseFloat(allData[j].freq[i]);
263
+ }
264
+ var happs = 0.0;
265
+ for (var i=0; i<allData[j].freq.length; i++) {
266
+ happs += parseFloat(allData[j].freq[i])*parseFloat(lens[i]);
267
+ }
268
+ allData[j].avhapps = happs/N;
269
+ }
270
+ }
271
+ var opublic = { go: go, };
272
+ return opublic;
273
+ }();
256
274
  hedotools.barchartoncall = function() {
257
275
  var test = function(d,i) {
258
276
  // console.log(i);
@@ -279,6 +297,16 @@ hedotools.barchartoncall = function() {
279
297
  return opublic;
280
298
  }();
281
299
 
300
+ // mousedown ("click-to-open") hook: an empty stub by default; the host page
301
+ // overrides hedotools.barchartonclick.test to open the linked shift/modal.
302
+ hedotools.barchartonclick = function() {
303
+ var test = function(event,d) {
304
+ }
305
+ var opublic = { test: test,
306
+ };
307
+ return opublic;
308
+ }();
309
+
282
310
  // make the plot
283
311
  hedotools.barchart = function() {
284
312
  var figure;
@@ -526,6 +554,9 @@ hedotools.barchart = function() {
526
554
  .on('mouseout', function(event,d){
527
555
  var rectSelection = d3.select(this).style('opacity','1.0').style('stroke','rgb(100,100,100)').style('stroke-width','1.0');
528
556
  // var rectSelection = d3.select(this).style({opacity:'0.7'});
557
+ })
558
+ .on('mousedown', function(event,d){
559
+ hedotools.barchartonclick.test(d,d[0]);
529
560
  });
530
561
 
531
562
  axes.selectAll("text.statetext")
@@ -539,6 +570,9 @@ hedotools.barchart = function() {
539
570
  .text(function(d,i) { return (i+1)+". "+d[2]; })
540
571
  .on('mouseover', function(event,d){
541
572
  hedotools.barchartoncall.test(d,d[0]);
573
+ })
574
+ .on('mousedown', function(event,d){
575
+ hedotools.barchartonclick.test(d,d[0]);
542
576
  });
543
577
 
544
578
  // d3.select(window).on("resize.shiftplot",resizeshift);
@@ -589,7 +623,7 @@ hedotools.barchart = function() {
589
623
  plot: plot, };
590
624
 
591
625
  return opublic;
592
- };
626
+ }();
593
627
 
594
628
 
595
629
 
@@ -946,7 +980,7 @@ hedotools.lens = function() {
946
980
  };
947
981
 
948
982
  return opublic;
949
- };
983
+ }();
950
984
  hedotools.map = function() {
951
985
 
952
986
  var figure;
@@ -1501,7 +1535,7 @@ hedotools.map = function() {
1501
1535
 
1502
1536
  return opublic;
1503
1537
 
1504
- };
1538
+ }();
1505
1539
 
1506
1540
 
1507
1541
 
@@ -2054,7 +2088,7 @@ hedotools.sankey = function() {
2054
2088
  };
2055
2089
 
2056
2090
  return opublic;
2057
- };
2091
+ }();
2058
2092
 
2059
2093
 
2060
2094
 
@@ -24,6 +24,16 @@ hedotools.barchartoncall = function() {
24
24
  return opublic;
25
25
  }();
26
26
 
27
+ // mousedown ("click-to-open") hook: an empty stub by default; the host page
28
+ // overrides hedotools.barchartonclick.test to open the linked shift/modal.
29
+ hedotools.barchartonclick = function() {
30
+ var test = function(event,d) {
31
+ }
32
+ var opublic = { test: test,
33
+ };
34
+ return opublic;
35
+ }();
36
+
27
37
  // make the plot
28
38
  hedotools.barchart = function() {
29
39
  var figure;
@@ -271,6 +281,9 @@ hedotools.barchart = function() {
271
281
  .on('mouseout', function(event,d){
272
282
  var rectSelection = d3.select(this).style('opacity','1.0').style('stroke','rgb(100,100,100)').style('stroke-width','1.0');
273
283
  // var rectSelection = d3.select(this).style({opacity:'0.7'});
284
+ })
285
+ .on('mousedown', function(event,d){
286
+ hedotools.barchartonclick.test(d,d[0]);
274
287
  });
275
288
 
276
289
  axes.selectAll("text.statetext")
@@ -284,6 +297,9 @@ hedotools.barchart = function() {
284
297
  .text(function(d,i) { return (i+1)+". "+d[2]; })
285
298
  .on('mouseover', function(event,d){
286
299
  hedotools.barchartoncall.test(d,d[0]);
300
+ })
301
+ .on('mousedown', function(event,d){
302
+ hedotools.barchartonclick.test(d,d[0]);
287
303
  });
288
304
 
289
305
  // d3.select(window).on("resize.shiftplot",resizeshift);
@@ -334,7 +350,7 @@ hedotools.barchart = function() {
334
350
  plot: plot, };
335
351
 
336
352
  return opublic;
337
- };
353
+ }();
338
354
 
339
355
 
340
356
 
@@ -0,0 +1,18 @@
1
+ hedotools.computeHapps = function() {
2
+ var go = function () {
3
+ for (var j=0; j<52; j++) {
4
+ // compute total frequency
5
+ var N = 0.0;
6
+ for (var i=0; i<allData[j].freq.length; i++) {
7
+ N += parseFloat(allData[j].freq[i]);
8
+ }
9
+ var happs = 0.0;
10
+ for (var i=0; i<allData[j].freq.length; i++) {
11
+ happs += parseFloat(allData[j].freq[i])*parseFloat(lens[i]);
12
+ }
13
+ allData[j].avhapps = happs/N;
14
+ }
15
+ }
16
+ var opublic = { go: go, };
17
+ return opublic;
18
+ }();
@@ -345,4 +345,4 @@ hedotools.lens = function() {
345
345
  };
346
346
 
347
347
  return opublic;
348
- };
348
+ }();
@@ -552,7 +552,7 @@ hedotools.map = function() {
552
552
 
553
553
  return opublic;
554
554
 
555
- };
555
+ }();
556
556
 
557
557
 
558
558
 
@@ -0,0 +1,580 @@
1
+ hedotools.sankeyoncall = function() {
2
+ var test = function(i,data) {
3
+ console.log("set in module");
4
+
5
+ console.log(allDataOld);
6
+
7
+ var shiftObj = hedotools.shifter.shift(allDataOld[data[i].index].freq,allData[data[i].index].freq,lens,words);
8
+
9
+ shiftObj.setfigure(d3.select('#shift01')).setText("Why "+data[i].name+" has become "+((allDataOld[data[i].index].avhapps < allData[data[i].index].avhapps) ? "happier" : "less happy")+":").plot();
10
+
11
+
12
+ }
13
+ var opublic = { test: test, };
14
+ return opublic;
15
+ }();
16
+
17
+ hedotools.sankey = function() {
18
+
19
+ var popuptimer;
20
+
21
+ var figure;
22
+
23
+ var setfigure = function(_) {
24
+ console.log("setting figure");
25
+ figure = _;
26
+ // grabwidth();
27
+ return hedotools.sankey;
28
+ }
29
+
30
+ var oldlist;
31
+ var newlist;
32
+ var stateNames;
33
+
34
+ var oldindices;
35
+ var newindices;
36
+ var data;
37
+
38
+ var setdata = function(a,b,c) {
39
+ oldlist = a;
40
+ newlist = b;
41
+ stateNames = c;
42
+ if ( stateNames[50] === "District of Columbia" ) {
43
+ stateNames[50] = "DC";
44
+ }
45
+
46
+ // do the sorting
47
+ oldindices = Array(oldlist.length);
48
+ for (var i = 0; i < oldlist.length; i++) { oldindices[i] = i; }
49
+
50
+ // sort by abs magnitude
51
+ // oldindices.sort(function(a,b) { return Math.abs(data[a]) < Math.abs(data[b]) ? 1 : Math.abs(data[a]) > Math.abs(data[b]) ? -1 : 0; });
52
+
53
+ // sort by magnitude, parity preserving
54
+ oldindices.sort(function(a,b) { return oldlist[a] < oldlist[b] ? 1 : oldlist[a] > oldlist[b] ? -1 : 0; });
55
+
56
+ // do the sorting on new data
57
+ newindices = Array(newlist.length);
58
+ for (var i = 0; i < newlist.length; i++) { newindices[i] = i; }
59
+
60
+ newindices.sort(function(a,b) { return newlist[a] < newlist[b] ? 1 : newlist[a] > newlist[b] ? -1 : 0; });
61
+
62
+ data = Array(oldlist.length);
63
+ for (var i=0; i<data.length; i++) {
64
+ data[i] = {
65
+ "name": stateNames[i],
66
+ "index": i,
67
+ "oldindex": oldindices.indexOf(i),
68
+ "newindex": newindices.indexOf(i),
69
+ "change": newlist[i]-oldlist[i],
70
+ "oldhapps": oldlist[i],
71
+ "newhapps": newlist[i],
72
+ };
73
+ }
74
+
75
+ // console.log(data);
76
+ // tmpglob = data;
77
+
78
+ return hedotools.sankey;
79
+ }
80
+
81
+ // initialize everything so other function in this module have access
82
+ var margin;
83
+ var axeslabelmargin;
84
+ var figwidth;
85
+ var aspectRatio;
86
+ var figheight;
87
+ var width;
88
+ var height;
89
+ var figcenter;
90
+ var leftOffsetStatic;
91
+
92
+ var canvas;
93
+ var x;
94
+ var y;
95
+ var axes;
96
+
97
+ var oldstateselection;
98
+ var newstateselction;
99
+ var path;
100
+ var sankeydata;
101
+ var pathwidth;
102
+ var pathselection;
103
+
104
+ var listlabels;
105
+ var extraSideWidth = [0,0];
106
+
107
+ var useTip = false;
108
+ var tip;
109
+
110
+ var minwidth = 450;
111
+
112
+ // make the plot
113
+ var plot = function() {
114
+ margin = {top: 0, right: 0, bottom: 0, left: 0};
115
+ axeslabelmargin = {top: 0, right: 0+extraSideWidth[0], bottom: 0, left: 0+extraSideWidth[1]};
116
+ figwidth = parseInt(figure.style('width')) - margin.left - margin.right;
117
+ if (figwidth<minwidth) {
118
+ console.log("width is too small...");
119
+ d3.selectAll(".reftimelabel,.comptimelabel,.reftimelabelbottom,.comptimelabelbottom").remove();
120
+ figure.append("text").text("Unfortunately, this visualization will look terrible on your device. If you're on a phone, try rotating and refreshing, or looking from a desktop. Thanks :)");
121
+ return hedotools.sankey;
122
+ }
123
+ aspectRatio = 1.8+3.4*(oldlist.length-51)/(304-51);
124
+ figheight = parseInt(figure.style('width'))*aspectRatio - margin.top - margin.bottom;
125
+ // console.log("figheight is "+figheight);
126
+ // figheight = 4576; // for the city sankey this seems good
127
+ width = figwidth-axeslabelmargin.left-axeslabelmargin.right;
128
+ height = figheight-axeslabelmargin.top-axeslabelmargin.bottom;
129
+ figcenter = width/2;
130
+ leftOffsetStatic = axeslabelmargin.left;
131
+
132
+ var hovergroup = figure.append("div").attr("class", "hoverinfogroup")
133
+ // .style("transform", "translate("+(x+hoverboxxoffset+axeslabelmargin.left)+","+(d3.min([d3.max([0,y-hoverboxheight/2-hoverboxyoffset]),height-hoverboxheight]))+")")
134
+ .style("position", "absolute")
135
+ .style("top", "100px")
136
+ .style("left", "100px")
137
+ .style("visibility", "hidden");
138
+
139
+ function hidehover() {
140
+ console.log("hiding hover");
141
+ hovergroup.style("visibility", "hidden");
142
+ }
143
+
144
+ // remove an old figure if it exists
145
+ figure.select(".canvas").remove();
146
+
147
+ canvas = figure.append("svg")
148
+ .attr("width",figwidth)
149
+ .attr("height",figheight)
150
+ .attr("class","canvas")
151
+
152
+ // x scale, maps all the data to
153
+ x = d3.scaleLinear()
154
+ .domain([0,1])
155
+ .range([5,width-10]);
156
+
157
+ // linear scale function
158
+ y = d3.scaleLinear()
159
+ .domain([newlist.length,1])
160
+ .range([height-20, 0]);
161
+
162
+ // create the axes themselves
163
+ axes = canvas.append("g")
164
+ .attr("transform", "translate(" + (axeslabelmargin.left) + "," +
165
+ (axeslabelmargin.top) + ")")
166
+ .attr("width", width)
167
+ .attr("height", height)
168
+ .attr("class", "main");
169
+
170
+ // if (useTip) {
171
+ // console.log("setting tip");
172
+ // tip = d3.tip().attr('class', 'd3-tip').html(function(d) { return d; });
173
+ // axes.call(tip);
174
+ // }
175
+
176
+ oldstateselection = axes.selectAll("text.statetext.old")
177
+ .data(data)
178
+ .enter()
179
+ .append("text")
180
+ .attr("class", function(d,i) { return d.name+" statetext"; })
181
+ .attr("x",20)
182
+ .style("text-anchor", "start")
183
+ .attr("y",function(d,i) { return y(d.oldindex+1)+11; } )
184
+ .text(function(d,i) { return (d.oldindex+1)+". "+d.name; })
185
+ .on("mouseover", function(event, d) {
186
+ var i = d.index;
187
+ var hoverboxheight = 90;
188
+ var hoverboxwidth = 200;
189
+ var hoverboxyoffset = 0;
190
+ var hoverboxxoffset = 0;
191
+
192
+ var x = d3.pointer(event, this)[0];
193
+ var y = d3.pointer(event, this)[1];
194
+
195
+ var hoverboxheightguess = 190;
196
+ if (refcity.length > 0) {
197
+ hoverboxheightguess = 270;
198
+ }
199
+ if ((y+hoverboxheightguess)>height) { y-=(y+hoverboxheightguess-height); }
200
+
201
+ hovergroup.style("position", "absolute")
202
+ .style("top", y+"px")
203
+ .style("left", x+"px")
204
+ .style("visibility", "visible");
205
+
206
+ hovergroup.selectAll("p,h3,button,br").remove();
207
+
208
+ hovergroup.append("h3")
209
+ .attr("class","cityname")
210
+ .text(d.name);
211
+
212
+ hovergroup.append("p")
213
+ .attr("class","refhapps")
214
+ .text(reftimeseldecoder().cached+" Happiness: "+parseFloat(d.oldhapps).toFixed(2));
215
+
216
+ hovergroup.append("p")
217
+ .attr("class","refrank")
218
+ .text(reftimeseldecoder().cached+" Rank: "+(d.oldindex+1));
219
+
220
+ hovergroup.append("p")
221
+ .attr("class","comphapps")
222
+ .text(comptimeseldecoder().cached+" Happiness: "+parseFloat(d.newhapps).toFixed(2));
223
+
224
+ hovergroup.append("p")
225
+ .attr("class","comprank")
226
+ .text(comptimeseldecoder().cached+" Rank: "+(d.newindex+1));
227
+
228
+ var popupshift = function(refyear,refname,compyear,compname) {
229
+ refshifttimeencoder.varval(refyear);
230
+ refshiftcityencoder.varval(refname);
231
+ compshifttimeencoder.varval(compyear);
232
+ compshiftcityencoder.varval(compname);
233
+ // write a function to call on the load
234
+ drawShift = function() {
235
+ hedotools.shifter._refF(refF);
236
+ hedotools.shifter._compF(compF);
237
+ hedotools.shifter.stop();
238
+ hedotools.shifter.shifter();
239
+ hedotools.shifter.setText("Why "+compname+" in "+compyear+" is "+( ( hedotools.shifter._compH() > hedotools.shifter._refH() ) ? "happier" : "less happy" )+" than "+refname+" in "+refyear+":").plot();
240
+ $('#myModal').modal('show');
241
+ }
242
+ // load both of the files
243
+ var csvLoadsRemaining = 2;
244
+ var reffile = "https://hedonometer.org/data/cities/word-vectors/"+refyear+"/"+refname+".csv";
245
+ if (parseInt(refyear) < 2014) reffile+=".new"
246
+ var compfile = "https://hedonometer.org/data/cities/word-vectors/"+compyear+"/"+compname+".csv";
247
+ if (parseInt(compyear) < 2014) compfile+=".new"
248
+ console.log(reffile);
249
+ console.log(compfile);
250
+ var refF;
251
+ var compF;
252
+ d3.text(reffile).then(function(text) {
253
+ refF = text.split(",");
254
+ console.log(refF);
255
+ if (!--csvLoadsRemaining) drawShift();
256
+ });
257
+ d3.text(compfile).then(function(text) {
258
+ compF = text.split(",");
259
+ console.log(compF);
260
+ if (!--csvLoadsRemaining) drawShift();
261
+ });
262
+ }
263
+
264
+ hovergroup.append("button")
265
+ .attr("class","btn btn-sm btn-primary")
266
+ .text("Shift city vs previous year")
267
+ .on("click", function() {
268
+ console.log(d);
269
+ console.log(i);
270
+ popupshift(reftimeseldecoder().cached,d.name,comptimeseldecoder().cached,d.name);
271
+ });
272
+
273
+ hovergroup.append("br");
274
+ hovergroup.append("br");
275
+
276
+ hovergroup.append("button")
277
+ .attr("class","btn btn-sm btn-primary")
278
+ .text("Shift city in "+reftimeseldecoder().cached+" vs sum "+reftimeseldecoder().cached)
279
+ .on("click", function() {
280
+ console.log(d);
281
+ console.log(i);
282
+ popupshift(reftimeseldecoder().cached,"US",reftimeseldecoder().cached,d.name);
283
+ });
284
+
285
+ hovergroup.append("br");
286
+ hovergroup.append("br");
287
+
288
+ hovergroup.append("button")
289
+ .attr("class","btn btn-sm btn-primary")
290
+ .text("Shift city in "+comptimeseldecoder().cached+" vs sum "+comptimeseldecoder().cached)
291
+ .on("click", function() {
292
+ console.log(d);
293
+ console.log(i);
294
+ popupshift(comptimeseldecoder().cached,"US",comptimeseldecoder().cached,d.name);
295
+ });
296
+
297
+ hovergroup.append("br");
298
+ hovergroup.append("br");
299
+
300
+
301
+ hovergroup.append("button")
302
+ .attr("class","btn btn-xs btn-primary")
303
+ .text("Select as reference for city-city comparison")
304
+ .on("click", function() {
305
+ console.log(d);
306
+ console.log(i);
307
+ refcity = d.name;
308
+ });
309
+
310
+ if (refcity.length > 0) {
311
+ hovergroup.append("br");
312
+ hovergroup.append("br");
313
+ hovergroup.append("button")
314
+ .attr("class","btn btn-xs btn-primary")
315
+ .text("Compare against "+refcity+" in "+comptimeseldecoder().cached)
316
+ .on("click", function() {
317
+ console.log(d);
318
+ console.log(i);
319
+ popupshift(comptimeseldecoder().cached,refcity,comptimeseldecoder().cached,d.name);
320
+ });
321
+ hovergroup.append("br");
322
+ hovergroup.append("br");
323
+ hovergroup.append("button")
324
+ .attr("class","btn btn-xs btn-primary")
325
+ .text("Compare against "+refcity+" in "+reftimeseldecoder().cached)
326
+ .on("click", function() {
327
+ console.log(d);
328
+ console.log(i);
329
+ popupshift(reftimeseldecoder().cached,refcity,reftimeseldecoder().cached,d.name);
330
+ });
331
+ }
332
+
333
+ clearTimeout(popuptimer);
334
+
335
+ popuptimer = setTimeout(hidehover,3000);
336
+ })
337
+ .on("mouseout", function(event, d) {
338
+ clearTimeout(popuptimer);
339
+
340
+ popuptimer = setTimeout(hidehover,3000);
341
+ });
342
+
343
+ newstateselection = axes.selectAll("text.statetext.new")
344
+ .data(data)
345
+ .enter()
346
+ .append("text")
347
+ .attr("class", function(d,i) { return d.name+" statetext"; })
348
+ .attr("x",300)
349
+ .style("text-anchor", "start")
350
+ .attr("y",function(d,i) { return y(d.newindex+1)+11; } )
351
+ .text(function(d,i) { return (d.newindex+1)+". "+d.name; })
352
+ .on("mouseover", function(event, d) {
353
+ var i = d.index;
354
+ var hoverboxheight = 90;
355
+ var hoverboxwidth = 200;
356
+ var hoverboxyoffset = 0;
357
+ var hoverboxxoffset = 0;
358
+
359
+ var x = d3.pointer(event, this)[0];
360
+ var y = d3.pointer(event, this)[1];
361
+
362
+ var hoverboxheightguess = 190;
363
+ if (refcity.length > 0) {
364
+ hoverboxheightguess = 270;
365
+ }
366
+ if ((y+hoverboxheightguess)>height) { y-=(y+hoverboxheightguess-height); }
367
+
368
+ hovergroup.style("position", "absolute")
369
+ .style("top", y+"px")
370
+ .style("left", x+"px")
371
+ .style("visibility", "visible");
372
+
373
+ hovergroup.selectAll("p,h3,button,br").remove();
374
+
375
+ hovergroup.append("h3")
376
+ .attr("class","cityname")
377
+ .text(d.name);
378
+
379
+ hovergroup.append("p")
380
+ .attr("class","refhapps")
381
+ .text(reftimeseldecoder().cached+" Happiness: "+parseFloat(d.oldhapps).toFixed(2));
382
+
383
+ hovergroup.append("p")
384
+ .attr("class","refrank")
385
+ .text(reftimeseldecoder().cached+" Rank: "+(d.oldindex+1));
386
+
387
+ hovergroup.append("p")
388
+ .attr("class","comphapps")
389
+ .text(comptimeseldecoder().cached+" Happiness: "+parseFloat(d.newhapps).toFixed(2));
390
+
391
+ hovergroup.append("p")
392
+ .attr("class","comprank")
393
+ .text(comptimeseldecoder().cached+" Rank: "+(d.newindex+1));
394
+
395
+ var popupshift = function(refyear,refname,compyear,compname) {
396
+ refshifttimeencoder.varval(refyear);
397
+ refshiftcityencoder.varval(refname);
398
+ compshifttimeencoder.varval(compyear);
399
+ compshiftcityencoder.varval(compname);
400
+ // write a function to call on the load
401
+ drawShift = function() {
402
+ hedotools.shifter._refF(refF);
403
+ hedotools.shifter._compF(compF);
404
+ hedotools.shifter.stop();
405
+ hedotools.shifter.shifter();
406
+ hedotools.shifter.setText("Why "+compname+" in "+compyear+" is "+( ( hedotools.shifter._compH() > hedotools.shifter._refH() ) ? "happier" : "less happy" )+" than "+refname+" in "+refyear+":").plot();
407
+ $('#myModal').modal('show');
408
+ }
409
+ // load both of the files
410
+ var csvLoadsRemaining = 2;
411
+ var reffile = "https://hedonometer.org/data/cities/word-vectors/"+refyear+"/"+refname+".csv";
412
+ if (parseInt(refyear) < 2014) reffile+=".new"
413
+ var compfile = "https://hedonometer.org/data/cities/word-vectors/"+compyear+"/"+compname+".csv";
414
+ if (parseInt(compyear) < 2014) compfile+=".new"
415
+ console.log(reffile);
416
+ console.log(compfile);
417
+ var refF;
418
+ var compF;
419
+ d3.text(reffile).then(function(text) {
420
+ refF = text.split(",");
421
+ console.log(refF);
422
+ if (!--csvLoadsRemaining) drawShift();
423
+ });
424
+ d3.text(compfile).then(function(text) {
425
+ compF = text.split(",");
426
+ console.log(compF);
427
+ if (!--csvLoadsRemaining) drawShift();
428
+ });
429
+ }
430
+
431
+ hovergroup.append("button")
432
+ .attr("class","btn btn-sm btn-primary")
433
+ .text("Shift city vs previous year")
434
+ .on("click", function() {
435
+ console.log(d);
436
+ console.log(i);
437
+ popupshift(reftimeseldecoder().cached,d.name,comptimeseldecoder().cached,d.name);
438
+ });
439
+
440
+ hovergroup.append("br");
441
+ hovergroup.append("br");
442
+
443
+ hovergroup.append("button")
444
+ .attr("class","btn btn-sm btn-primary")
445
+ .text("Shift city in "+reftimeseldecoder().cached+" vs sum "+reftimeseldecoder().cached)
446
+ .on("click", function() {
447
+ console.log(d);
448
+ console.log(i);
449
+ popupshift(reftimeseldecoder().cached,"US",reftimeseldecoder().cached,d.name);
450
+ });
451
+
452
+ hovergroup.append("br");
453
+ hovergroup.append("br");
454
+
455
+ hovergroup.append("button")
456
+ .attr("class","btn btn-sm btn-primary")
457
+ .text("Shift city in "+comptimeseldecoder().cached+" vs sum "+comptimeseldecoder().cached)
458
+ .on("click", function() {
459
+ console.log(d);
460
+ console.log(i);
461
+ popupshift(comptimeseldecoder().cached,"US",comptimeseldecoder().cached,d.name);
462
+ });
463
+
464
+ hovergroup.append("br");
465
+ hovergroup.append("br");
466
+
467
+
468
+ hovergroup.append("button")
469
+ .attr("class","btn btn-xs btn-primary")
470
+ .text("Select as reference for city-city comparison")
471
+ .on("click", function() {
472
+ console.log(d);
473
+ console.log(i);
474
+ refcity = d.name;
475
+ });
476
+
477
+ if (refcity.length > 0) {
478
+ hovergroup.append("br");
479
+ hovergroup.append("br");
480
+ hovergroup.append("button")
481
+ .attr("class","btn btn-xs btn-primary")
482
+ .text("Compare against "+refcity+" in "+comptimeseldecoder().cached)
483
+ .on("click", function() {
484
+ console.log(d);
485
+ console.log(i);
486
+ popupshift(comptimeseldecoder().cached,refcity,comptimeseldecoder().cached,d.name);
487
+ });
488
+ hovergroup.append("br");
489
+ hovergroup.append("br");
490
+ hovergroup.append("button")
491
+ .attr("class","btn btn-xs btn-primary")
492
+ .text("Compare against "+refcity+" in "+reftimeseldecoder().cached)
493
+ .on("click", function() {
494
+ console.log(d);
495
+ console.log(i);
496
+ popupshift(reftimeseldecoder().cached,refcity,reftimeseldecoder().cached,d.name);
497
+ });
498
+ }
499
+
500
+ clearTimeout(popuptimer);
501
+
502
+ popuptimer = setTimeout(hidehover,3000);
503
+ })
504
+ .on("mouseout", function(event, d) {
505
+ clearTimeout(popuptimer);
506
+
507
+ popuptimer = setTimeout(hidehover,3000);
508
+ });
509
+
510
+ return hedotools.sankey;
511
+ };
512
+
513
+ var replot = function() {
514
+ // assuming that the data has been updated
515
+ // console.log(oldstateselection);
516
+ // console.log(newstateselection);
517
+
518
+ console.log(data);
519
+
520
+ oldstateselection.data(data)
521
+ .transition()
522
+ .duration(3000)
523
+ .text(function(d,i) { return (d.oldindex+1)+". "+d.name; })
524
+ .attr("y",function(d,i) { return y(d.oldindex+1)+11; } );
525
+
526
+ newstateselection.data(data)
527
+ .transition()
528
+ .duration(3000)
529
+ .text(function(d,i) { return (d.newindex+1)+". "+d.name; })
530
+ .attr("y",function(d,i) { return y(d.newindex+1)+11; } );
531
+
532
+ return hedotools.sankey;
533
+ };
534
+
535
+ // need functions to access updated properties
536
+ var GETdata = function() {
537
+ return data;
538
+ };
539
+
540
+ var GETnewindices = function() {
541
+ return newindices;
542
+ };
543
+
544
+ var setTitles = function(titles) {
545
+ listlabels = titles;
546
+ return hedotools.sankey;
547
+ };
548
+
549
+ var setSideWidth = function(listTwoByOne) {
550
+ extraSideWidth = listTwoByOne;
551
+ return hedotools.sankey;
552
+ };
553
+
554
+ var setTipOn = function() {
555
+ useTip = true;
556
+ return hedotools.sankey;
557
+ };
558
+
559
+ var opublic = {
560
+ plot: plot,
561
+ setfigure: setfigure,
562
+ setdata: setdata,
563
+ data: GETdata,
564
+ newindices: GETnewindices,
565
+ replot: replot,
566
+ setTitles: setTitles,
567
+ setSideWidth: setSideWidth,
568
+ setTipOn: setTipOn,
569
+ };
570
+
571
+ return opublic;
572
+
573
+ }();
574
+
575
+
576
+
577
+
578
+
579
+
580
+
@@ -544,7 +544,7 @@ hedotools.sankey = function() {
544
544
  };
545
545
 
546
546
  return opublic;
547
- };
547
+ }();
548
548
 
549
549
 
550
550
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andyreagan/hedotools",
3
- "version": "7.1.0",
3
+ "version": "7.2.0",
4
4
  "description": "A collection of D3.js tools in use at hedonometer.org: word shifts (via @andyreagan/d3-shifterator), choropleth maps, sankey diagrams, a frequency lens, and bar charts. Version tracks the supported D3 major version (7.x = D3 v7).",
5
5
  "author": "Andy Reagan",
6
6
  "license": "BSD-2-Clause",