;(function(define, _win) { 'use strict'; define( 'v.roundspan', [ 'v', 'underscore', 'v.geometry', 'v.log', 'v.basehandler' , 'zepto.extras' ], function( V, _, Geometry, Log, BaseHandler ){ V = V || window.V || {}; Geometry = Geometry || V.Geometry; BaseHandler = BaseHandler || V.BaseHandler; Log = Log || V.Log; _ = _ || window._; /** * 圆环进度控制(多条件) * @module v.roundspan * @implements {@link v.module:basehandler} * @inheritdoc * @requires {@link v} * @requires {@link underscore} * @requires {@link v.module:geometry} * @requires {@link v.module:log} * @requires {@link Zepto#zepto.extras} * @export V.Const.RoundSpan * @see {@link http://demo.v.js.openjavascript.org/modules/v.roundspan/0.1/_demo/default_order.html demo} * @example <link href='../res/default/style.css' rel='stylesheet' /> <div style="margin-top: 20px; margin-left: 150px; "> <div class="comp-rs" data-comp="RoundSpan" data-offset_angle="210" data-max_angle="240" data-value="11,29" data-min_value="6" data-max_value="34" data-order="1" > <div class="comp-rs-control" data-control="point" ><label data-type="text"></label></div> <div class="comp-rs-control" data-control="point" ><label data-type="text"></label></div> </div> </div> <script> requirejs( [ 'v.roundspan' ], function( RoundSpan ){ RoundSpan.trigger( RoundSpan.init ); }); </script> */ var _PREFIX = 'compRoundSpan_' , _CONST = $.extend( true, { init: _PREFIX + 'init' , initItem: _PREFIX + 'initItem' , getParams: _PREFIX + 'getParams' , updateParams: _PREFIX + 'updateParams' , precision: 0 , checkorder: _PREFIX + 'checkorder' , calcCenterPoint: _PREFIX + 'calcCenterPoint' , dataKey: _PREFIX + 'data' , updateWrapperCor: _PREFIX + 'updateWrapperCor' /** * roundspan更新操作的事件名集合 * @namespace v.module:roundspan#update * @see {@link v.module:roundspan} */ , update: { angle: _PREFIX + 'updateAngle' , visibleAngle: _PREFIX + 'updateVisibleAngle' , noticeStart: _PREFIX + 'updateNoticeStart' , notice: _PREFIX + 'updateNotice' , noticeEnd: _PREFIX + 'updateNoticeEnd' , values: _PREFIX + 'update_values' , value: _PREFIX + 'update_value' , text: _PREFIX + 'updateNoticeText' } , calcVisibleParams: _PREFIX + 'calcVisibleParams' , pointDelegate: [ 'div[data-comp=RoundSpan] [data-control=point]' , 'li[data-comp=RoundSpan] [data-control=point]' ].join(',') , wrapperSelector: '[data-comp=RoundSpan]' /** * 圆点拖动时检测是否可以拖动 * @event v.module:roundspan#beforeDragCheckEvent * @return {boolean} * @example <div class="temp-circle isRoomItem" data-comp="RoundSpan" data-offset_angle="210" data-max_angle="240" data-value="17,24" data-min_value="5" data-max_value="35" data-room_num="3" data-order="1" data-before_drag_check_event="customEvent"> <span class="temp-high" data-control="point" data-type="lower" data-point_value="17" style="z-index: 101; left: 10.9731px; top: -13.8172px;"> <label data-type="text">17</label> </span> <span class="temp-low" data-control="point" data-type="upper" data-point_value="24" style="z-index: 102; left: 50.8223px; top: -10.3988px;"> <label data-type="text">24</label> </span> <div class="temp-hidden"></div> </div> <script> V.WIN.on( 'customEvent', function( _evt, _src, _params ){ return window.isCanDrag; }); </script> */ , beforeDragCheckEvent: 'before_drag_check_event' }, BaseHandler ) , _PARAMS , _LAST_ANGLE = 0 ; V.Const.RoundSpan = _CONST; /** * 初始化圆环 * @event v.module:roundspan#init * @param {selector} _wrapper 要初始化的复选框 * @param {boolean} _isItem 声明 _wrapper 是否为单个组件, 否则初始化 _wrapper 下的所有 RoundSpan, default: false * @example * RoundSpan.trigger( RoundSpan.init, [ 'body' ] ) * //RoundSpan.trigger( RoundSpan.init, [ $( 'div[data-comp=RoundSpan]', true ) ] ) */ _CONST.on( _CONST.init, function( _evt, _wrapper, _isItem ){ if( _isItem ){ $.each( _wrapper, function( _k, _v ){ _CONST.trigger( _CONST.initItem, [ $( _v ) ] ); }); }else{ _wrapper = $( _wrapper || V.BODY ); _wrapper.length && _wrapper.find( 'div[data-comp=RoundSpan]' ).each( function( _k, _v ){ _CONST.trigger( _CONST.initItem, [ _v ] ); }); } }); /** * 初始化单个圆环 * @event v.module:roundspan#initItem * @param {selector} _item 要初始化的圆环 * @example * RoundSpan.trigger( RoundSpan.initItem, [ 'div[data-comp=RoundSpan]:first' ] ) */ _CONST.on( _CONST.initItem, function( _evt, _item ){ _item = $( _item ); if( !_item.length ) return; var _val = (_item.data( 'value' ) || '0' ).toString().replace( /[^\d,]/g, '' ).split( ',' ) , _points = _item.find( '[data-control=point]' ) ; $.each( _points, function( _k, _v ){ _v = $( _v ); var _prev = _points[ _k - 1] , _next = _points[ _k + 1] ; _v[0].prev = _prev; _v[0].next = _next; }); //Log.dir( _params, _val ); // _points.each( function( _k, _v ){ var _point = $( _v ) , _params = _CONST.triggerHandler( _CONST.getParams, [ _point ] ) , _sv = _val[ _k ] || _params.min_value ; _CONST.trigger( _CONST.updateWrapperCor, [ _params ] ); var _angle = ( _sv - _params.min_value ) / _params.value * _params.max_angle - _params.offsetAngle; _CONST.trigger( _CONST.update.angle, [ _angle, _params, true ] ); }); }); /** * 检查圆环是否需要进行大小比较 * @event v.module:roundspan#checkorder * @param {object} _params RoundSpan 的数据模型 * @param {object} _visibleParams RoundSpan 的可视化数据模型 * @return {boolean} * @private */ _CONST.on( _CONST.checkorder, function( _evt, _params, _visibleParams ){ var _r = true; if( !_params.order ) return _r; var _point = _params.point , _prev = _point[0].prev , _next = _point[0].next ; //Log.dir( _params ); if( _prev ){ if( _visibleParams.value <= $( _prev ).data( 'point_value' ) ) _r = false; } if( _next ){ if( _visibleParams.value >= $( _next ).data( 'point_value' ) ) _r = false; } return _r; }); _CONST.on( _CONST.calcVisibleParams, function( _evt, _angle, _params ){ var _r = { angle: _angle , visibleAngle: 0 , value: 0 }; _r.visibleAngle = Geometry.fixAngle( _r.angle + _params.offsetAngle ); if( _params.max_angle && _r.visibleAngle > _params.max_angle ){ if( _r.visibleAngle > 20 && _r.visibleAngle <= ( _params.max_angle + ( 360 - _params.max_angle ) / 2 )){ _r.angle -= ( _r.visibleAngle - _params.max_angle ); _r.visibleAngle = _params.max_angle; }else{ _r.angle = -_params.offsetAngle; _r.visibleAngle = 0; } } //Log.log( _params.max_angle, _r.visibleAngle, _params.value, _.now() ); _r.value = V.utils.parseFinance( _r.visibleAngle / _params.max_angle * _params.value + _params.min_value, _CONST.precision ); return _r; }); _CONST.on( _CONST.updateWrapperCor, function( _evt, _params ){ var _wp = _params.wrapper , _pt = _params.point , _position = _wp.position() , _offset = _wp.offset() , _ptposition = _pt.position() , _ptoffset = _pt.offset() ; _params.cor = { left: _position.left , top: _position.top , offsetLeft: _offset.left , offsetTop: _offset.top , width: _wp.width() , height: _wp.height() , offsetWidth: _wp[0].offsetWidth , offsetHeight: _wp[0].offsetHeight }; _CONST.triggerHandler( _CONST.calcCenterPoint, _params.cor ); _params.pcor = { left: _ptposition.left , top: _ptposition.top , offsetLeft: _ptoffset.left , offsetTop: _ptoffset.top , width: _pt.outerWidth( true ) , height: _pt.outerHeight( true ) , offsetWidth: _pt.outerWidth( true ) || _pt[0].offsetWidth , offsetHeight: _pt.outerHeight( true ) || _pt[0].offsetHeight }; _CONST.triggerHandler( _CONST.calcCenterPoint, _params.pcor ); _CONST.trigger( _CONST.updateParams, [ _params ] ); }); _CONST.on( _CONST.calcCenterPoint, function( _evt, _cor ){ var _r = { cx: _cor.offsetLeft + _cor.offsetWidth / 2 , cy: _cor.offsetTop + _cor.offsetHeight / 2 , radius: Math.max( _cor.offsetWidth, _cor.offsetHeight ) / 2 }; $.extend( _cor, _r ); return _r; }); _CONST.on( _CONST.updateParams, function( _evt, _params ){ _params.wrapper[0][ _CONST.dataKey ] = _params; return _params; }); _CONST.on( _CONST.getParams, function( _evt, _p ){ _p = $( _p ); var _r = _p[0][ _CONST.dataKey ]; if( !_r ){ _r = { wrapper: _p.closest( _CONST.wrapperSelector ) , point: _p , points: null , text: _p.find( '[data-type=text]' ) , offsetAngle: 90 , drag_check_event: '' , max_angle: 360 , min_value: 0 , max_value: 0 , value: 0 } _r.points = _r.wrapper.find( '[data-control=point]' ); _r.offsetAngle = _r.wrapper.data( 'offset_angle' ) || _r.offsetAngle _r.max_angle = _r.wrapper.data( 'max_angle' ) || _r.max_angle _r.drag_check_event = _r.wrapper.data( 'drag_check_event' ) || _r.drag_check_event _p[0][ _CONST.dataKey ] = _r; //Log.log( _r.wrapper.data( 'max_value' ), _.now() ); _r.min_value = _r.wrapper.data( 'min_value' ) || _r.min_value; _r.max_value = _r.wrapper.data( 'max_value' ) || _r.max_angle; _r.value = _r.max_value - _r.min_value; _r.order = V.utils.parseBool( _r.wrapper.data( 'order' ) ); } return _r; }); /** * 更新圆环单个点的文本 * @event text * @param {number} _visibleAngle 可视化角度 * @param {object} _params RoundSpan 的数据模型 * @param {number} _angle 程序角度 * @param {number} _value 用于显示的文本数值 * @memberof v.module:roundspan#update * @see {@link v.module:roundspan} */ _CONST.on( _CONST.update.text, function( _evt, _visibleAngle, _params, _angle, _value ){ if ( !( _params.text && _params.text.length ) ) return; _params.text.html( Math.ceil( _value ) ); }); /** * 更新圆环的所有点 * @event values * @param {object} _params RoundSpan 的数据模型 * @memberof v.module:roundspan#update * @see {@link v.module:roundspan} */ _CONST.on( _CONST.update.values, function( _evt, _params ){ var _vals = []; _params.points.each( function( _k, _v ){ _v = $( _v ); var _label = _v.find( '[data-type=text]' ), _tmp; _label.length && ( _tmp = _label.html().replace( /[^\d.]/g, '' ) ).length && _vals.push( V.utils.parseFinance( _tmp ) ); }); _vals.length && ( _vals = _.sortBy( _vals ) ) && ( _params.wrapper.data( 'value', _vals.join( ',' ) ) , _params.wrapper[0].RoundSpanData = _vals , _CONST.trigger( _CONST.update.value, [ _vals, _params ] ) ); }); /** * 更新圆环的角度 * @event angle * @param {number} _angle 角度 * @param {object} _params RoundSpan 的数据模型 * @param {boolean} _ignoreNotice 是否忽略更新后的通知事件, default: false * @memberof v.module:roundspan#update * @see {@link v.module:roundspan} */ _CONST.on( _CONST.update.angle, function( _evt, _angle, _params, _ignoreNotice ){ _params = _params || _PARAMS; if( !_params ) return; var _visibleParams = _CONST.triggerHandler( _CONST.calcVisibleParams, [ _angle, _params ] ); if( !_ignoreNotice ){ if( !_CONST.triggerHandler( _CONST.checkorder, [ _params, _visibleParams ] ) ){ return; } } _params.point.data( 'point_value', _visibleParams.value ); var _pt = { left: _params.cor.radius - _params.pcor.radius - 2 , top: _params.cor.radius - _params.pcor.radius - 2 } , _realPt = Geometry.distanceAngleToPoint( _params.cor.radius, _visibleParams.angle ) ; _params.point.css( { left: _realPt.x + _pt.left, top: _realPt.y + _pt.top } ); _CONST.trigger( _CONST.update.text, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); _CONST.trigger( _CONST.update.values, [ _params ] ); !_ignoreNotice && _CONST.trigger( _CONST.update.notice, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); }); V.DOC.delegate( _CONST.pointDelegate, 'touchend', function( _evt ){ var _params = _CONST.triggerHandler( _CONST.getParams, [ this ] ) ; V.DOC.off( 'touchmove', onTouchMove ); V.Log.log( 'touchend', _params.wrapper.length, _.now(), _LAST_ANGLE ); var _visibleParams = _CONST.triggerHandler( _CONST.calcVisibleParams, [ _LAST_ANGLE, _params ] ) _CONST.trigger( _CONST.update.values, [ _params ] ); _CONST.trigger( _CONST.update.noticeEnd, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); _PARAMS = null; }); V.DOC.delegate( _CONST.pointDelegate, 'touchstart', function( _evt ){ _evt.preventDefault(); _evt.stopPropagation(); var _p = $( this ) , _checkEvent ; var _params = _CONST.triggerHandler( _CONST.getParams, [ this ] ) ; _checkEvent = V.utils.detectCommand( _params.wrapper.data( _CONST.beforeDragCheckEvent ) ); if( _checkEvent && ( ( !V.WIN.triggerHandler( _checkEvent, [ _p, _params ] ) ) //|| ( !_CONST.triggerHandler( _checkEvent, [ _p, _params ] ) ) ) ) return; _p.css( 'z-index', ++V.ZINDEX ); _CONST.trigger( _CONST.updateWrapperCor, [ _params ] ); _PARAMS = _params; var _angle = Geometry.lineAngle( { x: _PARAMS.cor.cx, y: _PARAMS.cor.cy } , { x: _evt.touches[0].pageX, y: _evt.touches[0].pageY } ); var _visibleParams = _CONST.triggerHandler( _CONST.calcVisibleParams, [ _angle, _params ] ) _CONST.trigger( _CONST.update.noticeStart, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); //V.Log.dir( _params ); V.Log.log( 'touchstart', _params.wrapper.length, _.now() ); V.DOC.off( 'touchmove', onTouchMove ).on( 'touchmove', onTouchMove ); }); function onTouchMove( _evt ){ if( !_PARAMS ) return; //V.Log.dir( _evt, 'onTouchMove' ); //V.Log.log( _.now(), _evt.touches[0].pageX, _evt.touches[0].pageY ); var _angle = Geometry.lineAngle( { x: _PARAMS.cor.cx, y: _PARAMS.cor.cy } , { x: _evt.touches[0].pageX, y: _evt.touches[0].pageY } ); _LAST_ANGLE = _angle; _CONST.trigger( _CONST.update.angle, [ _angle ] ); } _CONST.on( _CONST.update.noticeEnd, function( _evt, _visibleAngle, _params, _angel, _value, _visibleParams ){ V.WIN.trigger( _CONST.update.noticeEnd, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); }); _CONST.on( _CONST.update.notice, function( _evt, _visibleAngle, _params, _angel, _value, _visibleParams ){ V.WIN.trigger( _CONST.update.notice, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); }); _CONST.on( _CONST.update.notice, function( _evt, _visibleAngle, _params, _angel, _value, _visibleParams ){ V.WIN.trigger( _CONST.update.noticeStart, [ _visibleParams.visibleAngle, _params, _visibleParams.angle, _visibleParams.value, _visibleParams ] ); }); //bind on V.WIN no longer support V.WIN.on( _CONST.update.values, function( _evt, _params ){ _CONST.trigger( _CONST.update.values, [ _params ] ); }); V.WIN.on( _CONST.update.angle, function( _evt, _angle, _params, _ignoreNotice ){ _CONST.trigger( _CONST.update.angle, [ _angle, _params, _ignoreNotice ] ); }); V.WIN.on( _CONST.checkorder, function( _evt, _params, _visibleParams ){ return _CONST.triggerHandler( _CONST.checkorder, [ _params, _visibleParams ] ); }); V.WIN.on( _CONST.init, function( _evt, _wrapper, _isItem ){ _CONST.trigger( _CONST.init, [ _wrapper, _isItem ] ); }); V.WIN.on( _CONST.initItem, function( _evt, _item ){ _CONST.trigger( _CONST.initItem, [ _item ] ); }); V.WIN.on( _CONST.update.text, function( _evt, _visibleAngle, _params, _angle, _value ){ _CONST.trigger( _CONST.update.text, [ _visibleAngle, _params, _angle, _value ] ); }); V.WIN.on( _CONST.calcVisibleParams, function( _evt, _angle, _params ){ return _CONST.triggerHandler( _CONST.calcVisibleParams, [ _angle, _params ] ) }); V.WIN.on( _CONST.updateWrapperCor, function( _evt, _params ){ _CONST.trigger( _CONST.updateWrapperCor, [ _evt, _params ] ); }); V.WIN.on( _CONST.calcCenterPoint, function( _evt, _cor ){ return _CONST.triggerHandler( _CONST.calcCenterPoint, [ _cor ] ); }); V.WIN.on( _CONST.updateParams, function( _evt, _params ){ _CONST.trigger( _CONST.updateParams, [ _params ] ); }); V.WIN.on( _CONST.getParams, function( _evt, _p ){ return _CONST.triggerHandler( _CONST.getParams, [ _p ] ); }); return _CONST; });}( typeof define === 'function' && define.amd ? define : function ( _name, _require, _cb ) { typeof _name == 'function' && ( _cb = _name ); typeof _require == 'function' && ( _cb = _require ); _cb && ( _cb() ); } , window ) );