forked from: bubble sort
bubble sorting visualization.
inspired on http://wonderfl.net/c/8rbD
for Universidade Federal de Itajubá - Campus Itabira
git https://github.com/thyfl/eco-010/tree/master/fabiana/extras/bubble (11 november 2011, now its colored. but still not ready)
/**
* Copyright Thy ( http://wonderfl.net/user/Thy )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/kGYT
*/
package
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
/**
* bubble sorting visualization.
* inspired on http://wonderfl.net/c/8rbD
* for Universidade Federal de Itajubá - Campus Itabira
* git https://github.com/thyfl/eco-010/tree/master/fabiana/extras/bubble (11 november 2011, now its colored. but still not ready)
* @author thi
*
*
* TODO: environment blubbles force map
* TODO: environment blubbles proper reposition on zooming/resizing
* TODO: full screen button
*
*/
public class Main extends Sprite
{
public function Main():void
{
// setup
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.frameRate = 40;
// children
this.addChild(ground.back); // background
this.addChild(bubbles.bubbles); // bubbles
this.addChild(text); // input
this.addChild(text2); // result
this.addChild(ground.front); // foreground
// event
this.addEventListener(Event.ENTER_FRAME, ef);
stage.addEventListener(Event.RESIZE, resize);
// var
s = text.tf.text;
// init
resize();
// bubbles
bubbles.init(s, radius);
bubbles.bubbles.y = 20; // user's bubbles
// text
stage.focus = text.tf;
text.tf.setSelection(0, text.tf.text.length);
text.x = text.y = text2.x = 0; // text
// ground bubbles
groundBubblesInit();
}
//
private var ground:Ground = new Ground(), // background, foreground
//
bubbles:Bubbles = new Bubbles(), // bubble's list's list
backBubbles:Bubbles = new Bubbles(),
frontBubbles:Bubbles = new Bubbles(),
//
s:String = "",
text:Field = new Field(), // input text
text2:Field = new Field(), // sorted text
//
W:Number = 0,
H:Number = 0,
radius:Number = Math.PI * .75; // radius from an sphere's volume input
private function groundBubblesInit():void
{
// create background and foreground bubbles
var i:int = -1, bs:Bubbles = backBubbles, s:String;
while (++i < 5)
{
bs.next = new Bubbles();
bs = bs.next;
ground.back.addChild(bs.bubbles);
s = String(int(Math.random() * Math.random() * 1000));
bs.init(s, radius);
bs.bubbles.y = 0;
bs.bubbles.x = -20;
}
i = -1;
bs = frontBubbles;
while (++i < 5)
{
bs.next = new Bubbles();
bs = bs.next;
ground.front.addChild(bs.bubbles);
s = String(int(Math.random() * Math.random() * 1000));
bs.init(s, radius);
bs.bubbles.y = 0;
bs.bubbles.x = -20;
}
}
private function resize(e:Event = null):void
{
// app dimension
W = stage.stageWidth;
H = stage.stageHeight;
// texts
text.resize(W, H);
text2.resize(W, H);
text2.y = H - 20;
// ground
ground.resize(W,H);
// bubbles
var b:Bubbles = bubbles;
b.bubbles.x = W / 2;
/*
b = backBubbles;
while (b = b.next)
{
b.bubbles.x = W / 2;
}
b = frontBubbles;
while (b = b.next)
{
b.bubbles.x = W / 2;
}
*/
}
private function ef(e:Event):void
{
// re init user's bubbles
if (s != text.tf.text && ++text.time > text.timeOut)
{
text.time = 0;
s = text.tf.text;
if (s == "") s = "1";
bubbles.init(s, radius);
}
var b:Bubbles = bubbles;
// move & sort user's bubbles
text2.tf.text = b.sort(); // user's
var zoom:Number = b.zoom(W, H); // adjust the bubbles zooming
var dx:Number, dy:Number, s2:String, offset:Number;
// move & sort back/foreground bubbles
b = backBubbles;
while (b = b.next)
{
b.sort();
b.apllyZoom(zoom);
dx = Math.random() - .5;
dy = -10;
if (!b.move(W, H, dx, dy))
{
s2 = String(int(Math.random() * Math.random() * 1000));
offset = Math.random();
b.replace(W, H, s2, radius, offset);
}
}
b = frontBubbles;
while (b = b.next)
{
b.sort();
b.apllyZoom(zoom);
dx = Math.random() - .5;
dy = -10;
if (!b.move(W, H, dx, dy))
{
s2 = String(int(Math.random() * Math.random() * 1000));
offset = Math.random() * Math.random() * 2;
b.replace(W, H, s2, radius/8, offset*8);
}
}
}
}
}
import flash.filters.BlurFilter;
/**
* bubble list
* @author thi
*/
class Bubbles
{
public var next:Bubbles,
bubbles:Bubble = new Bubble(), // head
garbage:Bubble = new Bubble(), // head
//
rMultiplier:Number,
rOffset:Number;
public function Bubbles(rm:Number = 1, ro:Number = 1)
{
rMultiplier = rm;
rOffset = ro;
}
// radius multiplier, radius offset
public function init(s:String = "1", rm:Number = 1, ro:Number = 1):void
{
rMultiplier = rm;
rOffset = ro;
var b:Bubble = bubbles,
b2:Bubble = bubbles,
i:int = -1,
l:int = s.length;
// modify bubbles
while ((b = b.next) !== null && ++i < l)
b2 = b.draw(Number(s.charAt(i)), rMultiplier, rOffset);
b = b2; // b is the last modified bubble
// recycle bubbles
b2 = garbage;
while (++i < l && (b2 = b2.next) !== null)
{
garbage.next = b2.next;
b2.next = null;
b2.prev = b;
bubbles.addChild(b2.draw(Number(s.charAt(i)), rMultiplier, rOffset));
b.next = b2;
b = b.next;
}
--i;
// b is the last modified bubble
// create bubbles
while (++i < l)
{
b.next = new Bubble();
b.next.prev = b;
b = b.next.draw(Number(s.charAt(i)), rMultiplier, rOffset);
bubbles.addChild(b);
}
--i;
// b is the newest or last modified bubble
// add bubbles to garbage, prev pointer ignored
if (i == l)
{
var b3:Bubble = b2 = b;
while ((b2 = b2.next) !== null)
{
bubbles.removeChild(b2.clear());
b3 = b2; // last cleared
}
b3.next = garbage.next;
garbage.next = b.next;
b.next = null;
}
bubbles.next.prev = null; // dont need to go back to head, when backwards
} // init
public function sort():String
{
var b:Bubble = bubbles,
//b2:Bubble, // hold last bubble
next:Bubble,
s:String = "";
// get the angle for the movement right
while ((b = b.next) !== null)
{
// finish when we got to the last bubble
if ((next = b.next) === null)
break;
s += String(b.info); // sorted string
// you shall not pass
if (next.info >= b.info)
{
b.passing = false;
b.teta *= .2;
continue;
}
// shall pass
{
b.passing = true;
// now the angle
b.teta += next.radius / b.radius * .04 + b.teta * .2;
//b.teta += .1;
if (next.passing && next.next)
b.teta *= 0.8;
// already passed
if (b.teta > Math.PI)
{
//b.teta *= 0.1;
//b.teta = 0;
// pointer mess
next.prev = b.prev;
b.prev = next;
b.next = next.next;
next.next = b;
// (now works like like b is next; next is b)
if (next.prev === null)
bubbles.next = next;
else
next.prev.next = next;
if (b.next)
b.next.prev = b;
else
b = next;
}
}
} // while's angle stuff
s += String(b.info); // last char
_upper = b; // b is the last/up bubble; _upper is used on zooming
// adjust the upper bubble position
b.x = 0;
b.y = b.radius;
// move the bubbles
while (b = b.prev)
{
next = b.next;
// passing
if (b.passing)
{
var r:Number = (next.radius + b.radius) / 2; // average radius
var xc:Number = (b.x + next.x) / 2; // x center
var yc:Number = (b.y + next.y) / 2; // y center
var sin:Number = Math.sin(b.teta) * r;
var cos:Number = Math.cos(b.teta) * r;
b.x = xc + sin;
b.y = yc + cos;
// move the next bubble
if (next.next)
{
next.x = xc - sin;
next.y = yc - cos;
continue;
}
// move only a little, the last/upper bubble
{
next.x += (xc - sin - next.x) * .1;
next.y += (yc - cos - next.y) * .1;
}
continue;
}
// not passing
{
b.x += (next.x - b.x ) * .7 + Math.random() * 1 - .5;
b.y += (next.y + next.radius + b.radius - b.y ) * .7;
}
} // while's movement stuff
return s;
} // sort
// adjust the bubbles zoom
private var _upper:Bubble;
public function zoom(W:Number, H:Number):Number
{
// TODO? fix the width.. bug dont looks bad.
var _y:Number = _upper.height + 5;
var _h:Number = (bubbles.height + _y) / bubbles.scaleY;
var min:Number = Math.min(W / bubbles.width, (H - _y) / _h);
bubbles.scaleX = bubbles.scaleY += (min - bubbles.scaleY) * .2;
return bubbles.scaleY;
}
// now functions for automatic bubbles -----------------------------------------------
public function apllyZoom(zoom:Number):void
{
bubbles.scaleX = bubbles.scaleY = zoom;
}
private var blur:BlurFilter = new BlurFilter(0, 0, 1);
public var upSpeed:Number; // TODO: maybe use that instead the forceMap
public function move(W:Number, H:Number, dx:Number, dy:Number):Boolean
{
// move the bubble
bubbles.x += dx * rOffset;
bubbles.y += dy * rOffset;
dx = bubbles.x - W/2;
dy = bubbles.y - H / 2;
dy *= .75;
dx *= 1;
// apply blur
blur.blurX = blur.blurY = Math.sqrt(dx * dx + dy*dy) * .05 + rOffset*2;
bubbles.filters = [blur];
if (bubbles.x > W + 20 || bubbles.x < -20 || bubbles.y < -bubbles.height - 20)
return false;
return true;
}
public function replace(W:Number, H:Number, s:String, rm:Number = 1, ro:Number = 1):void
{
init(s, rm, ro);
bubbles.x = Math.random() * W;
bubbles.y = H + bubbles.height + 20;
}
}
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.filters.GlowFilter;
/**
* blub.
* TODO: make it pretty.
* @author thi
*/
class Bubble extends Sprite
{
public var next:Bubble,
prev:Bubble,
//
info:Number, // the sphere's volume
radius:Number,
teta:Number = 0, // the movement
passing:Boolean; // if going up
public function Bubble()
{
//var glow:GlowFilter = new GlowFilter(0x707090, 1, 6, 6, 5, 3, false, false);
//this.filters = [glow];
//this.blendMode = BlendMode.HARDLIGHT;
}
// vector without bmData's cpyPixel
public function draw(info:Number, rm:Number, ro:Number):Bubble
{
// information
this.info = info;
radius = rm * info * ro;
// draw it
var g:Graphics = this.graphics;
g.clear();
//g.lineStyle(.5 , 0xFFFFFF, .1);
g.beginFill(0xD0E0F0, .4);
g.drawCircle(0, 0, radius);
g.endFill();
g = null;
return this;
}
public function clear():Bubble
{
this.graphics.clear();
return this;
}
}
import flash.display.Graphics;
import flash.display.Sprite;
import flash.filters.GlowFilter;
import flash.geom.Matrix;
/**
* back/fore ground.
* @author thi
*/
class Ground
{
public var back:Sprite,
front:Sprite;
public function Ground()
{
back = new Sprite();
front = new Sprite();
back.cacheAsBitmap = true;
front.cacheAsBitmap = true;
}
public function resize(W:Number, H:Number):void
{
var g:Graphics = back.graphics;
g.clear();
g.moveTo(0, 0);
var colors:Array = [0xC4E6F5, 0x435268];
var alphas:Array = [1, 1];
var ratios:Array = [0, 255];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(W, H, 90*Math.PI/180, 0, 0);
g.beginGradientFill("linear", colors, alphas, ratios, matrix);
g.drawRect(0, 0, W, H);
g.endFill();
var glow:GlowFilter = new GlowFilter(0, .3, 256, 296, 1, 2, true);
back.filters = [glow];
}
}
import flash.display.Graphics;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* input/output textfield
* @author thi
*/
class Field extends Sprite
{
public var time:int = 0,
timeOut:int = 30,
tf:TextField;
private var g:Graphics;
public function Field()
{
var f:TextFormat = new TextFormat("Arial", 14);
tf = new TextField();
tf.defaultTextFormat = f;
tf.type = "input";
tf.text = "9991232387418521";
//tf.text = "231232938741895211111111111111111111111111111111111111111111111";
//tf.text = "11111111111111119999999999999999911111111111111111111199999999999991111111111111111999999999999911111111111119999999999999111111111999999999991111111111111";
tf.textColor = 0xFFFFFF;
tf.height = 20;
tf.multiline = false;
this.addChild(tf);
// debug
tf.border = true;
}
public function resize(W:Number, H:Number):void
{
// text
tf.width = W;
// background
g = this.graphics;
g.beginFill(0, .8);
g.drawRect(0, 0, W, 20);
g.endFill();
g = null;
}
}