Spiro
Mouse over to see the wheels and buttons. Drag the wheels to change the radius and speed. Add/subtract wheels using the buttons. Click anywhere to clear the canvas.
/**
* Copyright royi ( http://wonderfl.net/user/royi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/mL1u
*/
package {
import flash.events.MouseEvent;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width=465, height=465, frameRate=60, backgroundColor=0x000000)]
public class Spiro extends Sprite {
private static const BG_COLOR:uint = 0x000000;
private static const CANVAS_COLOR:uint = 0x00000000;
private static const NUM_WHEELS:int = 3;
private static const SPARK_COLOR:uint = 0xffff00ff;
private static const NUM_SPARKS:int = 200;
private static const GRAVITY:Number = 0.05;
private var _colors:Array;
private var _radii:Array;
private var _wheels:Array = [];
private var _sparks:Array = [];
private var _counter:int = 0;
private var _pointX:Number, _pointY:Number;
private var _paused:Boolean = false;
private var _changed:Boolean = true;
private var _bg:Sprite = new Sprite();
private var _addBtn:Sprite = new Sprite();
private var _subtractBtn:Sprite = new Sprite();
private var _canvas:BitmapData;
private var _sparksCanvas:BitmapData;
private var _bmp:Bitmap;
private var _sparksBmp:Bitmap;
private var _sw:Number, _sh:Number;
private var _centerX:Number, _centerY:Number;
public function Spiro() {
_sw = stage.stageWidth, _sh = stage.stageHeight;
_centerX = _sw/2;
_centerY = _sh/2;
_bg.graphics.beginFill(BG_COLOR);
_bg.graphics.drawRect(0, 0, _sw, _sh);
_bg.graphics.endFill();
_sparksCanvas = new BitmapData(_sw, _sh, true, 0x000000);
_sparksBmp = new Bitmap(_sparksCanvas);
_canvas = new BitmapData(_sw, _sh, false, CANVAS_COLOR);
_bmp = new Bitmap(_canvas, "auto", true);
_colors = [
0xff008a,
0xb20095,
0x7a009d,
0x4700a5,
0x5900a2,
0xd00090,
0x970099,
0xc90092,
0xff008a
];
_radii = [
36,
22,
47,
24,
21,
26,
28,
30,
33
];
_addBtn.graphics.beginFill(_colors[0]);
_addBtn.graphics.drawCircle(0, 0, 16);
_addBtn.graphics.endFill();
_addBtn.graphics.lineStyle(4, 0x000000);
_addBtn.graphics.moveTo(-7, 0);
_addBtn.graphics.lineTo(7, 0);
_addBtn.graphics.moveTo(0, -7);
_addBtn.graphics.lineTo(0, 7);
_addBtn.x = 40;
_addBtn.y = 40;
_addBtn.buttonMode = true;
_addBtn.name = "add";
_subtractBtn.graphics.beginFill(_colors[1]);
_subtractBtn.graphics.drawCircle(0, 0, 16);
_subtractBtn.graphics.endFill();
_subtractBtn.graphics.lineStyle(4, 0x000000);
_subtractBtn.graphics.moveTo(-7, 0);
_subtractBtn.graphics.lineTo(7, 0);
_subtractBtn.x = 80;
_subtractBtn.y = 40;
_subtractBtn.buttonMode = true;
_subtractBtn.name = "subtract";
addChild(_bmp);
addChild(_sparksBmp);
var hitArea:Sprite = new Sprite();
hitArea.graphics.beginFill(0x000000);
hitArea.graphics.drawRect(0, 0, _sw, _sh);
hitArea.graphics.endFill();
hitArea.alpha = 0;
addChild(hitArea);
_wheels[0] = new Wheel(_radii[0], _colors[0], stage);
addChild(_wheels[0]);
for (var i:int = 1; i < NUM_WHEELS; i++) {
_wheels[i] = new Wheel(_radii[i], _colors[i], _wheels[i-1]);
addChild(_wheels[i]);
}
addChild(_addBtn);
addChild(_subtractBtn);
onMouseOut(null);
_addBtn.addEventListener(MouseEvent.CLICK, onButtonClick);
_subtractBtn.addEventListener(MouseEvent.CLICK, onButtonClick);
stage.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
stage.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
addEventListener(Event.ENTER_FRAME, loop);
}
private function loop(e:Event):void {
if (_paused) return;
for (var i:int = 0; i < _wheels.length; i++) {
_wheels[i].update(_counter);
}
var lastWheel:Wheel = _wheels[_wheels.length-1];
_pointX = lastWheel.x + Math.sin(_counter * lastWheel.speed) * lastWheel.radius;
_pointY = lastWheel.y + Math.cos(_counter * lastWheel.speed) * lastWheel.radius;
var dx:Number = _pointX - _centerX;
var dy:Number = _pointY - _centerY;
var val:int = (Math.sqrt(dx * dx + dy * dy) / _centerY) * 255;
if (val > 255) val = 255;
var rgb:uint = rgbToHex(255 - val * .5, val * .2, val);
var argb:uint = 255 << 24 | rgb;
_bg.graphics.lineStyle(2, rgb);
if (_changed) {
_changed = false;
_bg.graphics.moveTo(_pointX, _pointY);
} else {
_bg.graphics.lineTo(_pointX, _pointY);
_canvas.draw(_bg);
_bg.graphics.clear();
_bg.graphics.moveTo(_pointX, _pointY);
}
_sparks[_counter % NUM_SPARKS] = {x:_pointX, y:_pointY, vx:(Math.random()*2)-1, vy:(Math.random()*2)-1, color:argb};
_sparksCanvas.lock();
_sparksCanvas.fillRect(_sparksCanvas.rect, 0x00000000);
var spark:Object;
for (var j:int = _sparks.length-1; j >= 0; j--) {
spark = _sparks[j];
spark.vy += GRAVITY;
spark.x += spark.vx;
spark.y += spark.vy;
_sparksCanvas.setPixel32(spark.x, spark.y, spark.color);
}
_sparksCanvas.unlock();
_counter++;
}
private function onButtonClick(e:MouseEvent):void {
if (e.currentTarget.name == "add") {
if (_wheels.length == _colors.length || _wheels.length == _radii.length) return;
var newWheel:Wheel = new Wheel(_radii[_wheels.length], _colors[_wheels.length], _wheels[_wheels.length-1]);
_wheels.push( newWheel );
addChild(newWheel);
} else if (e.currentTarget.name == "subtract" && _wheels.length > 1) {
removeChild(_wheels[_wheels.length-1]);
_wheels.pop();
}
}
private function onMouseOver(e:MouseEvent):void {
for (var i:int = _wheels.length-1; i >= 0; i--) {
_wheels[i].alpha = 1;
}
_addBtn.alpha = 1;
_subtractBtn.alpha = 1;
}
private function onMouseOut(e:MouseEvent):void {
for (var i:int = _wheels.length-1; i >= 0; i--) {
_wheels[i].alpha = 0;
}
_addBtn.alpha = 0;
_subtractBtn.alpha = 0;
}
private function onMouseDown(e:MouseEvent):void {
_paused = true;
}
private function onMouseUp(e:MouseEvent):void {
_bg.graphics.clear();
_canvas.fillRect(_canvas.rect, CANVAS_COLOR);
_changed = true;
for (var i:int = _wheels.length-1; i >= 0; i--) {
_wheels[i].dragging = false;
}
_paused = false;
}
private function onMouseMove(e:MouseEvent):void {
for (var i:int = 0; i < _wheels.length; i++) {
if (_wheels[i].dragging) {
var dx:Number = mouseX - _wheels[i].x;
var dy:Number = mouseY - _wheels[i].y;
_wheels[i].radius = Math.sqrt(dx * dx + dy * dy);
}
}
}
private function rgbToHex(r:int, g:int, b:int):uint {
var hex:uint = r << 16 | g << 8 | b;
return hex;
}
}
}
import flash.events.MouseEvent;
import flash.display.DisplayObject;
import flash.display.Stage;
import flash.display.Sprite;
class Wheel extends Sprite {
public var dragging:Boolean = false;
public var parentWheel:Wheel;
private var _speed:Number;
private var _radius:Number;
private var _color:uint;
public function Wheel(radius:Number, color:uint, parentWheel:DisplayObject) {
this.radius = radius;
this.color = color;
this.parentWheel = (parentWheel is Stage) ? null : Wheel(parentWheel);
this.buttonMode = true;
if (!this.parentWheel) {
this.x = Stage(parentWheel).stageHeight / 2;
this.y = Stage(parentWheel).stageWidth / 2;
}
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
public function update(counter:int):void {
if (!parentWheel) return;
this.x = parentWheel.x + Math.sin(counter * _speed) * (parentWheel.radius + _radius);
this.y = parentWheel.y + Math.cos(counter * _speed) * (parentWheel.radius + _radius);
}
public function refresh():void {
graphics.clear();
graphics.lineStyle(2, _color);
graphics.beginFill(0x000000, 0);
graphics.drawCircle(0, 0, _radius);
graphics.endFill();
}
public function get speed():Number {
return _speed;
}
public function get radius():Number {
return _radius;
}
public function set radius(value:Number):void {
if (value < 10) value = 10;
_radius = value;
_speed = value * .001;
graphics.clear();
graphics.lineStyle(2, _color);
graphics.beginFill(0x000000, 0);
graphics.drawCircle(0, 0, value);
graphics.endFill();
}
public function get color():uint {
return _color;
}
public function set color(value:uint):void {
_color = value;
graphics.clear();
graphics.lineStyle(2, value);
graphics.beginFill(0x000000, 0);
graphics.drawCircle(0, 0, _radius);
graphics.endFill();
}
private function onMouseDown(e:MouseEvent):void {
dragging = true;
}
private function onMouseUp(e:MouseEvent):void {
dragging = false;
}
}