万華鏡 - Kaleidoscope
万華鏡 (KaleidoscopeController) by enok
画像はJPG, GIF, PNGに対応してます。サイズは200KBまでです。
画像サイズを400~600pxぐらいにするといい感じ。縦横の長さが違うと効果あります。
その他詳細はこちら http://linkalink.jp/enok/?p=573
/**
* Copyright linktale ( http://wonderfl.net/user/linktale )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/w9hC
*/
// 万華鏡 (KaleidoscopeController) by enok
//
// 画像はJPG, GIF, PNGに対応してます。サイズは200KBまでです。
// 画像サイズを400~600pxぐらいにするといい感じ。縦横の長さが違うと効果あります。
//
// http://linktale.net/
package {
import flash.display.Sprite;
[SWF(backgroundColor="0x000000", frameRate="24")]
public class KaleidoscopeController extends Sprite {
public function KaleidoscopeController():void {
//背景をしく
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill();
//万華鏡を配置
var trick:Kaleidoscope = new Kaleidoscope(this);
addChild(trick);
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.DisplayObjectContainer;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Timer;
//万華鏡本体
class Kaleidoscope extends Sprite {
protected var _centerX:Number; //中心X
protected var _centerY:Number; //中心Y
protected var _imgBmp:Bitmap; //読込画像ビットマップ
protected var _sec:Sector; //扇クラス
protected var _partsBmpArray:Array; //万華鏡のパーツ配列
protected var _partsAngle:Number = 30; //一つの万華鏡の角度
protected var _ksRadius:Number = 0; //万華鏡の半径
protected var _imgParam:Object = new Object(); //画像のパラメータ配列
protected var _maskBmpData:BitmapData; //扇型マスクのビットマップデータ
protected var _fileup:fileUpload; //ファイルアップクラス
protected var _viewSp:Sprite; //万華鏡スプライト
public function Kaleidoscope(s:DisplayObjectContainer):void {
//中点
_centerX = s.stage.stageWidth / 2;
_centerY = s.stage.stageHeight / 2;
//初期画像の取得
var imgLoader:ImageLoader = new ImageLoader(this, "http://linkalink.jp/enok/wonderfl/kaleidoscope/images/sample/1.jpg");
imgLoader.addEventListener(ImageLoader.LOAD_COMPLETE, init);
}
//ロード画像の初期化
protected function init(e:Event):void {
//画像変数初期化
_imgParam["angle"] = 0.0;
_imgParam["scale"] = 1.0;
_imgParam["vx"] = 0.0;
_imgParam["vec"] = 1;
//画像のビットマップ化
var loader:Loader = e.currentTarget.loader;
var imgBmpData:BitmapData = new BitmapData(loader.width, loader.height);
imgBmpData.draw(loader);
_imgBmp = new Bitmap(imgBmpData);
//長い方の片を万華鏡の半径にする
_ksRadius = Math.min(Math.max(loader.width, loader.height), 420) / 2;
//扇型クラス取得
_sec = new Sector(0, 0, _partsAngle, 0, _ksRadius);
//扇型マスクのBitmap化
_maskBmpData = new BitmapData(_imgBmp.width, _imgBmp.height, true, 0x00000000);
_maskBmpData.draw(_sec);
//万華鏡パーツの設置
_viewSp = new Sprite();
_partsBmpArray = new Array()
for (var i:uint = 0; i < Math.ceil(360 / _partsAngle); i++ ) {
var partsBmp:Bitmap = new Bitmap();
_partsBmpArray.push(partsBmp);
_viewSp.addChild(partsBmp);
}
//追加
addChild(_viewSp);
addEventListener( Event.ENTER_FRAME, update );
//ファイルアップ系
_fileup = new fileUpload(this);
_fileup.addEventListener(fileUpload.UP_COMPLETE, changeImgLoad);
}
//繰り返し処理
protected function update(e:Event):void {
copyKsParts( createKsParts() );
}
//扇型画像作成
protected function createKsParts():BitmapData {
//画像ビットマップの変形処理
var mat:Matrix = new Matrix();
mat.translate( -_ksRadius, -_ksRadius);
if (_ksRadius - stage.mouseX > 0) {
_imgParam["vec"] = 1.0;
}else {
_imgParam["vec"] = -1.0;
}
var dist:Number = Math.sqrt(Math.pow(_centerX - stage.mouseX, 2) + Math.pow(_centerY - stage.mouseY, 2))
_imgParam["vx"] = dist / _ksRadius * Math.PI * _imgParam["vec"];
_imgParam["angle"] += _imgParam["vx"] * 0.02;
mat.rotate(_imgParam["angle"]);
_imgParam["scale"] = Math.min(1 / (dist / _ksRadius), 1.0);
mat.scale(_imgParam["scale"], _imgParam["scale"]);
//画像ビットマップマップデータ化
var imgBmpData:BitmapData = new BitmapData(_imgBmp.height, _imgBmp.height, true, 0x00000000);
imgBmpData.draw(_imgBmp, mat);
//画像と扇型マスクを合体
imgBmpData.copyChannel(_maskBmpData, new Rectangle(0, 0, _imgBmp.width, _imgBmp.height), new Point(0, 0), BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
//処理後のビットマップマップデータを返す
return imgBmpData;
}
//扇型画像をコピー
protected function copyKsParts(imgBmpData:BitmapData):void {
for (var i:uint = 0; i < _partsBmpArray.length; i++) {
var mat:Matrix = new Matrix();
//配置処理
if (i % 2 != 0) {
mat.scale( 1.0, -1.0);
mat.rotate(_partsAngle * Math.PI / 180);
}
mat.rotate((i * _partsAngle - 90) * Math.PI / 180);
mat.translate(_centerX, _centerY);
//反映
_partsBmpArray[i].transform.matrix = mat;
_partsBmpArray[i].bitmapData = imgBmpData;
}
}
//画像変更
protected function changeImgLoad(e:Event):void {
//画像ロード
var imgLoader:ImageLoader = new ImageLoader(this, "http://linkalink.jp/enok/wonderfl/kaleidoscope/images/users/"+_fileup.name);
imgLoader.addEventListener(ImageLoader.LOAD_COMPLETE, changeImg);
}
//画像変更処理
protected function changeImg(e:Event):void {
//画像のビットマップ化
var loader:Loader = e.currentTarget.loader;
var imgBmpData:BitmapData = new BitmapData(loader.width, loader.height);
imgBmpData.draw(loader);
_imgBmp = new Bitmap(imgBmpData);
//万華鏡半径算出
_ksRadius = Math.min(Math.max(loader.width, loader.height), 420) / 2;
}
}
//扇型クラス
//sketchbook参考にさせて頂きました
class Sector extends Sprite {
public function Sector(px:Number, py:Number, partsRotate:Number, startAngle:Number, ksRadius:Number):void {
var points:Array = getArcPoints(px, py, ksRadius, partsRotate, startAngle, 180);
points.unshift( new Point(x, y) );
drawLines(points);
}
//扇形、円弧と中心点を結んだ形状を算出
private function getArcPoints(x:Number, y:Number, radius:Number, degree:Number, fromDegree:Number=0, split:Number=36):Array{
var points:Array = new Array();
var fromRad:Number = fromDegree * Math.PI / 180;
var dr:Number = (degree * Math.PI / 180) / split;
for(var i:int=0; i<split + 1; i++){
var pt:Point = new Point();
var rad:Number = fromRad + dr * i;
pt.x = Math.cos(rad) * radius + x;
pt.y = Math.sin(rad) * radius + y;
points.push(pt);
}
return points;
}
//扇を描画
public function drawLines(points:Array):void {
graphics.lineStyle(1, 0xffffff);
graphics.beginFill(0xffffff);
graphics.moveTo(points[0].x, points[0].y);
for(var i:Number=1; i<points.length; i++){
graphics.lineTo(points[i].x, points[i].y);
}
}
}
import flash.events.ProgressEvent;
import flash.events.IOErrorEvent;
import flash.events.TimerEvent;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.system.LoaderContext;
import flash.net.URLRequest;
//画像ローダーディスパッチャー
class ImageLoader extends EventDispatcher {
public static const LOAD_COMPLETE:String = "LOAD_COMPLETE";
public static const IOERROR:String = "IOERROR";
protected var _loader:Loader;
protected var _sv:statusView;
protected var _timer:Timer;
public function ImageLoader(s:DisplayObjectContainer , url:String) {
//登録
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, error);
//セキュリティ
var loaderContext:LoaderContext = new LoaderContext(true);
//画像ロード開始
var urlReq:URLRequest = new URLRequest(url);
_loader.load(urlReq, loaderContext);
//ステータス表示
_sv = new statusView();
_sv.view("IMAGE LOAD START");
s.addChild(_sv);
s.setChildIndex(_sv, 0);
}
//画像ロード完了
protected function onLoaded(e:Event):void {
_sv.view("");
dispatchEvent(new Event(LOAD_COMPLETE));
}
//画像ロード中
protected function onProgress(e:ProgressEvent):void {
_sv.view("IMAGE LOADING...");
//var per:Number = Math.round(e.bytesLoaded / e.bytesTotal * 100);
}
//エラー
protected function error(e:IOErrorEvent):void {
_sv.view("IMAGE LOAD ERROR");
_timer = new Timer(3000, 1);
_timer.addEventListener(TimerEvent.TIMER, onTimer);
_timer.start();
dispatchEvent(new Event(IOERROR));
}
protected function onTimer(event:TimerEvent):void {
_sv.view("");
_timer.removeEventListener(TimerEvent.TIMER, onTimer);
}
//プロパティ
public function get loader():Loader { return _loader;}
}
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.net.FileReference;
import flash.net.FileFilter;
//ファイルアップディスパッチャ
class fileUpload extends EventDispatcher {
public static const UP_COMPLETE:String = "UP_COMPLETE";
protected var s:DisplayObjectContainer;
protected var fileRef:FileReference;;
protected var uploadURL:URLRequest;
protected var _sv:statusView;
public function fileUpload(ps:DisplayObjectContainer):void {
s = ps;
//初期化
fileRef = new FileReference();
fileRef.addEventListener(Event.SELECT, onSelect);
fileRef.addEventListener(ProgressEvent.PROGRESS , onProgress);
fileRef.addEventListener(Event.COMPLETE, onComplete);
uploadURL = new URLRequest();
uploadURL.url = "http://linkalink.jp/enok/wonderfl/kaleidoscope/upload.php";
//ボタン設置
var upBtn:customButton = new customButton(s);
upBtn.x = 5;
upBtn.y = s.stage.stageHeight - upBtn.height - 5;
//ステータス表示
_sv = new statusView();;
s.addChild(_sv);
s.setChildIndex(_sv, 0);
//追加
s.addChild(upBtn);
upBtn.addEventListener(MouseEvent.MOUSE_DOWN, function(event:Event):void{ var fileFilter:FileFilter = new FileFilter("Images", "*.jpg;*.gif;*.png"); fileRef.browse([fileFilter]);});
}
//ファイル選んだ時
protected function onSelect(e:Event):void {
var fileRef:FileReference = FileReference(e.target);
fileRef.upload(uploadURL);
}
//アップが完了
protected function onProgress(e:Event):void {
_sv.view("FILE UPLOADING...");
}
//アップが完了
protected function onComplete(e:Event):void {
_sv.view("");
dispatchEvent(new Event(UP_COMPLETE));
}
//プロパティ
public function get name():String {
return fileRef.name;
}
}
import flash.geom.ColorTransform;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
//ボタンクラス
class customButton extends SimpleButton {
private var s:DisplayObjectContainer;
public function customButton(ps:DisplayObjectContainer):void {
s = ps;
//ボタンの色とか設定
var state:Sprite = makeUpstate();
state.transform.colorTransform = new ColorTransform(1, 1, 1, 0.9, 0, 0, 0, 0);
downState = upState = state;
state = makeUpstate();
state.transform.colorTransform = new ColorTransform(1, 1, 1, 0.8, 0, 0, 0, 0);
overState = state;
useHandCursor = true;
hitTestState = upState;
}
//ボタン画像作成
protected function makeUpstate():Sprite {
var state:Sprite = new Sprite();
var w:Number = 50;
var h:Number = 10;
var margin:Number = 2;
//枠系
state.graphics.lineStyle(1, 0xffffff);
state.graphics.drawRect(0, 0, w + margin * 2, h + margin * 2);
state.graphics.endFill();
state.graphics.beginFill(0xffffff);
state.graphics.drawRect(margin, margin, w, h);
state.graphics.endFill();
//テキスト系
var txtFormat:TextFormat = new TextFormat();
txtFormat.font = "_sans";
txtFormat.size = 10;
txtFormat.color = 0xcc2222;
txtFormat.bold = true;
var txtField:TextField = new TextField();
txtField.defaultTextFormat = txtFormat;
txtField.text = "CHANGE";
txtField.autoSize = TextFieldAutoSize.LEFT;
txtField.x = 4;
txtField.y = -1;
state.addChild(txtField);
return state;
}
}
class statusView extends Sprite {
protected var _txtField:TextField;
public function statusView():void {
//テキスト系
var txtFormat:TextFormat = new TextFormat();
txtFormat.font = "_sans";
txtFormat.size = 10;
txtFormat.color = 0xeeeeee;
//txtFormat.bold = true;
_txtField = new TextField();
_txtField.defaultTextFormat = txtFormat;
_txtField.text = "";
_txtField.autoSize = TextFieldAutoSize.LEFT;
_txtField.x = 0;
_txtField.y = 0;
addChild(_txtField);
}
public function view(mess:String):void {
_txtField.text = mess;
}
}