Skip to content

Instantly share code, notes, and snippets.

@ageller
Last active August 12, 2019 16:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ageller/8f947a4cf96d61f144a21ec0adfbea55 to your computer and use it in GitHub Desktop.
Save ageller/8f947a4cf96d61f144a21ec0adfbea55 to your computer and use it in GitHub Desktop.
Interactive Searchable Bar Chart
license: mit
height: 505

Interactive Searchable Bar Chart

  • Clicking on the top row of buttons lets you select subsamples of the data. (This is dummy data, and contains three "types" of elements -- A, B, C, dominated by A and B.)
  • Click on any bar to see the list of data elements in that bin.
  • Use the search box to search for any individual data element by name. (Names for each data element were generated from python's lorem package.)
  • Within panel below the search bar you can click on any data element to see the "type" (e.g., A, B, or C).

Built with blockbuilder.org

institutionname institution_type2 coord1D_horizontal axis
0 Adipisci eius Type A 0.7910933906755007
1 Eius ut Type B -0.14925774579455903
2 Ipsum magnam Type A 0.08642846928856845
3 Dolorem consectetur Type A 0.7957129692529638
4 Modi dolore Type A 0.37401508579943665
5 Non consectetur Type A 0.5049557655574493
6 Sed quisquam Type A 0.12255691115018241
7 Magnam quaerat Type A -0.26974536848965586
8 Labore quiquia Type B 0.3239612823061825
9 Dolore non Type A 0.1881582106366903
10 Ipsum ut Type A 0.8078675134440951
11 Modi non Type A -0.038353201350506405
12 Neque sed Type A 0.6288164004839887
13 Est tempora Type A 0.563040147129356
14 Neque quiquia Type A 0.30092426600176186
15 Dolor magnam Type A 0.11949523262757203
16 Consectetur est Type A 0.48691378912264555
17 Consectetur porro Type A 0.5756239320224645
18 Non dolore Type A 0.7665887755755644
19 Etincidunt velit Type A -0.02951465144427945
20 Labore adipisci Type A 0.19147823455197038
21 Magnam quisquam Type A -0.02062468739022849
22 Etincidunt velit Type A 1.1474841234929427
23 Etincidunt non Type A 0.6119859578091389
24 Voluptatem dolore Type A 0.5371611918593949
25 Numquam quiquia Type A -0.018769491707662178
26 Est quaerat Type A 0.39406631421529814
27 Modi adipisci Type A -0.23555915026475055
28 Sed dolore Type A 0.32862781824346415
29 Quiquia velit Type A -0.19532379444811343
30 Sit voluptatem Type A 0.18610128809036897
31 Adipisci ipsum Type A 0.4258762937384758
32 Neque sit Type A 0.1525327991360421
33 Labore aliquam Type A 0.9016488150839124
34 Adipisci sit Type A 0.32142136245716557
35 Ut dolor Type B -0.8598349620375869
36 Adipisci amet Type B -0.2834219525858179
37 Porro dolorem Type A 0.6168704358178354
38 Amet tempora Type A 0.16758110080886773
39 Labore quaerat Type B -0.6722391854941483
40 Neque voluptatem Type A 0.49397292015493205
41 Dolore amet Type A 0.12879559155007783
42 Sit adipisci Type A 0.204062739024402
43 Ipsum ut Type A 0.27883676971488996
44 Amet modi Type A 0.2921449693648844
45 Adipisci consectetur Type A 0.6978709733170416
46 Dolor adipisci Type B -0.6577332224078045
47 Sit dolore Type A -0.02817449434784386
48 Porro consectetur Type A 0.31059867952618175
49 Velit quiquia Type A 0.19861091403109565
50 Etincidunt ut Type B -0.38582922645420725
51 Numquam dolore Type A 0.2876580193797778
52 Numquam neque Type A -0.6870779551764616
53 Velit quaerat Type A 0.33197360477690246
54 Ut velit Type B -0.6688844315143833
55 Eius aliquam Type A 0.43959139394475744
56 Eius sit Type A 0.49892181082251297
57 Dolorem tempora Type A 0.4042672656078629
58 Velit etincidunt Type A 0.7440157341827411
59 Ut voluptatem Type A -0.08618709769770111
60 Etincidunt ipsum Type A -0.08024196739949152
61 Dolor dolor Type A 0.774867707780841
62 Quiquia est Type A 0.7859763821954038
63 Neque aliquam Type A -0.8254345997277635
64 Magnam etincidunt Type A 0.482519273191858
65 Velit dolore Type A 0.3332870928033144
66 Quiquia sed Type A -0.3243179560342057
67 Labore dolorem Type A 0.505127507584881
68 Voluptatem modi Type A -0.000941284167181422
69 Dolorem modi Type A 0.0536112328911405
70 Magnam quisquam Type A 0.27863134407246676
71 Ipsum voluptatem Type A 0.07912986456603563
72 Ut aliquam Type A 0.27555802441177746
73 Aliquam est Type A 0.055779137141818785
74 Consectetur etincidunt Type A -0.21718219163313696
75 Numquam labore Type A 0.2658963713197317
76 Consectetur modi Type A 1.1138536739229146
77 Quaerat sit Type A -0.16667662016371376
78 Sit dolorem Type A 0.046525319437616175
79 Porro sit Type A -0.3832609749754073
80 Neque ut Type B -0.3944531359935087
81 Velit adipisci Type A 0.8349024936879481
82 Etincidunt dolor Type A 0.4468403227632326
83 Quaerat dolorem Type A 0.3013160026837836
84 Consectetur dolorem Type A 0.032699073878197205
85 Voluptatem dolorem Type A 0.1411215404318208
86 Est ut Type A -0.17776522180028548
87 Numquam numquam Type C 0.045348428756307145
88 Ipsum neque Type A 0.49970753291339437
89 Dolorem non Type A 0.5124274426708867
90 Neque numquam Type A 0.06648744800007547
91 Consectetur dolore Type A 0.31146743704506163
92 Tempora numquam Type A 0.8558255742090726
93 Porro quisquam Type A -0.07852883173619579
94 Sit numquam Type A 0.28245113599435284
95 Ut consectetur Type A 0.4898395164869751
96 Amet numquam Type A 0.41642252628789783
97 Ipsum tempora Type A 1.0213872738705887
98 Quaerat velit Type A 0.25299234050181424
99 Quiquia voluptatem Type A 0.6914613890326158
100 Voluptatem amet Type A -0.06918808290830886
101 Voluptatem labore Type A 0.2604357555935728
102 Amet sit Type B -0.5682064520242658
103 Tempora sed Type A -1.1239982951314418
104 Ipsum amet Type A 0.26738498974902425
105 Amet velit Type A 0.20542693199471396
106 Numquam dolore Type C 1.8697614224318244
107 Quaerat porro Type A -0.0807804151822718
108 Porro etincidunt Type B -0.8614838017639799
109 Modi adipisci Type B -0.9620496396640876
110 Adipisci consectetur Type B -0.5368224583556799
111 Neque non Type B -1.031150382372052
112 Aliquam tempora Type A 0.46967970222735467
113 Quiquia neque Type A -0.12019163994546195
114 Quaerat etincidunt Type A 0.2202353286999323
115 Ipsum aliquam Type A 0.24780354246185632
116 Tempora quisquam Type A 0.2024437472642029
117 Aliquam quaerat Type A 0.4945194369440005
118 Aliquam modi Type A 0.42565911486796904
119 Tempora porro Type A 0.7582562682486726
120 Voluptatem modi Type A 0.9100756072723815
121 Eius etincidunt Type A 0.06267770583041943
122 Ipsum dolore Type A 0.6990859442620351
123 Ut voluptatem Type B -0.046202519521757746
124 Voluptatem est Type A 0.5275981973856413
125 Magnam sed Type A 0.12182098017353912
126 Adipisci ut Type A 0.19211784570589208
127 Amet magnam Type A -0.2340397535106285
128 Ipsum amet Type A -0.5744301116648864
129 Etincidunt adipisci Type A -0.06787223601627995
130 Consectetur non Type A 1.1501438556597818
131 Etincidunt modi Type A 0.3063375218492816
132 Ut quisquam Type A 0.6795747490016977
133 Eius ipsum Type A 0.4436330767033859
134 Eius porro Type B -1.1037023383752904
135 Porro neque Type B -0.5304607990167166
136 Magnam magnam Type A 0.605410077100993
137 Modi adipisci Type A 0.09083413569505192
138 Velit quiquia Type A 0.7516133606871489
139 Quiquia consectetur Type A 0.16750552532206386
140 Voluptatem dolore Type A 0.3877957592223913
141 Consectetur est Type B 0.045777445868829814
142 Quisquam etincidunt Type C 0.17106943447628345
143 Dolor dolorem Type A 0.8498709632796071
144 Non sed Type A 0.36528561206710997
145 Quaerat porro Type A 0.4756867692186103
146 Aliquam sit Type B 0.1635343277830298
147 Aliquam quaerat Type B -0.5631854627543713
148 Velit quisquam Type A 1.021428937462567
149 Ut non Type A 0.024432028158072328
150 Tempora dolor Type A 0.33646558672127685
151 Dolorem dolore Type A 0.8119157928804845
152 Quiquia non Type A 0.6237510951140912
153 Voluptatem non Type A -0.011925458538928402
154 Quisquam ut Type A 0.342752830484897
155 Dolorem quaerat Type A -0.05023909499637119
156 Sed est Type A 0.6283543444135785
157 Velit porro Type A -0.2238221819889425
158 Labore non Type B -0.40113071002463924
159 Quiquia adipisci Type A 0.15910041553732437
160 Ipsum labore Type B -0.787281664274986
161 Adipisci dolor Type B -0.39572927991509677
162 Tempora adipisci Type A -0.3367038253742843
163 Dolor est Type A 0.5458284671563035
164 Dolor dolorem Type A 0.27891840749716895
165 Quaerat sed Type A 0.5877230481668857
166 Quisquam eius Type B -0.549709298367118
167 Sit ipsum Type A -0.2201234119619228
168 Numquam est Type A 0.3263340867392742
169 Voluptatem porro Type B -0.9550198735836251
170 Dolore amet Type A 0.5158105754380929
171 Numquam modi Type A 0.40006662878296056
172 Velit labore Type A -0.12076716628237755
173 Ut est Type A 0.07286452118984468
174 Quisquam non Type A 0.5239851367514172
175 Ut porro Type A -0.06930246718560984
176 Labore quiquia Type A 0.6318909125387228
177 Dolorem dolorem Type B -0.1353727567909186
178 Amet dolor Type B -0.8319179995714352
179 Dolor est Type B -0.5802625517045904
180 Sit sed Type A 0.37172501273180575
181 Quiquia ut Type A -0.6840182232050072
182 Voluptatem adipisci Type A 0.10285251752125713
183 Sit numquam Type A 0.032702949667796355
184 Dolorem adipisci Type A 0.34530971212207473
185 Adipisci consectetur Type A 0.09458789785288774
186 Velit labore Type B -0.8193490764049135
187 Quiquia ipsum Type A 0.27992205147566784
188 Consectetur quaerat Type A 0.6054915351655787
189 Voluptatem velit Type A 0.5323265865193707
190 Adipisci etincidunt Type A -0.34240588687946444
191 Adipisci labore Type A -0.4201510504847093
192 Sed etincidunt Type B -0.9298438851262452
193 Sed quaerat Type B -0.43106549708219305
194 Voluptatem dolore Type A 0.6205036807648928
195 Quiquia quaerat Type A 0.3698233246641922
196 Labore quisquam Type A 0.7840034248156611
197 Sed ipsum Type A 0.968563306124542
198 Neque sit Type A 0.16396402902303886
199 Adipisci porro Type A 0.4191163373010578
200 Voluptatem ipsum Type A 0.952015452167086
201 Sed magnam Type A 0.023526643899838606
202 Consectetur quiquia Type A 0.2899027724979251
203 Dolorem dolor Type A 0.18656457108698543
204 Consectetur amet Type A 0.19379233187930245
205 Neque sed Type A 0.6655323781155558
206 Sed velit Type A 0.8364563755651468
207 Ipsum sit Type A -0.5987935612552817
208 Amet modi Type A 0.739945419049818
209 Adipisci quiquia Type A 0.8795677699138467
210 Dolore quaerat Type A 0.12545671752438492
211 Amet porro Type A 0.5226283069136749
212 Tempora neque Type A 0.17554922866471634
213 Dolorem voluptatem Type A 0.47917667250814794
214 Ipsum velit Type A 1.0164463296226072
215 Quiquia dolorem Type A 0.3337837479780682
216 Quaerat dolore Type A -0.21962840919274546
217 Sit velit Type B -0.47230563059719327
218 Eius aliquam Type A 0.322621810402615
219 Quaerat ut Type A 0.35216358924458574
220 Non quiquia Type A 0.037940685649550776
221 Etincidunt quiquia Type A 0.558708796613595
222 Modi tempora Type A -0.5018250071354258
223 Non numquam Type A 0.027289430319031638
224 Sit dolorem Type B -0.5280967971967051
225 Sed sed Type B -0.6632773810595969
226 Dolor magnam Type B -0.5321458694579602
227 Amet voluptatem Type A 0.6484257019982244
228 Consectetur non Type A 0.46718861316134497
229 Etincidunt dolorem Type A 0.3064044329347137
230 Ut quisquam Type A 0.05463944531572057
231 Non quisquam Type A -0.24662231996491663
232 Dolorem velit Type A 0.6839415792575252
233 Modi amet Type A -0.09712395789871087
234 Neque amet Type B -0.23669074728725942
235 Neque labore Type A 0.3580853071513468
236 Ut ipsum Type A 1.2364924934382036
237 Quiquia voluptatem Type A 0.08023969264354586
238 Magnam modi Type A -0.33525942864365205
239 Magnam quaerat Type A -0.2972686407583655
240 Voluptatem aliquam Type A 0.10769737158269505
241 Aliquam ut Type A 0.16962928893719628
242 Consectetur amet Type A 0.5912575966052951
243 Labore quiquia Type A 0.31101524989361745
244 Numquam est Type A 0.018491553078373413
245 Amet magnam Type A 0.9479154300050039
246 Quiquia neque Type A 0.5814297606057435
247 Porro dolor Type B -0.1720864563544065
248 Amet quisquam Type A 0.229104670029415
249 Dolor aliquam Type B -0.8477442204921737
250 Amet eius Type B -0.06196988088449129
251 Quiquia quisquam Type B -0.5914062030752805
252 Voluptatem non Type B -0.36584756241965943
253 Ipsum magnam Type B -0.40113633184753117
254 Tempora voluptatem Type A 0.35426562405966683
255 Dolore voluptatem Type A 0.0649934188675369
256 Ut magnam Type A 0.06028819854500009
257 Quiquia adipisci Type A 0.2511529373481144
258 Ipsum sit Type A -0.2756809110155178
259 Non non Type B -0.49813840402742576
260 Porro modi Type A 0.3086689801452715
261 Sed consectetur Type A 0.9469962276070325
//see example here: https://www.d3-graph-gallery.com/graph/histogram_basic.html
function binData(type = null){
// set the parameters for the histogram
var histogram = d3.histogram()
.value(function(d){
if (type == null){
return d['coord1D_horizontal axis'];
} else {
if (d['institution_type2'] == type){
return d['coord1D_horizontal axis'];
}
}
}) // I need to give the vector of value
.domain(params.xAxis.domain()) // then the domain of the graphic
.thresholds(params.xAxis.ticks(params.nBins)); // then the numbers of bins
// And apply this function to data to get the bins
return histogram(params.inputData);
}
function createHistogram(){
//create the SVG element
var w = params.histWidth + params.histMargin.left + params.histMargin.right;
var h = params.histHeight + params.histMargin.top + params.histMargin.bottom;
params.svg = d3.select('#histogram')
.append('svg')
.attr('width', w + 'px')
.attr('height', h + 'px')
.append('g')
.attr('transform', 'translate(' + params.histMargin.left + ',' + params.histMargin.top + ')');
//rect to capture clicks to reset the coloring
params.svg.append('rect')
.attr('id','clickCatcher')
.attr('transform', 'translate(' + -params.histMargin.left + ',' + -params.histMargin.top + ')')
.attr('width',w + 'px')
.attr('height',h -1 + 'px') //for border
.attr('fill',params.backgroundColor)
.on('click',function(){
params.svg.selectAll('.bar').transition().duration(params.duration).style('fill', params.fillColor);
showNames();
})
// X axis: scale and draw:
params.xAxis = d3.scaleLinear()
.domain([params.minX, params.maxX])
.range([0, params.histWidth]);
params.svg.append('g')
.attr('transform', 'translate(0,' + params.histHeight + ')')
.call(d3.axisBottom(params.xAxis));
//bin the data for the three different categories
params.histAll = binData();
params.histTypeA = binData('Type A');
params.histTypeB = binData('Type B');
// Y axis: scale and draw:
params.yAxis = d3.scaleLinear()
.range([params.histHeight, 0]);
params.yAxis.domain([0, d3.max(params.histAll, function(d) { return d.length; })]);
// params.svg.append('g')
// .call(d3.axisLeft(params.yAxis));
// text label for the x axis
params.svg.append('text')
.attr('transform', 'translate(' + (params.histWidth/2) + ',' + (params.histHeight + params.histMargin.top + 24) + ')')
.style('text-anchor', 'middle')
.style('font','16px sans-serif')
.text('Parameter X')
// append the bar rectangles to the svg element
// first, check which data set to use (in case of resize)
var dataSet = params.histAll;
if (params.isTypeA) dataSet = params.histTypeA;
if (params.isTypeB) dataSet = params.histTypeB;
var fillColor = getComputedStyle(document.documentElement).getPropertyValue('--plot-background-color');
params.svg.selectAll('.bar')
.data(dataSet).enter()
.append('rect')
.attr('class','bar')
.attr('x', 1)
.attr('transform', function(d) { return 'translate(' + params.xAxis(d.x0) + ',' + params.yAxis(d.length) + ')'; })
.attr('width', function(d) { return Math.max(params.xAxis(d.x1) - params.xAxis(d.x0) -3 ,0) + 'px' ; }) //-val to give some separation between bins
.attr('height', function(d) { return params.histHeight - params.yAxis(d.length) + 'px'; })
.attr('stroke-width',1)
.attr('stroke', 'black')
.style('fill', params.fillColor)
.style('cursor','pointer')
//.on('mouseover', function() { d3.select(this).style('fill', params.hoverColor);})
//.on('mouseout', function() { d3.select(this).style('fill', params.fillColor);})
.on('click',function(d){
var names = [];
d3.selectAll('.bar').transition().duration(params.duration).style('fill', params.hoverColor);
d3.select(this).transition().duration(params.duration).style('fill', params.fillColor)
showNames(d);
})
}
function changeHistogram(arg){
//console.log(arg)
params.isTypeB = false;
params.isTypeA = false;
if (arg.includes('TypeB')) params.isTypeB = true;
if (arg.includes('TypeA')) params.isTypeA = true;
showNames();
params.svg.selectAll('.bar').data(params[arg]);
//rescale the y axis?
//params.yAxis.domain([0, d3.max(params[arg], function(d) { return d.length; })]);
params.svg.selectAll('.bar').transition().duration(params.duration)
.attr('transform', function(d, i) { return 'translate(' + params.xAxis(d.x0) + ',' + params.yAxis(d.length) + ')'; })
.attr('height', function(d,i) { return params.histHeight - params.yAxis(d.length) + 'px'; })
.style('fill', params.fillColor)
}
function highlightBar(fund){
params.svg.selectAll('.bar').transition().duration(params.duration)
.style('fill',function(d){
var found = false;
d.forEach(function(dd){
if (dd['institutionname'] == fund['institutionname']) found = true;
})
if (found) {
return params.fillColor
} else {
return params.hoverColor
}
})
}
:root {
--foreground-color: #342F2E;
--background-color: #FFFFFF;
--button-foreground-color: #342F2E;
--button-background-color: #FFFFFF;
--highlight-color: #f87a62;
--hover-color: #f8c8ba;
}
#container {
font: 12px sans-serif;
font-family: sans-serif;
padding:0;
margin:0;
overflow: hidden;
background-color : var(--background-color);
color: var(--foreground-color);
}
.button{
float:left;
font-family: sans-serif;
border-bottom: 1px solid black;
text-align:center;
background-color: var(--button-background-color);
color: var(--button-foreground-color);
cursor: pointer;
}
.buttonHover:hover {
background-color: var(--hover-color);
/*color: var(--button-background-color);*/
}
.buttonClicked {
background-color: var(--highlight-color);
color: var(--button-background-color);
}
.listNames {
font: 16px sans-serif;
font-family: sans-serif;
padding:4px;
margin:0;
border-bottom: 1px solid black;
cursor:pointer;
}
.fundInfo {
font: 12px sans-serif;
font-family: sans-serif;
font-style: italic;
padding:4px;
padding-left:8px;
}
.listNamesHover:hover {
background-color: var(--hover-color);
/*color: var(--button-background-color);*/
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<!-- my style sheet -->
<link rel="stylesheet" type="text/css" href="index.css" />
<!-- for the search icon -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<!-- chart container -->
<div id='visContainer'></div>
<!-- my scripts -->
<script src="params.js"></script>
<script src="init.js"></script>
<script src="histogram.js"></script>
<script src="search.js"></script>
</body>
//get the position of a dom element on the page
//https://www.kirupa.com/html5/get_element_position_using_javascript.htm
function getPosition(el) {
var xPos = 0;
var yPos = 0;
while (el) {
if (el.tagName == "body") {
// deal with browser quirks with body/window/document and page scroll
var xScroll = el.scrollLeft || document.documentElement.scrollLeft;
var yScroll = el.scrollTop || document.documentElement.scrollTop;
xPos += (el.offsetLeft - xScroll + el.clientLeft);
yPos += (el.offsetTop - yScroll + el.clientTop);
} else {
// for all other non-BODY elements
xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPos += (el.offsetTop - el.scrollTop + el.clientTop);
}
el = el.offsetParent;
}
return {
x: xPos,
y: yPos
};
}
function fontLoop(elem, fs, dfs, w){
//shrink the text until it fits
var sW = elem.node().scrollWidth;
var wRound = Math.ceil(w);
while (sW > wRound && fs > 0){
fs -= dfs;
elem.style('font-size', fs);
sW = elem.node().scrollWidth;
}
return fs;
}
function resizeButtonFont(){
var elems = document.getElementsByClassName("button");
var minFs = params.buttonFontSize;
//first iterate through to get the minimum font size
for(var i = 0; i < elems.length; i++) {
var elem = d3.select(elems.item(i));
var fs = params.buttonFontSize;
var dfs = 0.1; //amount to shrink text at each iteration
var w = elem.node().getBoundingClientRect().width;
fs = fontLoop(elem, fs, dfs, w);
if (fs > 0.1) minFs = Math.min(minFs, fs);
if (i == elems.length - 1){
//now resize all to that minimum value
for(var j = 0; j < elems.length; j++) {
var elem = d3.select(elems.item(j));
elem.style('font-size', 0.9*minFs);
};
//also resize the search box to match
d3.select('#searchInput').style('font-size', 0.9*minFs);
d3.select('#searchIcon').style('font-size', 0.9*minFs);
}
}
}
function createContainers(){
function createButton(parent, id, width, text, callback, arg){
var button = parent.append('div')
.attr('id', id)
.attr('class','button')
.classed('buttonHover', true)
.style('width', width + 'px')
.style('height', params.buttonHeight + 'px')
.style('line-height',params.buttonHeight + 'px')
.style('font-size',params.buttonFontSize + 'px')
.text(text)
.on('click', function(){
d3.selectAll('.button')
.classed('buttonHover', true)
.classed('buttonClicked', false);
d3.select('#'+id)
.classed('buttonHover', false)
.classed('buttonClicked', true);
callback(arg);
})
return button
}
//main container
params.container = d3.select('#visContainer')
.style('border','1px solid black')
.style('width', params.width + 'px')
.style('height', params.height + 'px')
//for the plot
var plots = params.container.append('div')
.attr('id','plotContainer')
.style('width', params.plotWidth + 'px')
.style('height', params.height + 'px')
.style('border-right','1px solid black')
.style('float','left')
//buttons
var allButton = createButton(plots, 'allButton',params.plotWidth/3 -1, 'All', changeHistogram, 'histAll')
allButton.style('border-right', '1px solid black')
var TypeAButton = createButton(plots, 'TypeAButton', params.plotWidth/3 -1, 'TypeA', changeHistogram, 'histTypeA')
TypeAButton.style('border-right', '1px solid black')
var TypeBButton = createButton(plots, 'TypeBButton', params.plotWidth/3, 'TypeB', changeHistogram, 'histTypeB')
//check which one should be highlighted
var modButton = allButton;
if (params.isTypeA) modButton = TypeAButton
if (params.isTypeB) modButton = TypeBButton
modButton
.classed('buttonClicked', true)
.classed('buttonHover', false)
//histogram
plots.append('div')
.attr('id', 'histogram')
//search box
var search = params.container.append('div')
.attr('id','searchContainer')
.style('width',params.searchWidth -1 + 'px' )
.style('height',params.height + 'px')
.style('float','left')
var searchInput = search.append('input')
.attr('id','searchInput')
.attr('type','text')
.attr('placeholder','Search')
.attr('autocomplete','off')
.style('float', 'left')
.style('width',params.searchWidth - params.buttonHeight - 5 + 'px' )
.style('height',params.buttonHeight -4 + 'px') //-4 to account for borders
.style('font-size',params.buttonFontSize + 'px')
.style('line-height',params.buttonHeight + 'px')
.style('border-bottom', '1px solid black')
.style('border-right', '1px solid black')
.on('click',function(){
d3.select(this)
.attr('value',null)
})
.on('keydown',function(){
if (params.searchTimeout) clearTimeout(params.searchTimeout);
params.searchTimeout = setTimeout(checkSearchInput, 50);
})
//clear the input on any mouse click?
params.container.on('click', function(){clearSearch(event)});
var searchButton = search.append('div')
.attr('id', 'searchButton')
.attr('class','button')
.classed('buttonHover', true)
.style('width', params.buttonHeight-1 + 'px')
.style('height', params.buttonHeight + 'px')
.on('click', function(){
checkSearchInput();
})
.on('mousedown', function(){
d3.select(this)
.classed('buttonHover', false)
.classed('buttonClicked', true);
})
.on('mouseup', function(){
d3.select(this)
.classed('buttonHover', true)
.classed('buttonClicked', false);
})
searchButton.append('i')
.attr('id','searchIcon')
.attr('class', 'fa fa-search')
.style('font-size',params.buttonFontSize + 'px')
.style('line-height',params.buttonHeight + 'px')
search.append('div')
.attr('id','searchList')
.style('overflow-y','auto')
.style('float','left')
.style('height',params.height - params.buttonHeight - 1 + 'px')
.style('width',params.searchWidth -1 + 'px' )
resizeButtonFont();
}
//runs directly after the data is read in, and initializes everything
function init(data){
//create the params object
defineParams();
params.inputData = data;
//create the containers
createContainers();
//bin the data
createHistogram();
}
//runs on load
d3.csv('dummyData.csv')
.then(function(data) {
init(data)
})
.catch(function(error){
console.log('ERROR:', error)
})
//all "global" variables are contained within params object
var params;
function defineParams(){
params = new function() {
//holds the data object
this.inputData = null;
//this is the histogram DOM elements
this.container = null;
this.svg = null;
//duration for transitions
this.duration = 500;
//for binning the data
this.nBins = 20;
this.minX = -1.;
this.maxX = 1.;
this.foregroundColor = getComputedStyle(document.documentElement).getPropertyValue('--foreground-color');
this.backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--background-color');
this.fillColor = getComputedStyle(document.documentElement).getPropertyValue('--highlight-color');
this.hoverColor = getComputedStyle(document.documentElement).getPropertyValue('--hover-color');
//store the binned data
this.histAll = null;
this.histTypeA = null;
this.histTypeB = null;
//store the histogram axis converters
this.xAxis = null;
this.yAxis = null;
//dimensions of the containers
this.width = 760;
this.plotWidthRatio = 460/760;
this.plotWidth = this.width*this.plotWidthRatio;
this.searchWidth = this.width - this.plotWidth;
this.height = 500;
this.buttonHeight = 60;
this.buttonFontSize = this.buttonHeight*0.6;
this.histMargin = {'top': 10, 'right': 15, 'bottom': 40, 'left': 15};
this.histWidth = this.plotWidth - this.histMargin.left - this.histMargin.right;
this.histHeight = this.height - this.buttonHeight - this.histMargin.top - this.histMargin.bottom;
//for searching
this.searchTimeout = null;
this.isTypeA = false;
this.isTypeB = false;
};
}
//search through the input object for names that match
function checkSearchInput(event = null){
var value = document.getElementById('searchInput').value;
//console.log("Searching", value)
//is there a faster way to do this? (maybe but this seems fast enough)
var funds;
if (value.length > 0){
funds = [];
params.inputData.forEach(function(d){
if (d['institutionname'].substring(0,value.length).toUpperCase() == value.toUpperCase()){
if ( (!params.isTypeA && !params.isTypeB) ||
(params.isTypeA && d['institution_type2'] == 'Type A') ||
(params.isTypeB && d['institution_type2'] == 'Type B') ) {
funds.push(d);
}
}
})
} else {
funds = null;
}
showNames(funds);
}
//show a list of names in the div below the search box
function showNames(funds = null){
d3.select('#searchList').selectAll('.listNames').remove();
d3.select('#searchList').selectAll('.fundInfo').remove();
if (funds){
if (funds.length > 0){
d3.select('#searchList').selectAll('.listNames')
.data(funds).enter()
.append('div')
.attr('class','listNames')
.classed('listNamesHover', true)
.attr('id',function(d) {return 'listNames' + d['institutionname'].replace(/[^a-zA-Z0-9]/g, "");})
.on('click', function(d) {
showNameInfo(d);
highlightBar(d);
})
.text(function(d){return d['institutionname'];})
} else {
d3.select('#searchList').append('div')
.attr('class','fundInfo')
.style('color','gray')
.style('font-size','16px')
.text('No results')
}
}
}
//show the type of fund for a given name (could add more info if desired)
function showNameInfo(fund){
var id = fund['institutionname'].replace(/[^a-zA-Z0-9]/g, "")
var elm = d3.select('#listNames' + id);
var posElm = getPosition(elm.node());
var posContainer = getPosition(params.container.node());
var posY = Math.max(posElm.y - params.buttonHeight - posContainer.y - 3, 0); //-3 for the borders
//clear the funds
showNames();
//add back this fund to the
d3.select('#searchList').append('div')
.attr('id','listNames' + id)
.attr('class','listNames')
.classed('listNamesHover', false)
.style('margin-top', posY + 'px')
.text(fund['institutionname'])
var dur = 0;
if (posY > 0) {
d3.select('#listNames' + id).style('border-top', '1px solid black')
dur = params.duration;
}
//move it to the top of the div
d3.select('#listNames' + id).transition().duration(dur)
.style('margin-top',0 + 'px')
.style('border-top',0 + 'px')
.style('border-bottom', 0 + 'px')
.on('end', function(){
var tp = fund['institution_type2'];
if (tp[tp.length - 1] == 's') tp = tp.substring(0, tp.length - 1);
d3.select(this).append('div')
.attr('class','fundInfo')
.text(tp)
})
}
function clearSearch(event){
if (!event.target.id.includes('search')) document.getElementById('searchInput').value = null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment