X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;ds=sidebyside;f=0.6.x%2Fjs%2F20_ui%2F15_ScrollBox.js;h=e82a647c8036482834b8ca7d95c9cd54d1be6d35;hb=d56e8cc1e13089eb6cbc9dcc6900d7f1828b93df;hp=73f62b61965011975a95752d270d3a3025ce53de;hpb=8e63f506d14490e852fa557d326ca91f9cdd3baf;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/20_ui/15_ScrollBox.js b/0.6.x/js/20_ui/15_ScrollBox.js index 73f62b6..e82a647 100644 --- a/0.6.x/js/20_ui/15_ScrollBox.js +++ b/0.6.x/js/20_ui/15_ScrollBox.js @@ -1,33 +1,88 @@ +/* + * scroll 要素は常にひとつ + * ScrollManager + * indicatorX, Y は再利用 + */ +var XUI_ScrollBox_useCSSP = !X_UA[ 'IE5' ], + XUI_ScrollBox_current, + XUI_ScrollBox_indicatorV, + XUI_ScrollBox_indicatorH; + +function XUI_ScrollBox_start( scrollBox ){ + // 既存スクロールの停止 + if( XUI_ScrollBox_current && XUI_ScrollBox_current !== scrollBox ){ + XUI_ScrollBox_indicatorV && + XUI_ScrollBox_current[ 'unlisten' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorV, XUI_ScrollBox_indicatorHandleEvent ); + + XUI_ScrollBox_indicatorH && + XUI_ScrollBox_current[ 'unlisten' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorH, XUI_ScrollBox_indicatorHandleEvent ); + }; - -function X_UI_ScrollBox_momentum( current, start, time, lowerMargin, wrapperSize, deceleration ){ - var distance = current - start, - speed = Math.abs( distance ) / time, - destination, - duration; - - deceleration = deceleration === undefined ? 0.0006 : deceleration; - - destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); - duration = speed / deceleration; - - if( destination < lowerMargin ){ - destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; - distance = Math.abs( destination - current ); - duration = distance / speed; + if( scrollBox && scrollBox.hasVScroll ){ + if( !XUI_ScrollBox_indicatorV ){ + XUI_ScrollBox_indicatorV = X_Doc_create( 'div' )[ 'className' ]( 'ScrollBox-IndicatorV' ); + }; + if( scrollBox.xnode !== XUI_ScrollBox_indicatorV.parent ){ + console.log( '*** Scroll Indicator add ***' ); + scrollBox.xnode[ 'append' ]( XUI_ScrollBox_indicatorV ); + XUI_ScrollBox_indicatorV[ 'animate' ]({ + 'from' : { opacity : 0 }, + 'to' : { opacity : 0.5 }, + 'duration' : 900, + 'easing' : 'circular', + 'lazyRelease' : 300 + }); + scrollBox + [ 'listen' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorV, XUI_ScrollBox_indicatorHandleEvent ); + }; } else - if ( destination > 0 ) { - destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; - distance = Math.abs( current ) + destination; - duration = distance / speed; + if( XUI_ScrollBox_indicatorV ){ + console.log( '*** Scroll Indicator remove ***' ); + XUI_ScrollBox_indicatorV[ 'remove' ](); + }; + + if( scrollBox && scrollBox.hasHScroll ){ + if( !XUI_ScrollBox_indicatorH ){ + XUI_ScrollBox_indicatorH = X_Doc_create( 'div' )[ 'className' ]( 'ScrollBox-IndicatorH' ); + }; + if( scrollBox.xnode !== XUI_ScrollBox_indicatorH.parent ){ + scrollBox.xnode[ 'append' ]( XUI_ScrollBox_indicatorH ); + XUI_ScrollBox_indicatorH[ 'animate' ]({ + 'from' : { opacity : 0 }, + 'to' : { opacity : 0.5 }, + 'duration' : 900, + 'easing' : 'circular', + 'lazyRelease' : 300 + }); + scrollBox + [ 'listen' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorH, XUI_ScrollBox_indicatorHandleEvent ); + }; + } else + if( XUI_ScrollBox_indicatorH ){ + XUI_ScrollBox_indicatorH[ 'remove' ](); }; + + XUI_ScrollBox_current = scrollBox; +}; - return { - destination : Math.round( destination ), - duration : duration +function XUI_ScrollBox_indicatorHandleEvent( e ){ + //if( !XUI_ScrollBox_useCSSP ) return; + switch( e.type ){ + case X_EVENT_CANCELED : + case XUI_Event.SCROLL_END : + console.log( '-fadeout-' ); + this[ 'animate' ]({ + 'from' : { opacity : 0.5 }, + 'to' : { opacity : 0 }, + 'duration' : 900, + 'easing' : 'circular', + 'lazyRelease' : 300 + }); + break; }; }; + var X_UI_ScrollBox_SUPPORT_ATTRS = { // スクロール開始するために必要な移動距離、縦か横、どちらか制限する場合、より重要 directionLockThreshold : [ 10, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.LENGTH ], @@ -35,7 +90,7 @@ var X_UI_ScrollBox_SUPPORT_ATTRS = { scrollYEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], scrollEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], bounceEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], - bounceTime : [ 600, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.TIME ], + bounceTime : [ 300, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.TIME ], useWheel : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], useKey : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], hasScrollShadow : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], @@ -46,6 +101,8 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( '_ScrollBox', X_Class.NONE, { + layout : XUI_Layout_Canvas, + directionLockThreshold : 10, scrollXEnabled : true, scrollYEnabled : true, @@ -58,8 +115,6 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( hasScrollShadow : true, scrollShadowColor : '#000', - supportAttrs : XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_ScrollBox_SUPPORT_ATTRS ), - scrolling : false, initiated : '', @@ -67,7 +122,6 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( directionLocked : '', startTime : 0, endTime : 0, - isAnimating : false, isInTransition : false, hasHScroll : false, @@ -107,7 +161,7 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( Constructor : function( user, layout, args ){ this[ 'Super' ]( user, layout, args ); this._containerNode = X_Pair_get( this.containerNode ); - this.xnodeSlider = this._containerNode.xnode[ 'className' ]( 'ScrollSlider' ).listen( X_EVENT_ANIME_END, this, X_UI_ScrollBox_onAnimeEnd ); + this.xnodeSlider = this._containerNode.xnode[ 'className' ]( 'ScrollSlider' )[ 'listen' ]( X_EVENT_ANIME_END, this, X_UI_ScrollBox_onAnimeEnd ); this.xnode[ 'className' ]( 'ScrollBox' ); }, @@ -131,7 +185,8 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( this.lastScrollHeight !== this._containerNode.boxHeight || this.lastBoxWidth !== this.boxWidth || this.lastBoxHeight !== this.boxHeight ){ - X_UI_rootData[ 'listenOnce' ]( XUI_Event.LAYOUT_COMPLETE, this, X_UI_ScrollBox_onLayoutComplete ); + console.log( 'scroll - calc' ); + XUI_rootData[ 'listenOnce' ]( XUI_Event.LAYOUT_COMPLETE, this, X_UI_ScrollBox_onLayoutComplete ); }; }, @@ -149,8 +204,22 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( _remove : function(){ XUI_AbstractUINode.prototype._remove.apply( this, arguments ); + if( this.scrolling ){ - // remove scroll + // scroller 削除 + this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, X_UI_ScrollBox_onStart ) + [ 'unlisten' ]( XUI_Event.DRAG, X_UI_ScrollBox_onMove ) + [ 'unlisten' ]( XUI_Event.DRAG_END, X_UI_ScrollBox_onEnd ); + XUI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); + + XUI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_COMPLETE, this, X_UI_ScrollBox_onLayoutComplete ); + this[ 'unlisten' ]( XUI_Event.SCROLL_END, XUI_rootData, XUI_rootData.calculate ); + + XUI_ScrollBox_useCSSP ? this.xnodeSlider[ 'stop' ]() : this.xnode[ 'stop' ](); + + XUI_ScrollBox_current === this && XUI_ScrollBox_start( null ); + + this.scrolling = false; }; } @@ -158,26 +227,26 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( ); function X_UI_ScrollBox_onLayoutBefore( e ){ - if( e[ 'cancelable' ] && this.isInTransition && X_Node_Anime_translateZ ){ - this[ 'listenOnce' ]( XUI_Event.SCROLL_END, X_UI_rootData, X_UI_rootData.calculate ); - return X_Callback_PREVENT_DEFAULT; + if( e[ 'cancelable' ] && this.isInTransition && X_NodeAnime_translateZ ){ + this[ 'listenOnce' ]( XUI_Event.SCROLL_END, XUI_rootData, XUI_rootData.calculate ); + return X_CALLBACK_PREVENT_DEFAULT; }; - this.scrollXRatio = this.scrollX ? this.scrollXMax / this.scrollX : 0; - this.scrollYRatio = this.scrollY ? this.scrollYMax / this.scrollY : 0; - this.xnodeSlider.stop(); + this.scrollXRatio = this.scrollX / this.scrollXMax; + this.scrollYRatio = this.scrollY / this.scrollYMax; + XUI_ScrollBox_useCSSP ? this.xnodeSlider[ 'stop' ]() : this.xnode[ 'stop' ](); this.isInTransition = false; - return X_Callback_NONE; + return X_CALLBACK_NONE; }; function X_UI_ScrollBox_onLayoutComplete( e ){ // scroll の停止、GPU の解除 - var font = this.fontSize = this.xnodeSlider.call( 'fontSize' ); - - this.scrollXMax = ( this.boxWidth - this._containerNode.boxWidth ) * font; - this.scrollYMax = ( this.boxHeight - this._containerNode.boxHeight ) * font; + var font = this.fontSize = this.xnodeSlider[ 'call' ]( 'fontSize' ); + + this.scrollXMax = ( this.boxWidth - this._containerNode.boxWidth ) * font | 0; + this.scrollYMax = ( this.boxHeight - this._containerNode.boxHeight ) * font | 0; - this.hasHScroll = this.scrollXEnabled && this.scrollXMax < 0; - this.hasVScroll = this.scrollYEnabled && this.scrollYMax < 0; + this.hasHScroll = this.scrollXEnabled && ( this.scrollXMax < -1 ); // < 0 だと + this.hasVScroll = this.scrollYEnabled && ( this.scrollYMax < -1 ); if( !this.hasHScroll ){ this.scrollXMax = 0; @@ -199,8 +268,10 @@ function X_UI_ScrollBox_onLayoutComplete( e ){ X_UI_ScrollBox_translate( this, this.scrollXMax * this.scrollXRatio, this.scrollYMax * this.scrollYRatio, 100, '', 300 ); } else { // scroller 作る - this[ 'listen' ]( XUI_Event._POINTER_DOWN, this, X_UI_ScrollBox_onStart ); - X_UI_rootData[ 'listen' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); + this[ 'listen' ]( XUI_Event._POINTER_DOWN, X_UI_ScrollBox_onStart ) + [ 'listen' ]( XUI_Event.DRAG, X_UI_ScrollBox_onMove ) + [ 'listen' ]( XUI_Event.DRAG_END, X_UI_ScrollBox_onEnd ); + XUI_rootData[ 'listen' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); X_UI_ScrollBox_translate( this, this.scrollXMax * this.scrollXRatio, this.scrollYMax * this.scrollYRatio, 100, '', 300 ); this.scrolling = true; @@ -209,8 +280,10 @@ function X_UI_ScrollBox_onLayoutComplete( e ){ // scroll 不要 if( this.scrolling ){ // scroller 削除 - this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, this, X_UI_ScrollBox_onStart ); - X_UI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); + this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, X_UI_ScrollBox_onStart ) + [ 'unlisten' ]( XUI_Event.DRAG, X_UI_ScrollBox_onMove ) + [ 'unlisten' ]( XUI_Event.DRAG_END, X_UI_ScrollBox_onEnd ); + XUI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); ( this.scrollX !== 0 || this.scrollY !== 0 ) && X_UI_ScrollBox_translate( this, 0, 0, 100, '', 300 ); @@ -220,43 +293,101 @@ function X_UI_ScrollBox_onLayoutComplete( e ){ }; }; - // TODO use scrollLeft, scrollTop - function X_UI_ScrollBox_translate( that, x, y, opt_time, opt_easing, opt_release ){ - - opt_time = 0 <= opt_time ? opt_time : 0; - opt_easing = opt_easing === '' ? '' : opt_easing || 'circular'; - opt_release = 0 <= opt_release ? opt_release : 300; - - that.xnodeSlider.animate( - { - x : that.scrollX, - y : that.scrollY - }, - { - x : x, - y : y - }, - opt_time, opt_easing, opt_release - ); - - that.scrollX = x; - that.scrollY = y; - - if( that.indicators ){ - for( i = that.indicators.length; i--; ){ - that.indicators[ i ].updatePosition(); - }; - }; - }; +// TODO use scrollLeft, scrollTop +function X_UI_ScrollBox_translate( that, x, y, opt_time, opt_easing, opt_release ){ + var scrollBoxH = that.fontSize * that.boxHeight, + scrollBoxW = that.fontSize * that.boxWidth, + indicatorH, indicatorW; + + opt_time = 0 <= opt_time ? opt_time : 0; + opt_easing = opt_easing === '' ? '' : opt_easing || 'circular'; + opt_release = 0 <= opt_release ? opt_release : 300; + + console.log( 'scr ' + y ); + + if( !XUI_ScrollBox_useCSSP ){ + that.xnode[ 'animate' ]({ + 'from' : { + scrollX : -that.scrollX, + scrollY : -that.scrollY + }, + 'to' : { + scrollX : -x, + scrollY : -y + }, + 'duration' : opt_time, + 'easing' : opt_easing + }); + } else { + that.xnodeSlider[ 'animate' ]({ + 'from' : { + x : that.scrollX, + y : that.scrollY + }, + 'to' : { + x : x, + y : y + }, + 'duration' : opt_time, + 'easing' : opt_easing, + 'lazyRelease' : opt_release + }); + }; -function X_UI_ScrollBox_onStart( e ){ - var ret = X_Callback_NONE; + if( X_UA[ 'IE' ] < 6 ){ + XUI_ScrollBox_indicatorV && XUI_ScrollBox_indicatorV[ 'css' ]( 'left', ( scrollBoxW - that.fontSize * 0.6 | 0 ) + 'px' ); + XUI_ScrollBox_indicatorH && XUI_ScrollBox_indicatorH[ 'css' ]( 'top' , ( scrollBoxH - that.fontSize * 0.6 | 0 ) + 'px' ); + }; - // React to left mouse button only - if( e.pointerType === 'mouse' && e.button !== 0 ){ - return ret; + if( that.hasVScroll && XUI_ScrollBox_indicatorV && XUI_ScrollBox_indicatorV.parent === that.xnode ){ + indicatorH = scrollBoxH * scrollBoxH / ( - that.scrollYMax + scrollBoxH ); + scrollBoxH -= indicatorH; + + XUI_ScrollBox_indicatorV + [ 'css' ]({ + height : ( indicatorH | 0 ) + 'px' + }) + [ 'animate' ]({ + 'from' : { + y : scrollBoxH * that.scrollY / that.scrollYMax }, + 'to' : { + y : scrollBoxH * y / that.scrollYMax, + opacity : 0.5 + }, + 'duration' : opt_time, + 'easing' : opt_easing, + 'lazyRelease' : opt_release + }); + }; + if( that.hasHScroll && XUI_ScrollBox_indicatorH && XUI_ScrollBox_indicatorH.parent === that.xnode ){ + indicatorW = scrollBoxW * scrollBoxW / ( - that.scrollXMax + scrollBoxW ); + scrollBoxW -= indicatorW; + XUI_ScrollBox_indicatorH + [ 'css' ]({ + width : ( indicatorW | 0 ) + 'px' + }) + [ 'animate' ]({ + 'from' : { + x : scrollBoxW * that.scrollX / that.scrollXMax }, + 'to' : { + x : scrollBoxW * x / that.scrollXMax, + opacity : 0.5 + }, + 'duration' : opt_time, + 'easing' : opt_easing, + 'lazyRelease' : opt_release + }); }; + that.scrollX = x; + that.scrollXEm = x / that.fontSize; + that.scrollY = y; + that.scrollYEm = y / that.fontSize; +}; + +function X_UI_ScrollBox_onStart( e ){ + var ret = X_CALLBACK_NONE; + if( !this.scrollEnabled || ( this.initiated && e.pointerType !== this.initiated ) ){ return ret; }; @@ -271,11 +402,13 @@ function X_UI_ScrollBox_onStart( e ){ this.startTime = X_Timer_now(); // スクロール中の停止 - if( this.isInTransition || this.isAnimating ){ - this.isInTransition = this.isAnimating = false; + if( this.isInTransition ){ + this.isInTransition = false; + //console.log( '-1-' ); this[ 'dispatch' ]( XUI_Event.SCROLL_END ); - this.xnodeSlider.stop(); - }; + // TODO current位置 + XUI_ScrollBox_useCSSP ? this.xnodeSlider[ 'stop' ]() : this.xnode[ 'stop' ](); + }; this.startX = this.scrollX; this.startY = this.scrollY; @@ -284,33 +417,26 @@ function X_UI_ScrollBox_onStart( e ){ this.pointX = e.pageX; this.pointY = e.pageY; - console.log( 'scrollstart ' + e.pageY ); - - this[ 'listen' ]( XUI_Event._POINTER_MOVE, this, X_UI_ScrollBox_onMove ); - this[ 'listen' ]( [ XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL ], this, X_UI_ScrollBox_onEnd ); + console.log( 'scrollstart ' + e.pageY + e.target.className() ); - return ret | X_Callback_PREVENT_DEFAULT; + return ret | X_CALLBACK_PREVENT_DEFAULT; }; function X_UI_ScrollBox_onMove( e ){ - var ret = X_Callback_NONE, + var ret = X_CALLBACK_NONE, deltaX, deltaY, timestamp, newX, newY, absDistX, absDistY; // 規定以上の move でスクロール開始 -console.log( 'scrollmove ' + e.buttons + ' ' + e.button ); +//console.log( 'scrollmove ' + e.buttons + ' ' + e.button ); if( !this.scrollEnabled || e.pointerType !== this.initiated ){ return ret; }; - - if( e.buttons !== 1 ){ - return X_UI_ScrollBox_onEnd.call( this, e ); - }; // gpu の用意 - if( !this.xnodeSlider[ '_anime' ] ){ + if( !XUI_ScrollBox_useCSSP ? ( !this.xnode[ '_anime' ] || !this.xnode[ '_anime' ].phase ) : ( !this.xnodeSlider[ '_anime' ] || !this.xnodeSlider[ '_anime' ].phase ) ){ //console.log( 'gpuレイヤーの用意 ' + e.pageY ); //console.log( 'mov1 x:' + this.scrollX + ' y:' + this.scrollY ); X_UI_ScrollBox_translate( this, this.scrollX, this.scrollY, 0, '', 300 ); @@ -361,6 +487,8 @@ console.log( 'scrollmove ' + e.buttons + ' ' + e.button ); this.moved = true; this.minusX = deltaX; this.minusY = deltaY; + // indicator + XUI_ScrollBox_start( this ); } else { this[ 'dispatch' ]( XUI_Event.SCROLL_MOVE ); }; @@ -381,7 +509,7 @@ console.log( 'scrollmove ' + e.buttons + ' ' + e.button ); this.directionX = 0 < deltaX ? -1 : deltaX < 0 ? 1 : 0; this.directionY = 0 < deltaY ? -1 : deltaY < 0 ? 1 : 0; - //console.log( 'mov2 x:' + newX + ' y:' + newY ); + console.log( 'mov2 x:' + newX + ' y:' + newY ); X_UI_ScrollBox_translate( this, newX, newY, 0, '', 300 ); if( 300 < timestamp - this.startTime ){ @@ -390,21 +518,21 @@ console.log( 'scrollmove ' + e.buttons + ' ' + e.button ); this.startY = this.scrollY; }; // イベントの拘束 - return ret | X_Callback_PREVENT_DEFAULT | X_Callback_CAPTURE_POINTER; + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_CAPTURE_POINTER; }; function X_UI_ScrollBox_onEnd( e ){ - var ret = X_Callback_NONE, + var ret = X_CALLBACK_NONE, time = 0, easing = '', newX, newY, momentumX, momentumY, duration, distanceX, distanceY; - - this[ 'unlisten' ]( XUI_Event._POINTER_MOVE, this, X_UI_ScrollBox_onMove ); - this[ 'unlisten' ]( [ XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL ], this, X_UI_ScrollBox_onEnd ); + + //console.log( e.type + ' onend ' + XUI_Event.POINTER_OUT ); if( !this.scrollEnabled || e.pointerType !== this.initiated ){ + //console.log( e.type + ' onend 1 ' + e.pointerType + ' ' + this.initiated ); return ret; }; @@ -420,14 +548,15 @@ function X_UI_ScrollBox_onEnd( e ){ // reset if we are outside of the boundaries if( X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){ - return ret; + //console.log( e.type + ' onend 2 ' + XUI_Event.POINTER_OUT ); + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER; }; // we scrolled less than 10 pixels if( !this.moved ){ - // this[ 'dispatch' ]( X_EVENT_CANCELED ); - console.log( 'we scrolled less than 10 pixels ' + e.pageY ); - return ret; + this[ 'dispatch' ]( X_EVENT_CANCELED ); + //console.log( 'we scrolled less than 10 pixels ' + e.pageY ); + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER; }; // start momentum animation if needed @@ -443,7 +572,7 @@ function X_UI_ScrollBox_onEnd( e ){ time = Math.max( momentumX.duration, momentumY.duration ) | 0; this.isInTransition = true; } else { - console.log( '慣性無し' ); + //console.log( '慣性無し' ); }; if( newX != this.scrollX || newY != this.scrollY ){ @@ -452,17 +581,16 @@ function X_UI_ScrollBox_onEnd( e ){ easing = 'quadratic'; }; - console.log( 'end2 x:' + newX + ' y:' + newY + ' t:' + time ); + //console.log( 'end2 x:' + newX + ' y:' + newY + '<-y:' + this.scrollY + ' t:' + time ); this.scrollTo( newX, newY, time, easing, 1000 ); - return ret; + } else { + //console.log( 'end1 x:' + newX + ' y:' + newY ); + this.scrollTo( newX, newY, 0, '', 1000 ); // ensures that the last position is rounded + //console.log( '-3-' ); + this[ 'dispatch' ]( XUI_Event.SCROLL_END ); }; - console.log( 'end1 x:' + newX + ' y:' + newY ); - this.scrollTo( newX, newY, 0, '', 1000 ); // ensures that the last position is rounded - - this[ 'dispatch' ]( XUI_Event.SCROLL_END ); - - return ret; + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER; }; function X_UI_ScrollBox_resetPosition( that, time ){ @@ -486,34 +614,68 @@ function X_UI_ScrollBox_resetPosition( that, time ){ }; if( x === that.scrollX && y === that.scrollY ){ - console.log( 'no バウンド y:' + y + ' max:' + that.scrollYMax ); + //console.log( 'no バウンド y:' + y + ' max:' + that.scrollYMax ); return false; }; - //console.log( 'バウンド!' ); - //console.log( 'rese x:' + x + ' y:' + y ); + //console.log( ' ===> resetPosition - バウンド!' ); + //console.log( ' x:' + x + ' y:' + y ); that.scrollTo( x, y, time, that.bounceEasing, 1000 ); return true; }; function X_UI_ScrollBox_onAnimeEnd( e ){ - if( e.target !== this.xnodeSlider || !this.isInTransition ){ - return X_Callback_NONE; - }; - if( !X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){ + if( this.isInTransition && !X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){ this.isInTransition = false; + //console.log( '-2-' ); this[ 'dispatch' ]( XUI_Event.SCROLL_END ); }; - return X_Callback_NONE; + //console.log(' -2.1- '+this.isInTransition ); + return X_CALLBACK_NONE; +}; + +function X_UI_ScrollBox_momentum( current, start, time, lowerMargin, wrapperSize, deceleration ){ + var distance = current - start, + speed = Math.abs( distance ) / time, + destination, + duration; + + deceleration = deceleration === undefined ? 0.0006 : deceleration; + + destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); + duration = speed / deceleration; + + if( destination < lowerMargin ){ + destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; + distance = Math.abs( destination - current ); + duration = distance / speed; + } else + if ( destination > 0 ) { + destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; + distance = Math.abs( current ) + destination; + duration = distance / speed; + }; + + return { + destination : Math.round( destination ), + duration : duration + }; }; -// TODO Box の継承に! X.UI.ScrollBox = X.UI.ChromeBox.inherits( 'ScrollBox', X_Class.NONE, { Constructor : function(){ + var supports, slider; + + if( XUI_ScrollBox.prototype.usableAttrs === XUI_ChromeBox.prototype.usableAttrs ){ + XUI_ScrollBox.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_ScrollBox_SUPPORT_ATTRS ); + + XUI_ScrollBox.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { width : '100%', height : '100%', bgColor : 0x111111 } ); + }; + var args = [ XUI_Layout_Vertical, { @@ -525,19 +687,20 @@ X.UI.ScrollBox = X.UI.ChromeBox.inherits( minHeight : '100%' } ], - i = arguments.length, - arg, layout, attr; + l = arguments.length, i = 0, j = 1, + arg, attr; - for( ; i; ){ - arg = arguments[ --i ]; + for( ; i < l; ++i ){ + arg = arguments[ i ]; if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( XUI_LayoutBase ) ){ - layout = arg; + args[ 0 ] = arg; } else if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( X.UI.AbstractUINode ) ){ - args[ args.length ] = arg; + args[ ++j ] = arg; } else if( X_Type_isObject( arg ) ){ - attr = arg; + args[ ++j ] = attr = arg; + slider = attr.scrollSlider; }; }; @@ -545,18 +708,14 @@ X.UI.ScrollBox = X.UI.ChromeBox.inherits( this, XUI_ScrollBox( this, - XUI_Layout_Canvas, + null, [ - { - width : '100%', - height : '100%' - }, - X.UI.VBox.apply( 0, args ) + slider || X.UI.VBox.apply( 0, args ) ] ) ); - attr && this.attr( attr ); + //attr && this.attr( attr ); }, scrollX : function(){ @@ -574,4 +733,5 @@ X.UI.ScrollBox = X.UI.ChromeBox.inherits( } } -); \ No newline at end of file +); +