No description provided
The showcase player uses a modified version of Processing.js in combination with jsweet to let students program their apps in Java code while still allowing for browser support.
Content created by students is scaled to fit the showcase frame while maintaining aspect ratio and cursor position. This is why some projects may appear blurry in fullscreen, or why some small details may not be visible on a small screen
<iframe width='500px' height='400px' src='https://nest.ktbyte.com/nest#97171' allowfullscreen></iframe>
// Dynamic SCAA 2016 Flavor Wheel // Jared S Tarbell // October 14, 2016 // // Implemented a recursive polar hierarchy visualization to display the various // coffee flavor notes and faults with the graphic style, lexicon, and colors // of the SCAA 2016 Coffee Taster's Flavor Wheel www.scaa.org // // TODO fix font loading FlavorWheel flavorWheel; // PFont font; float arcResolution = 10.0; int restoreTimer = 0; void setup() { size(2000,2000); fullScreen(); background(#e8e4dc); background(0); smooth(); // font = createFont("URWTopic.otf"); // this is not working! // textFont(font,22); flavorWheel = new FlavorWheel(); Sector neoFloral = flavorWheel.addSector("floral", 0xFFed028c); Sector neoBlacktea = neoFloral.addSector("black tea", 0xFFad657c); Sector neoFFloral = neoFloral.addSector("floral", 0xFFef4b8e); neoFFloral.addSector("chamomile", 0xFFf7a834); neoFFloral.addSector("rose", 0xFFe2749f); neoFFloral.addSector("jasmine", 0xFFfffde5); Sector neoFruity = flavorWheel.addSector("fruity", 0xFFee1d23); Sector neoBerry = neoFruity.addSector("berry", 0xFFed2c41); neoBerry.addSector("blackberry", 0xFF090819); neoBerry.addSector("raspberry", 0xFFe32886); neoBerry.addSector("blueberry", 0xFF9799c0); neoBerry.addSector("strawberry", 0xFFee283b); Sector neoDried = neoFruity.addSector("dried fruit", 0xFFd6444e); neoDried.addSector("raisin", 0xFF9e1d78); neoDried.addSector("prune", 0xFF84548e); Sector neoOther = neoFruity.addSector("other fruit", 0xFFf26648); neoOther.addSector("coconut", 0xFFe38f29); neoOther.addSector("cherry", 0xFFe71256); neoOther.addSector("pomegranate", 0xFFee3c5c); neoOther.addSector("pineapple", 0xFFf89c1c); neoOther.addSector("grape", 0xFF9ec536); neoOther.addSector("apple", 0xFF69c071); neoOther.addSector("peach", 0xFFf27f51); neoOther.addSector("pear", 0xFFb2a91d); Sector neoCitrus = neoFruity.addSector("citrus fruit", 0xFFfcb814); neoCitrus.addSector("grapefruit", 0xFFf05961); neoCitrus.addSector("orange", 0xFFf47921); neoCitrus.addSector("lemon", 0xFFf4d902); neoCitrus.addSector("lime", 0xFF8fc254); Sector neoSweet = flavorWheel.addSector("sweet", 0xFFf36421); Sector neoBrownSugar = neoSweet.addSector("brown sugar", 0xFFcc7b89); neoBrownSugar.addSector("molasses",0xFF020f09); neoBrownSugar.addSector("maple syrup",0xFFce5e31); neoBrownSugar.addSector("carmelized",0xFFdd9c34); neoBrownSugar.addSector("honey",0xFFee7933); neoSweet.addSector("vanilla", 0xFFf39477); neoSweet.addSector("vanillin", 0xFFef7d80); neoSweet.addSector("overall sweet", 0xFFda7174); neoSweet.addSector("sweet aromatics", 0xFFc74465); neoSweet.addSector("pez", 0xFFb668e7); Sector neoNC = flavorWheel.addSector("nutty/cocoa", 0xFF997b78); Sector neoCocoa = neoNC.addSector("cocoa",0xFFac6e30); neoCocoa.addSector("dark chocolate",0xFF4a2c21); neoCocoa.addSector("chocolate",0xFF66332c); Sector neoNutty = neoNC.addSector("nutty",0xFFb58c7d); neoNutty.addSector("almond",0xFFd8a493); neoNutty.addSector("hazelnut",0xFF8e5e2f); neoNutty.addSector("peanuts",0xFFdeaf29); Sector neoSpices = flavorWheel.addSector("spices", 0xFFb80e40); Sector neoBrownSpice = neoSpices.addSector("brown spice",0xFFb4464b); neoBrownSpice.addSector("clove",0xFFb27566); neoBrownSpice.addSector("cinnamon",0xFFe08d39); neoBrownSpice.addSector("nutmeg",0xFF9a2e28); neoBrownSpice.addSector("anise",0xFFc3992f); Sector neoPepper = neoSpices.addSector("pepper",0xFFd53136); Sector neoPungent = neoSpices.addSector("pungent",0xFF724a5a); Sector neoRoasted = flavorWheel.addSector("roasted", 0xFFd33627); Sector neoCereal = neoRoasted.addSector("cereal",0xFFedc13c); neoCereal.addSector("malt",0xFFe89663); neoCereal.addSector("grain",0xFFcfa080); Sector neoBurnt = neoRoasted.addSector("burnt",0xFFb17c4e); neoBurnt.addSector("brown, roast",0xFF7f572e); neoBurnt.addSector("smoky",0xFFa47c3c); neoBurnt.addSector("ashy",0xFF98a187); neoBurnt.addSector("acrid",0xFFae9d67); Sector neoTobacco = neoRoasted.addSector("tabacco",0xFFcdb07b); Sector neoPipe = neoRoasted.addSector("pipe tabacco",0xFFa3905f); Sector neoVegetal = flavorWheel.addSector("vegetal", 0xFF167f3b); Sector neoBeany = neoVegetal.addSector("beany",0xFF799887); Sector neoGreen = neoVegetal.addSector("green",0xFF31a447); neoGreen.addSector("herb-like",0xFF7eb950); neoGreen.addSector("hay-like",0xFF9d9c33); neoGreen.addSector("vegetative",0xFF2ea55e); neoGreen.addSector("dark green",0xFF15583a); neoGreen.addSector("fresh",0xFF009d62); neoGreen.addSector("peapod",0xFF55a941); neoGreen.addSector("under-ripe",0xFFa8c346); Sector neoFault = flavorWheel.addSector("fault", 0xFF00a6d1); Sector neoChem = neoFault.addSector("chemical", 0xFF7ac0cd); neoChem.addSector("rubber",0xFF1e232d); neoChem.addSector("skunky",0xFF6b7f8a); neoChem.addSector("petroleum",0xFF009ba9); neoChem.addSector("medicinal",0xFF73a3b6); neoChem.addSector("salty",0xFFf9fbfc); neoChem.addSector("bitter",0xFF7fc2af); Sector neoPapery = neoFault.addSector("papery/musty",0xFFa6bac3); neoPapery.addSector("phenolic",0xFFe57c82); neoPapery.addSector("metay brothy",0xFFc97e72); neoPapery.addSector("animalic",0xFFa29c70); neoPapery.addSector("rusty",0xFF938149); neoPapery.addSector("dusty",0xFFc8a065); neoPapery.addSector("damp",0xFFa3a66e); neoPapery.addSector("woody",0xFF725c31); neoPapery.addSector("papery",0xFFfffefd); neoPapery.addSector("cardboard",0xFFd6bf4c); neoPapery.addSector("stale",0xFF6c7662); flavorWheel.render(); } void draw() { //Sector neo = flavorWheel.pickRandomSector(); //neo.mag = random(1.0,100.0); //background(#e8e4dc); background(0); flavorWheel.move(); flavorWheel.render(); restoreTimer++; if (restoreTimer==0) { flavorWheel.restore(); } } void mousePressed() { if (mouseButton==RIGHT) { // right clicked Sector neo = flavorWheel.pickSectorAtMouse(); if (neo!=null) { println("right picked:"+neo.label); neo.removeMe(); } } else { // left clicked Sector neo = flavorWheel.pickSectorAtMouse(); if (neo!=null) { println("picked:"+neo.label); neo.dmag += 10.0; neo.dthw += .618; restoreTimer = -100; } } } void keyPressed() { if (key=='s') { saveFrame(); println("Saved frame."); } } class FlavorWheel { Sector motherSector; FlavorWheel() { motherSector = new Sector(null, "COFFEE", 0xFF3d3d3d); } void move() { motherSector.move(); } void render() { pushMatrix(); translate(width/2,height/2); rotate(-HALF_PI); motherSector.render(); popMatrix(); } void restore() { motherSector.restore(1.0,1.0); } Sector addSector(String _label, color _myc) { Sector neo = motherSector.addSector(_label, _myc); return neo; } Sector pickRandomSector() { Sector obj = motherSector; for (int k=0;k<3;k++) { if (obj.children.size()==0) return obj; if (random(100)>obj.children.size()*10) { int n = floor(random( obj.children.size() )); obj = obj.children.get(n); } } return obj; } Sector pickSectorAtMouse() { Sector obj = null; obj = motherSector.didClick(); return obj; } } class Sector { Sector mother = null; // mother ArrayList<Sector> children; String label; color myc; int gen; // radial location in space float r0; float r1; float t0; float t1; // weighted pie slice rendering float mag = 1.0; float dmag = 1.0; // weighted radial rednering float thw = 1.0; float dthw = 1.0; Sector(Sector _mother, String _label, color _myc) { mother = _mother; label = _label; myc = _myc; children = new ArrayList<Sector>(); // special configuration for mother sector if (mother==null) { t0 = 0; t1 = TWO_PI; r0 = 0; r1 = 300; gen = 0; } else { gen = mother.gen + 1; } } Sector addSector(String _label, color _myc) { Sector neo = new Sector(this, _label, _myc); children.add(neo); return neo; } void restore(float _mag, float _thw) { dmag = _mag; dthw = _thw; for (int n=0;n<children.size();n++) { Sector obj = children.get(n); obj.restore(_mag, _thw); } } void move() { if (dmag<mag) { mag += (dmag-mag)*.255; } else { mag += (dmag-mag)*.333; } if (dthw<thw) { thw += (dthw-thw)*.255; } else { thw += (dthw-thw)*.333; } for (int n=0;n<children.size();n++) { Sector obj = children.get(n); obj.move(); } } void render() { // compute 2d coordinates and count number of points if (mother==null) { fill(myc); noStroke(); float diam = (r1-3)*2; ellipse(0,0,diam,diam); fill(255); textAlign(CENTER,CENTER); pushMatrix(); rotate(HALF_PI); text(label.toUpperCase(),0,0); popMatrix(); } else { float tinc = atan(arcResolution/r1); // padding substitution float tpad = .02 / (gen+1); float pt0 = t0 + tpad; float pt1 = t1 - tpad; float rpad = 3; float pr0 = r0 + rpad; float pr1 = r1 - rpad; // stupid hack to temporarily keep radius of gen 3 sector float tempr0 = pr0; if (gen==3) pr0 = pr1-20; // draw solid arc and label fill(myc); noStroke(); beginShape(); float x0 = pr0*cos(pt0); float y0 = pr0*sin(pt0); vertex(x0,y0); float x1 = pr1*cos(pt0); float y1 = pr1*sin(pt0); vertex(x1,y1); for (float t=pt0;t<=pt1;t+=tinc) { float xt = pr1*cos(t); float yt = pr1*sin(t); vertex(xt,yt); } float x2 = pr1*cos(pt1); float y2 = pr1*sin(pt1); vertex(x2,y2); float x3 = pr0*cos(pt1); float y3 = pr0*sin(pt1); vertex(x3,y3); for (float t=pt1;t>=pt0;t-=tinc) { float xtt = pr0*cos(t); float ytt = pr0*sin(t); vertex(xtt,ytt); } vertex(x0,y0); endShape(); if (gen==3) { // draw solid arc and label pr1 = pr0; pr0 = tempr0; fill(myc,64); noStroke(); beginShape(); float nx0 = pr0*cos(pt0); float ny0 = pr0*sin(pt0); vertex(nx0,ny0); float nx1 = pr1*cos(pt0); float ny1 = pr1*sin(pt0); vertex(nx1,ny1); for (float t=pt0;t<=pt1;t+=tinc) { float nxt = pr1*cos(t); float nyt = pr1*sin(t); vertex(nxt,nyt); } float nx2 = pr1*cos(pt1); float ny2 = pr1*sin(pt1); vertex(nx2,ny2); float nx3 = pr0*cos(pt1); float ny3 = pr0*sin(pt1); vertex(nx3,ny3); for (float t=pt1;t>=pt0;t-=tinc) { float nxtt = pr0*cos(t); float nytt = pr0*sin(t); vertex(nxtt,nytt); } vertex(nx0,ny0); endShape(); } // place label pushMatrix(); fill(255); if (gen==3) fill(myc); noStroke(); float tt = (t0 + t1)/2.0; float fx = 0; float fy = 0; // place and transform label according to generation if (gen==1) { fx = (r1 - 40)*cos(tt); fy = (r1 - 40)*sin(tt); } else if (gen==2) { fx = (r0 + 10)*cos(tt); fy = (r0 + 10)*sin(tt); } else if (gen==3) { fx = (r1 + 10)*cos(tt); fy = (r1 + 10)*sin(tt); } translate(fx,fy); if (gen==1) { rotate(tt+HALF_PI); textAlign(CENTER,BOTTOM); } else { if (tt<=PI || tt<0) { rotate(tt); textAlign(LEFT,CENTER); } else { rotate(tt+PI); textAlign(RIGHT, CENTER); } } float maxTextHeight = abs(.5*(pr0+pr1)*tan(pt1-pt0)); if (maxTextHeight>1) { if (maxTextHeight<28) scale(maxTextHeight/28); text(label.toUpperCase(),0,0); } popMatrix(); } fitChildren(); renderChildren(); } void renderChildren() { for (int n=0;n<children.size();n++) { Sector obj = children.get(n); // calculate radii on the fly obj.r0 = r1; obj.r1 = r1 + 100*obj.thw; obj.render(); } } void fitChildren() { // adjust all children radial angles to fit float omega = t1 - t0; // count total weight of children float childWeight = 0; for (int n=0;n<children.size();n++) { childWeight+=children.get(n).getWeight(); } // fit theta angles float theta = t0; for (int n=0;n<children.size();n++) { Sector obj = children.get(n); obj.t0 = theta; // adjust theta according to weight and space available theta += omega * obj.getWeight()/childWeight; obj.t1 = theta; } } float getWeight() { float wt = mag; for (int n=0;n<children.size();n++) { Sector obj = children.get(n); wt += obj.getWeight(); } return wt; } float getThrow() { float tt = thw; for (int n=0;n<children.size();n++) { Sector obj = children.get(n); tt += obj.getThrow(); } return tt; } Sector didClick() { // did the mouse click this sector float mt = atan2(mouseY-height/2,mouseX-width/2)+HALF_PI; float mr = dist(width/2,height/2,mouseX,mouseY); // normalize thetas float normt0 = t0 + TWO_PI; if (normt0>TWO_PI) normt0-=TWO_PI; float normt1 = t1 + TWO_PI; if (normt1>TWO_PI) normt1-=TWO_PI; float normt = mt + TWO_PI; if (normt>TWO_PI) normt-=TWO_PI; //println("R:"+r0+" .. "+mr+" .. "+r1+" T:"+t0+" .. "+mt+" .. "+t1); if (normt>=normt0 && normt<normt1) { if (mr>=r0 && mr<r1) { return this; } } // not this one, check children for (int n=0;n<children.size();n++) { Sector hmm = children.get(n).didClick(); if (hmm!=null) return hmm; } return null; } void removeMe() { // remove this sector if (mother!=null) mother.removeSector(this); } void removeSector(Sector target) { for (int i=0;i<children.size();i++) { Sector obj = children.get(i); if (target==obj) { children.remove(i); } } } }