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 Neque labore Type A 0.04028525143262501
1 Magnam modi Type B 0.018177230528104382
2 Tempora amet Type A -0.916658678636934
3 Dolorem porro Type A 0.17798909034451196
4 Eius modi Type A 0.5382088817975744
5 Consectetur tempora Type A 0.02357633370075274
6 Dolore non Type A -0.2588666040401126
7 Quiquia velit Type A 0.405093845285034
8 Dolorem neque Type B -0.37930615599969597
9 Voluptatem etincidunt Type A 0.5112504106812501
10 Est dolor Type A 0.308147050633885
11 Non neque Type A 0.10554415112153392
12 Amet est Type A 0.5659948850493371
13 Etincidunt quisquam Type A 0.05450700262825048
14 Quiquia dolorem Type A -0.011246769021796443
15 Aliquam ut Type A -0.03114736718503308
16 Modi voluptatem Type A 0.7710369752365283
17 Labore adipisci Type A 0.09975523851892826
18 Quisquam quaerat Type A 0.3384308500477995
19 Sit dolorem Type A 0.776951609967643
20 Voluptatem labore Type A -0.10495090500588955
21 Adipisci labore Type A 0.7891879586989363
22 Dolorem tempora Type A 0.036740027598371916
23 Quisquam tempora Type A 0.06551443667853232
24 Aliquam numquam Type A -0.13030157453677832
25 Magnam aliquam Type A 0.7280859982499617
26 Est dolore Type A -0.001990971199191005
27 Quisquam neque Type A 0.10192647461137563
28 Consectetur numquam Type A 0.35693759001686
29 Amet quaerat Type A 0.8172523879979849
30 Labore amet Type A 0.2116517109106689
31 Quiquia amet Type A -0.06404398724432858
32 Tempora dolorem Type A 0.46540777827711255
33 Etincidunt labore Type A 0.32880198561608676
34 Ipsum sit Type A 0.7276818467283085
35 Porro adipisci Type B -0.25445469083438776
36 Modi dolor Type B -0.8494640268815952
37 Dolore amet Type A 0.5234671117197108
38 Voluptatem quaerat Type A 0.8084685482598959
39 Ipsum adipisci Type B -0.99
40 Est adipisci Type A 0.18868614294517422
41 Tempora voluptatem Type A 0.2868403346451913
42 Quaerat dolor Type A 0.2460400958211146
43 Dolore modi Type A 0.21397488143035365
44 Quiquia tempora Type A 0.26657587369230556
45 Adipisci sit Type A 0.7475863455703615
46 Quisquam quiquia Type B -0.5040211716251969
47 Velit sed Type A -0.16037477358588875
48 Quiquia voluptatem Type A 0.99
49 Amet velit Type A 0.8306642057674696
50 Numquam ut Type B -0.8618194590358923
51 Quiquia quaerat Type A 0.99
52 Velit modi Type A 0.11095535374744345
53 Non quaerat Type A 0.05632150228920063
54 Tempora etincidunt Type B -0.07791536860065756
55 Porro voluptatem Type A 0.21385004535036217
56 Eius dolore Type A 0.99
57 Quisquam amet Type A 0.378377455023206
58 Porro numquam Type A -0.18039492258905387
59 Numquam velit Type A 0.6468610111021498
60 Consectetur consectetur Type A 0.28745494080911266
61 Ut velit Type A 0.2709070078381265
62 Dolore adipisci Type A 0.4916987739018403
63 Porro dolorem Type A -0.09878993438794309
64 Non sed Type A 0.99
65 Porro magnam Type A 0.45998441209923147
66 Ipsum porro Type A -0.11335685195188244
67 Non dolorem Type A -0.060684887153896805
68 Labore quaerat Type A 0.99
69 Tempora dolore Type A 0.3401511121583678
70 Etincidunt ut Type A 0.7411419885985502
71 Eius quaerat Type A 0.13105299151486688
72 Aliquam amet Type A 0.99
73 Velit aliquam Type A 0.30428589499296405
74 Labore velit Type A -0.14922855727290085
75 Quaerat magnam Type A 0.5683949662381167
76 Quisquam voluptatem Type A 0.21896478789114993
77 Numquam modi Type A -0.08957572880989256
78 Dolor dolore Type A 0.37571162906605793
79 Velit quiquia Type A 0.03411175674478889
80 Ipsum est Type B -0.4051107199360266
81 Amet dolorem Type A 0.24753450500253493
82 Numquam est Type A 0.5712404204562187
83 Dolore neque Type A 0.4184688358153813
84 Magnam eius Type A -0.019576639212687874
85 Aliquam est Type A 0.3319360425022909
86 Est etincidunt Type A 0.15588642813232645
87 Neque quisquam Type C 0.1689801688215975
88 Quiquia modi Type A 0.518770300598767
89 Velit neque Type A 0.99
90 Modi quisquam Type A 0.18422826282945673
91 Dolorem amet Type A 0.5841898002803617
92 Amet quiquia Type A -0.36376688717884537
93 Quiquia dolore Type A 0.41862014099107225
94 Labore modi Type A 0.518963383218835
95 Labore est Type A 0.16632928156699087
96 Voluptatem quiquia Type A 0.4531824554032442
97 Ipsum etincidunt Type A 0.99
98 Magnam sit Type A 0.6076220244040138
99 Sed modi Type A 0.25564849709982446
100 Ipsum ipsum Type A 0.3441389693819597
101 Dolore ut Type A 0.21005840100411083
102 Sed velit Type B -0.3097561332249379
103 Eius adipisci Type A 0.35535811615116586
104 Dolorem velit Type A 0.21138150584008364
105 Eius aliquam Type A -0.02261677271986634
106 Sit sed Type C 0.5411281763727589
107 Voluptatem aliquam Type A -0.36018284151378893
108 Consectetur ut Type B -0.44706810557418064
109 Quaerat dolorem Type B -0.6726246599651748
110 Etincidunt velit Type B -0.4142428809406347
111 Quiquia aliquam Type B -0.6850762657250093
112 Non quiquia Type A 0.7398369191321792
113 Sit est Type A 0.8193897581602076
114 Amet tempora Type A 0.20282877575997227
115 Eius amet Type A -0.029066314898448464
116 Quiquia magnam Type A 0.07334911431516941
117 Modi adipisci Type A 0.7760128126920764
118 Porro quisquam Type A 0.4537005473199314
119 Amet dolor Type A -0.45011112947818527
120 Modi magnam Type A 0.6033990927819008
121 Voluptatem ut Type A 0.4713732576041002
122 Ut quisquam Type A 0.9380501800006769
123 Dolor quaerat Type B -0.2453042558497634
124 Non eius Type A -0.11082741642555904
125 Ut amet Type A 0.19108053814651582
126 Neque ipsum Type A 0.28694491246026194
127 Adipisci numquam Type A -0.02627791792482087
128 Non non Type A 0.33356287478928065
129 Magnam amet Type A 0.1348793535422827
130 Ut aliquam Type A -0.19500423544543088
131 Dolorem ut Type A 0.31855978295857273
132 Dolorem quiquia Type A 0.651748404949885
133 Modi ipsum Type A -0.3800569124836562
134 Aliquam neque Type B -0.7949355077291924
135 Labore dolorem Type B -0.8467831678951847
136 Labore porro Type A -0.8067229100876954
137 Non numquam Type A -0.3374858986525819
138 Ipsum non Type A 0.6146025862485798
139 Voluptatem ipsum Type A 0.41149354001412114
140 Dolor neque Type A -0.4929169892794059
141 Quiquia quisquam Type B -0.28289361755682707
142 Dolore porro Type C -0.19209635192465727
143 Aliquam quaerat Type A 0.7914571035869362
144 Ipsum amet Type A 0.5667443022990071
145 Amet consectetur Type A -0.1497872971873307
146 Magnam sed Type B -0.3398185594466163
147 Labore eius Type B -0.9849953917712161
148 Numquam eius Type A 0.1650486510057811
149 Dolorem quaerat Type A 0.99
150 Quiquia est Type A 0.7848336448558206
151 Tempora quaerat Type A 0.28824888594682313
152 Sed etincidunt Type A -0.25824082567395096
153 Dolor modi Type A -0.07871838747995646
154 Amet ut Type A 0.15497584792863323
155 Aliquam velit Type A 0.7399685836711056
156 Adipisci adipisci Type A 0.7097645463165023
157 Velit est Type A -0.3570161885494813
158 Voluptatem dolore Type B -0.40351071980090714
159 Dolorem dolorem Type A 0.40399321651769987
160 Quisquam non Type B -0.7728681737467913
161 Sit adipisci Type B -0.6563525590581148
162 Eius magnam Type A 0.17611401947026586
163 Velit quaerat Type A 0.10515218446051844
164 Quisquam numquam Type A 0.2585890903464151
165 Dolorem eius Type A 0.1680019590957421
166 Non dolore Type B -0.3316156622951419
167 Sit ipsum Type A -0.7442247682715979
168 Dolorem est Type A 0.29691264036675663
169 Ut dolorem Type B -0.6893613125411834
170 Labore tempora Type A 0.42902148394690304
171 Quiquia dolor Type A -0.9723351183683184
172 Labore consectetur Type A 0.14630438732031587
173 Eius etincidunt Type A 0.2674576902811244
174 Etincidunt quaerat Type A 0.20094698616443252
175 Velit labore Type A -0.15161199849706564
176 Aliquam aliquam Type A 0.8068296194458942
177 Dolore ipsum Type B -0.7226043162616915
178 Adipisci sed Type B -0.6317388023561796
179 Dolore dolore Type B 0.0915645136763592
180 Velit eius Type A -0.08738486714934507
181 Est quaerat Type A 0.6086527537865642
182 Voluptatem consectetur Type A 0.49444770041195446
183 Quiquia etincidunt Type A 0.5372120827210776
184 Quisquam ut Type A -0.1216604576944762
185 Aliquam dolore Type A 0.4926971221296932
186 Velit tempora Type B -0.4626321738955619
187 Est aliquam Type A -0.011386193377143305
188 Adipisci consectetur Type A 0.853139686089118
189 Neque quaerat Type A 0.5319703681482543
190 Tempora dolor Type A 0.26406995979620335
191 Ut ut Type A 0.1673795680034482
192 Sed magnam Type B -0.04497254869797951
193 Eius est Type B 0.14408881507152016
194 Numquam tempora Type A -0.20599431969170662
195 Tempora porro Type A 0.4597443384986364
196 Dolorem etincidunt Type A 0.99
197 Voluptatem neque Type A -0.19832683627393133
198 Porro aliquam Type A 0.6776221423494445
199 Eius neque Type A 0.04636059252878916
200 Aliquam quisquam Type A 0.22725020701017787
201 Dolorem magnam Type A 0.37156073283206037
202 Tempora magnam Type A 0.41991815077315686
203 Consectetur sit Type A 0.10328508063992209
204 Consectetur voluptatem Type A 0.22897157570781637
205 Non porro Type A 0.2176096747199192
206 Magnam voluptatem Type A 0.667482027659082
207 Magnam numquam Type A 0.1242957511758882
208 Neque magnam Type A 0.19954270959832948
209 Sit dolor Type A -0.21098911607990828
210 Etincidunt sit Type A 0.45009263025416035
211 Porro labore Type A 0.5730323952569409
212 Quiquia consectetur Type A 0.17564108226888248
213 Etincidunt amet Type A 0.6408162841104472
214 Velit porro Type A -0.99
215 Voluptatem est Type A -0.010172720353883336
216 Eius non Type A 0.1654899893387379
217 Dolorem adipisci Type B -0.5507309578313794
218 Porro amet Type A 0.99
219 Quaerat neque Type A 0.7427277051859288
220 Consectetur dolor Type A 0.46814104688841096
221 Neque sed Type A 0.36091112150777294
222 Quisquam etincidunt Type A 0.22224341803045827
223 Velit ut Type A 0.5402838701674691
224 Quisquam porro Type B -0.9443255939935409
225 Quiquia numquam Type B -0.30263681442260004
226 Quaerat tempora Type B -0.5617935393354916
227 Ipsum sed Type A 0.3972704659113511
228 Porro est Type A -0.8239569899559787
229 Adipisci ipsum Type A 0.09821308680012547
230 Ipsum modi Type A 0.47295035111965017
231 Sit etincidunt Type A -0.020792903951663333
232 Dolor dolorem Type A -0.2589680463091006
233 Quaerat aliquam Type A 0.1900311469048781
234 Adipisci modi Type B -0.48854038418860407
235 Magnam ipsum Type A 0.23726334990398062
236 Est quisquam Type A -0.19872956490131988
237 Etincidunt consectetur Type A 0.3305832223845271
238 Neque numquam Type A -0.05027930826782567
239 Adipisci quaerat Type A 0.5078014666804008
240 Porro modi Type A -0.022529679547683368
241 Tempora quiquia Type A 0.11175276891435468
242 Est ipsum Type A -0.07603357332811544
243 Labore dolor Type A 0.3560895894310678
244 Consectetur modi Type A -0.45895845427398246
245 Non sit Type A -0.23946352215114713
246 Ut numquam Type A 0.01639838739863736
247 Quaerat quiquia Type B -0.36976236636698256
248 Modi consectetur Type A 0.009910955481928774
249 Tempora eius Type B -0.7044474703507335
250 Etincidunt eius Type B -0.4423591641905001
251 Quaerat numquam Type B -0.4698794869289935
252 Consectetur dolore Type B -0.3092219324214919
253 Labore dolore Type B -0.13390388167250777
254 Velit etincidunt Type A 0.4623841571436095
255 Modi numquam Type A 0.6849198811785321
256 Est porro Type A -0.07469727316647906
257 Ipsum dolore Type A 0.2857814196841058
258 Modi tempora Type A 0.5654913385751323
259 Sed consectetur Type B -0.7034202855205105
260 Amet quisquam Type A 0.09378481217944873
261 Porro dolore Type A 0.1827772714228278
//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