PageSourceSearch

https://tomurell.github.io/bubbles/sketch.js

js tomurell.github.io collected 2026-10-03 10:05:42 UTC 16,069 bytes, 551 lines download raw bytes

1// mar15 > TOP 100 COMPANIES + THEIR TOP 200 INVESTORS
2
3//var exo2;
4var exo6;
5var exo3;
6var exo5;
7var particleSystem = [];
8var investorSystem = [];
9var attractors = [];
10var repulsors = [];
11var table;
12var categories = {};
13var catnums = {};
14var aggregated = {};
15var investors = [];
16var selectInvestors = [];
17var particles = [];
18var connections = [];
19var iOpacity = 100;
20var mouseState = false;
21
22function preload(){
23    table = loadTable("data/supertotal2.csv", "csv", "header");
24    exo3 = loadFont("fonts/Exo2-Light.ttf");
25    exo5 = loadFont("fonts/Exo2-Medium.ttf");
26    exo6 = loadFont("fonts/Exo2-SemiBold.ttf");
27}
28
29function windowResized() {
30    resizeCanvas(windowWidth, windowHeight);
31}
32
33//+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
34//SETUP
35function setup() {
36    var canvas = createCanvas(windowWidth, windowHeight);
37    frameRate(30);
38    colorMode(HSB, 360, 100, 100, 100);
39    background(0);
40    rectMode(CENTER);
41    textAlign(CENTER, CENTER);
42    
43    //+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
44    
45    //MAKE AGGREGATED COMPANIES & INVESTORS ARRAYS
46    for (var r = 0; r < table.getRowCount(); r++){
47        var cname = table.getString(r, "company_name");
48        var iname = table.getString(r, "investor_name");
49        var category = table.getString(r, "category_code");
50        var catnumb = table.getString(r, "category_num");
51        var invested = table.getString(r, "amount_usd");
52        invested = parseInt(invested);
53        
54        //total investment (to companies)
55        if(!isNaN(invested)){
56            if(aggregated.hasOwnProperty(cname)){
57                aggregated[cname] += invested;
58            }else{
59                aggregated[cname] = invested;
60            }
61        }
62        
63        //total investment (from investors)
64        if(!isNaN(invested)){
65            if(investors.hasOwnProperty(iname)){
66                investors[iname] += invested;
67            }else{
68                investors[iname] = invested;
69            }
70        }
71        
72        categories[cname] = category;
73        catnums[cname] = catnumb;
74
75    }
76    
77    //create aAggregated array 
78    var aAggregated = [];
79    Object.keys(aggregated).forEach(function(name_){
80        var company = {};
81        company.name = name_;
82        company.category = categories[name_];
83        company.cnum = catnums[name_];
84        company.sum = aggregated[name_]
85        aAggregated.push(company);
86    });
87    
88    //create aaInvestors array
89    var aInvestors = [];
90    Object.keys(investors).forEach(function(name_){
91        var investor = {};
92        investor.iname = name_;
93        investor.totalInv = investors[name_];
94        aInvestors.push(investor);
95    });
96    
97    //sort by sum
98    aAggregated.sort(function(companyA, companyB){
99        return companyB.sum - companyA.sum;
100    });    
101    
102    aAggregated = aAggregated.slice(0, 100);
103    
104    //+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
105    //MAKING CONNECTIONS ARRAY
106    for (var r = 0; r < table.getRowCount(); r++){
107        var compname = table.getString(r, "company_name");
108        var invname = table.getString(r, "investor_name");
109        var date = table.getString(r, "funded_at");
110        var category = table.getString(r, "category_code");
111        var amt = table.getString(r, "amount_usd");
112        amt = parseInt(amt);
113        
114        var foundCompany = aAggregated.find(function(element, index, array){
115            if(element.name == compname){
116                return true;
117            }else{
118                return false;
119            }
120        });
121        
122        if(foundCompany){
123            var foundInvestor = false;
124            foundInvestor = aInvestors.find(function(element, index, array){
125                if(element.iname == invname){
126                    return true;
127                }else{
128                    return false;
129                } 
130            });
131            
132            if(foundInvestor){
133                var connection = {};
134                connection.company = foundCompany;
135                connection.investor = foundInvestor;
136                connection.amount = amt;
137                //connection.date = date;
138                //connection.category = category;
139                connections.push(connection);  
140            }
141
142        }
143                                              
144    }
145    
146    print(connections);
147    
148    //+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
149
150    //Make selectInvestors array from connections
151    connections.forEach(function(connection){
152        var found = selectInvestors.find(function(selectInvestor){
153        return selectInvestor == connection.investor;
154            });
155        if(!found) selectInvestors.push(connection.investor) 
156    });
157    
158    //sort by totalInv
159    selectInvestors.sort(function(inameA, inameB){
160        return inameB.totalInv - inameA.totalInv;
161    });    
162    
163    selectInvestors = selectInvestors.slice(0, 200);
164    
165    
166    //+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
167
168    //# of objects in array AS PARTICLES
169    for (var i=0; i<aAggregated.length; i++) {
170        var p = new Particle(aAggregated[i].name, 
171                             aAggregated[i].sum, 
172                             aAggregated[i].category, 
173                             aAggregated[i].cnum);
174        particleSystem.push(p);
175    }
176    
177    for (var h=0; h<selectInvestors.length; h++) {
178        var j = new investorParticle(selectInvestors[h].iname,
179                                     selectInvestors[h].totalInv);
180        investorSystem.push(j);
181    }
182    
183    // attractor position & strength
184    var at = new Attractor(createVector(width*.5, height*.5), 84);
185    attractors.push(at);
186    
187    // repulsor position & strength
188    var rp = new Repulsor(createVector(width*.5, height*.5), 84);
189    repulsors.push(rp);
190    
191}
192
193//+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
194//DRAW
195function draw() {
196    background(0, 0, 100, 100);
197    
198    for (var STEPS = 0; STEPS<3; STEPS++) {
199            for (var i=0; i<particleSystem.length-1; i++){
200                for (var j=i+1; j<particleSystem.length; j++){
201                    var pa = particleSystem[i];
202                    var pb = particleSystem[j];
203                    var ab = p5.Vector.sub(pb.pos, pa.pos);
204                    var distSq = ab.magSq();
205                    if(distSq <= sq(pa.radius + pb.radius)){
206                        var dist = sqrt(distSq);
207                        var overlap = (pa.radius + pb.radius) - dist;
208                        ab.div(dist);
209                        ab.mult(overlap*0.5);
210                        pb.pos.add(ab);
211                        ab.mult(-1);
212                        pa.pos.add(ab);
213                        //friction
214                        pa.vel.mult(0.98);
215                        pb.vel.mult(0.98);
216                        
217                    }
218                }
219            }
220        }
221    
222    for (var STEPS = 0; STEPS<3; STEPS++) {
223            for (var i=0; i<investorSystem.length-1; i++){
224                for (var j=i+1; j<investorSystem.length; j++){
225                    var pa = investorSystem[i];
226                    var pb = investorSystem[j];
227                    var ab = p5.Vector.sub(pb.pos, pa.pos);
228                    var distSq = ab.magSq();
229                    if(distSq <= sq(pa.radius + pb.radius)){
230                        var dist = sqrt(distSq);
231                        var overlap = (pa.radius + pb.radius) - dist;
232                        ab.div(dist);
233                        ab.mult(overlap*0.5);
234                        pb.pos.add(ab);
235                        ab.mult(-1);
236                        pa.pos.add(ab);
237                        //friction
238                        pa.vel.mult(0.98);
239                        pb.vel.mult(0.98);
240                        
241                    }
242                }
243            }
244        }
245    
246    investorSystem.forEach(function(j) {
247        j.update();
248        j.draw();
249    });
250    
251    particleSystem.forEach(function(p) {
252        p.update();
253        p.draw();
254    });
255    
256    attractors.forEach(function(at){
257        at.draw();
258    });
259    
260    repulsors.forEach(function(rp){
261        rp.draw();
262    }); 
263    
264}
265
266//+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
267//INVESTOR PARTICLE
268var investorParticle = function(iname, totalInv) {    
269    this.iname = iname;
270    this.totalInv = totalInv;
271    var iColor = random(16, 32);
272    this.opacity = iOpacity;
273    this.radius = sqrt(this.totalInv)/2000;
274    var initialRadius = this.radius;
275    var maxRadius = 88;
276    var angleInc = TWO_PI / random(0.1, PI);
277    var ang = -0.75;    
278    ang = ang + angleInc;
279    this.pos = createVector(sin(ang), cos(ang));
280    this.pos.mult(460);
281    this.pos.add(width/2, height/2);
282    this.vel = createVector(0, 0);
283    var acc = createVector(0, 0);
284    var isMouseOver = false;
285        
286    this.update = function() {
287        
288        checkMouse(this);
289        this.opacity = iOpacity;
290
291        attractors.forEach(function(A){
292            var att = p5.Vector.sub(A.getPos(), this.pos);
293            var distanceSq = att.magSq();
294            if(distanceSq > 1){
295                att.normalize();
296                att.mult(5);
297                att.mult(initialRadius*.001);
298                acc.add(att);
299            }
300
301        }, this);
302        
303        //REPULSOR
304        repulsors.forEach(function(R){
305            var rpp = p5.Vector.sub(R.getPos(), this.pos);
306            var distanceSq = rpp.magSq();
307            if(distanceSq > 1){
308                rpp.normalize();
309                rpp.mult(5*-1);
310                rpp.mult(initialRadius*.001);
311                acc.add(rpp);
312            }
313
314        }, this);
315
316        this.pos.add(this.vel);
317        this.vel.add(acc);
318        acc.mult(0);
319        
320    }
321        
322    this.draw = function() {
323                        
324        if(isMouseOver == true){
325            //fill when hover
326            fill(iColor, 50, 80, 100)
327        }else{
328            //fill default
329            fill(iColor, 55, 80, this.opacity)
330        };
331
332        noStroke();
333        ellipse(this.pos.x, 
334                this.pos.y, 
335                this.radius*2-4,
336                this.radius*2-4);
337        
338        //DRAW INVESTOR NAME IN BUBBLE AT MAXRADIUS
339        if(this.radius == maxRadius){
340            
341            //this.opacity = 50;
342            //text color
343            fill(0, 0, 100, 100);
344            
345            //show text for company name
346            textFont(exo5);
347            textSize(22);
348            
349            //with wrap:            
350            text(this.iname, 
351                 this.pos.x, 
352                 this.pos.y-12, 
353                 maxRadius, maxRadius);
354
355            //show text for sum
356            textFont(exo6);
357            textSize(14);
358            text("invested:", this.pos.x, this.pos.y+50);
359            dispSum = nfc(this.totalInv/1000000000, 2);
360            text("$" + dispSum + "B", this.pos.x, this.pos.y+64);
361            
362        }
363                   
364    }
365    
366    function checkMouse(instance){
367        var mousePos = createVector(mouseX, mouseY);
368            if(mousePos.dist(instance.pos) <= instance.radius){
369                incRadius(instance);
370                isMouseOver = true;
371            }else{
372                decRadius(instance);
373                isMouseOver = false;
374            }
375    }
376
377    function incRadius(instance){
378        instance.radius+=6;
379        if(instance.radius > maxRadius){
380            instance.radius = maxRadius;
381        }
382
383    }
384
385    function decRadius(instance){
386        instance.radius-=8;
387        if(instance.radius < initialRadius){
388            instance.radius = initialRadius;
389        }
390
391    }
392      
393}
394
395//+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
396//COMPANY PARTICLE
397var Particle = function(name, sum, category, cnum) {    
398    this.name = name;
399    this.sum = sum;
400    this.category = category;
401    this.cnum = cnum;
402    var color = map(this.cnum, 0, 44, 120, 330);
403    this.opacity = 100;
404    this.radius = sqrt(sum)/2000;
405    var initialRadius = this.radius;
406    var maxRadius = 108;
407    var tempAng = random(0, TWO_PI);
408    this.pos = createVector(cos(tempAng), sin(tempAng));
409    this.pos.div(this.radius);
410    this.pos.mult(15000);
411    this.pos.set(this.pos.x + width/2, this.pos.y + height/2);
412    this.vel = createVector(0, 0);
413    var acc = createVector(0, 0);
414    var isMouseOver = false;
415        
416    this.update = function() {
417        
418        checkMouse(this);
419        
420        attractors.forEach(function(A){
421            var att = p5.Vector.sub(A.getPos(), this.pos);
422            var distanceSq = att.magSq();
423            if(distanceSq > 1){
424                att.normalize();
425                att.mult(4);
426                att.mult(initialRadius*.001);
427                acc.add(att);
428            }
429
430        }, this);
431
432        this.pos.add(this.vel);
433        this.vel.add(acc);
434        acc.mult(0);
435                
436    }
437        
438    this.draw = function() {
439                        
440        if(isMouseOver == true){
441            fill(color, 50, 80, 100)
442        }else{
443            fill(color, 55, 80, this.opacity)
444        };
445
446        noStroke();
447        ellipse(this.pos.x, 
448                this.pos.y, 
449                this.radius*2-4,
450                this.radius*2-4);
451        
452        //DRAW COMPANY NAME IN BUBBLE AT MAXRADIUS
453        if(this.radius == maxRadius){
454            //text color
455            fill(0, 0, 100, 100);
456            
457            //show text for company name
458            textFont(exo3);
459            textSize(32);
460            
461            //with wrap:            
462            text(this.name, 
463                 this.pos.x, 
464                 this.pos.y-10, 
465                 maxRadius, maxRadius);
466
467            //show text for sum
468            textFont(exo5);
469            textSize(16);
470            dispSum = nfc(this.sum/1000000000, 2);
471            text("$" + dispSum + "B", this.pos.x, this.pos.y+78);
472            
473            //show text for category
474            textFont(exo5);
475            textSize(16);
476            text(this.category, this.pos.x, this.pos.y+60);
477            
478            }
479                   
480    }
481    
482
483    function checkMouse(instance){
484            var mousePos = createVector(mouseX, mouseY);
485            if(mousePos.dist(instance.pos) <= instance.radius){
486                incRadius(instance);
487                isMouseOver = true;
488            }else{
489                decRadius(instance);
490                isMouseOver = false;
491            }
492    }
493
494    function incRadius(instance){
495        instance.radius+=6;
496        if(instance.radius > maxRadius){
497            instance.radius = maxRadius;
498        }
499
500    }
501
502    function decRadius(instance){
503        instance.radius-=8;
504        if(instance.radius < initialRadius){
505            instance.radius = initialRadius;
506        }
507
508    }
509      
510}
511
512//+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
513//ATTRACTOR + REPULSOR
514var Attractor = function(pos, s){
515        this.pos = pos.copy();
516        var strength = s*10;
517        this.draw = function(){ 
518            noStroke();
519            fill(230, 0, 0, 0);
520            ellipse(this.pos.x, this.pos.y, strength, strength);
521        }
522        
523        this.getPos = function(){
524            return this.pos.copy();
525        }
526    
527        this.getStrength = function(){
528            return strength*10;
529        }
530            
531}
532
533var Repulsor = function(pos, s){
534        this.pos = pos.copy();
535        var strength = s*10;
536        this.draw = function(){ 
537            noStroke();
538            fill(230, 0, 0, 0);
539            ellipse(this.pos.x, this.pos.y, strength, strength);
540        }
541        
542        this.getPos = function(){
543            return this.pos.copy();
544        }
545    
546        this.getStrength = function(){
547            return strength*10;
548        }
549            
550}
551

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.