forked from: Kinetic Scroll
/**
* Copyright sanoi ( http://wonderfl.net/user/sanoi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/5cfy
*/
// forked from gggiyeok's Kinetic Scroll
package {
import flash.display.AVM1Movie;
import flash.display.Sprite;
import com.bit101.components.*;
import flash.events.*;
import flash.utils.*;
public class FlickList extends Sprite {
/*
minimalComps를 Flash IDE에서 사용시 폰트임베트 시키기
Style.embedFonts = true;
var font = new FontA();
Style.fontName = font.fontNuint
*/
private var listCnt:uint=200000;
private var listItemH:uint=40;
private var listH:uint=200;
private var totalH:uint=listItemH*listCnt;
private var containerPosY:int = 50;
private var tCnt:uint=0;
private var tension:Array=[.5,.3,.2,.1,0];
private var tmpY:Number=0;
private var dragStatus:int=0;//tensino direction
private var tensionPosSum:Number=0;
private var cy:Number=0;
private var listW:uint=300;
private var viewCnt:uint=Math.ceil(listH/listItemH)*2;
private var listContainer:Panel;
private var scrollValue:Number=0;
private var listItems:Array
private var scrollBar:VScrollBar;
private var dy:Number=0;
private var flickTime:Number;
private var spd:int;
public function FlickList(){
listItems = new Array();
if (listCnt<int(listH/listItemH)) {
totalH=listH;
}
listContainer =new Panel(this, 0, containerPosY);
listContainer.setSize(listW, listH);
scrollBar = new VScrollBar(this,listW,containerPosY,changeScroll);
scrollBar.setSize(10, listH);
scrollBar.setThumbPercent(listItemH/(totalH-listH));
var max:int=totalH-listH;
if (max<0) {
max=0;
}
scrollBar.setSliderParams(0, max, 0);
init();
}
private function init() :void{
for (var i:uint = 0; i < viewCnt; i++) {
var item:ListItem = new ListItem(listContainer.content,0,listItemH*i);
item.y = listItemH*i;
//listContainer.addChild(item);
item.setSize(listW, listItemH);
listItems.push(item);
if (i<listCnt) {
item.data={label:String(i),id:i};
} else {
item.data={label:'',id:i};
}
}
listContainer.addEventListener(MouseEvent.MOUSE_DOWN, down);
}
private function changeScroll(e:Event) :void{
scrollJump(scrollBar.value);
}
/* scroll by scorllBar */
private function scrollJump(val:Number):void{
var index:int=int(val/listItemH);
var iy:Number = listItemH*(index) - val;
for (var i:uint = 0; i < viewCnt; i++) {
var item:ListItem=listItems[i];
item.y = iy + listItemH * i;
var newIndex:int = i + index;
item.data = { label:String(newIndex), id:newIndex };
item.visible = true;
if (newIndex < 0 || newIndex > listCnt-1) item.visible = false;
}
cy = -val;
}
private function down(e:MouseEvent) :void{
dy=mouseY;
flickTime=getTimer();
removeEventListener(Event.ENTER_FRAME, flickList);
removeEventListener(Event.ENTER_FRAME, rewind);
stage.addEventListener(MouseEvent.MOUSE_UP, endDrag);
e.currentTarget.addEventListener(Event.ENTER_FRAME, drag);
tensionPosSum=0;
tmpY=0;
}
private function endDrag(e:MouseEvent) :void{
removeEventListener(Event.ENTER_FRAME, flickList);
if (dragStatus>0) {
tmpY=cy;
addEventListener(Event.ENTER_FRAME, rewind);
} else if (dragStatus < 0) {
tmpY = (totalH-listH)+cy;
addEventListener(Event.ENTER_FRAME, rewind);
}
if (Math.abs(spd)>10&&dragStatus==0) {
addEventListener(Event.ENTER_FRAME, flickList);
}
listContainer.removeEventListener(Event.ENTER_FRAME, drag);
}
private function rewind(e:*=null) :void{
listContainer.removeEventListener(Event.ENTER_FRAME, drag);
//Floating-point 에러 보정
var divideVal:int=Math.round(tmpY*tension[tCnt]);
if (tCnt==tension.length-2) {
divideVal=tmpY-tensionPosSum;
}
tensionPosSum+=divideVal;
tCnt++;
scroll(-divideVal);
if (tCnt==tension.length) {
removeEventListener(Event.ENTER_FRAME, rewind);
tensionPosSum=0;
tCnt=0;
}
}
private function flickList(e:Event) :void{
spd*=.9;
//상하 리스트의 끝자리에서 크게 flick했을 때 텐션 범위 조절
if(spd < 0){
if(cy > listH/4) spd*=.4;
}else if( spd > 0){
if(cy+listH < -(totalH-listH)) {
spd*=.4;
}
}
if (Math.abs(spd)<1) {
removeEventListener(Event.ENTER_FRAME, flickList);
//되돌아가기
if (dragStatus>0) {
tmpY=cy;
addEventListener(Event.ENTER_FRAME, rewind);
} else if (dragStatus < 0) {
tmpY = (totalH-listH)+cy;
addEventListener(Event.ENTER_FRAME, rewind);
}
return;
}else scroll(-spd);
}
private function drag(e:Event) :void{
spd=dy-mouseY;
dy=mouseY;
flickTime=getTimer();
var abs:Number=Math.abs(spd);
if (abs>0) {
scroll(-spd);
}
}
private function scroll(val:Number) :void{
cy+=val;
var i:int,item:ListItem,id:int;
if (-(totalH-listH) > cy ) dragStatus=-1; //pull up
else if (cy > 0) dragStatus=1; //pull down
else dragStatus=0; // drag
var popItem:Vector.<ListItem> = new Vector.<ListItem>();
if (val<0) {
for (i = 0; i < viewCnt; i++) {
item=listItems[i];
item.y+=val;
if (item.y+item.height<0) {
popItem.push(item);
}
}
if (dragStatus!=0) return;
if (popItem.length>0) {
for (i = 0; i < popItem.length; i++) {
item=listItems.shift();
var prev:ListItem=listItems[listItems.length-1];
id=prev.data.id+1;
if (id>listCnt-1) {
item.visible=false;
} else {
item.visible=true;
}
item.data={label:String(prev.data.id+1),id:prev.data.id+1};
item.y=prev.y+listItemH;
listItems.push(item);
}
}
} else if (val > 0) {
for (i = 0; i < viewCnt; i++) {
item=listItems[i];
item.y+=val;
if (item.y>listH) {
popItem.push(item);
}
}
if (dragStatus!=0)return;
if (popItem.length>0) {
for (i = 0; i < popItem.length; i++) {
item=listItems.pop();
var next:ListItem=listItems[0];
id=next.data.id-1;
if (id<0) {
item.visible=false;
} else {
item.visible=true;
}
item.data={label:String(next.data.id-1),id:next.data.id-1};
item.y=listItems[0].y-item.height;
listItems.unshift(item);
}
}
}
scrollBar.value=- cy;
}
}
}