以前寫小遊戲的時候,為了指導使用者
會用一小箭頭指引使用者點哪裡
這兩天把這個功能寫成套件了
demo
http://ry.url.tw/wp/doc/ryPoint/rP1.htm
<meta charset="utf-8">
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<style>
</style>
<script>
;(function($, W, D)
{
String.prototype.format = function()
{
var args = arguments ;
return this.replace(/{(\d+)}/g, function(match, number)
{
return typeof (args[number] != 'undefined') ? args[number] : match ;
}) ;
} ;
var log = function()
{
if (logOn)
{
console.log(arguments) ;
}
}
var pg = 'ryPoint' ; //plugin name
var pgType = 'troops' ; //plugin type
var logOn = false ; //log switch
var innerSettings = //settings will never affected by outside.
{
indexPrefix: 'ry-'+pg+'-'
, indexSuffix: '-index-'
// 'data-'+pg+'-index-' + WIDGET ROLE + '-id-' + number
, pgAttr: 'ry-'+pg+'-number'
, arrowLength: 187
, arrowSrcGreen: '../css/images/ryPoint-arrow-green.png'
, arrowSrcRed: '../css/images/ryPoint-arrow-red.png'
, actorsClass :
{
'widget' : 'ry-'+pg+'-widget'
}
, classList:
{
'widget' : 'ry-'+pg+'-widget'
}
, tpl:
{
}
}
var defaults = //settings can be rewrited by outside.
{
color: 'green'
, size: innerSettings.arrowLength
, padding: '5px'
, effect: 'swing'
, removeMode: 'afterEffect'
, direction: null
, border: false
, effect: null
} ;
$[pg] = function()
{
$[pg].args = Array.prototype.slice.call(arguments) ;
$[pg].pgRouter() ;
} ;
$[pg].version = '0.1' ;
$[pg].id = 1 ;
$[pg].settings = {} ;
$[pg].pgRouter = function()
{
if ($[pg].args.length === 2)
{
if ($.isFunction( $[pg][ $[pg].args[0] ] ))
{
$[pg][ $[pg].args[0] ]( $[pg].args[1] ) ;
}
else
{
_.log('wrong method: ' + $[pg].args[0]) ;
}
}
else if ($[pg].args.length === 1 && typeof $[pg].args[0] === 'object')
{
$[pg].mkSettings($[pg].args[0]) ;
$[pg].init() ;
}
else if ($[pg].args.length === 1 && ( $.isFunction( $[pg][ $[pg].args[0] ] ) ))
{
$[pg][ $[pg].args[0] ]() ;
}
else
{
$[pg].init() ;
}
} ;
$[pg].init = function()
{
log('$[pg].init') ;
$(document)[pg]() ;
} ;
$[pg].mkSettings = function(arg)
{
log('$[pg].mkSettings') ;
// 運算值 預設值 設定值 內定值
$[pg].settings = $.extend({}, defaults, arg, innerSettings) ;
log('$[pg].settings:') ;
log($[pg].settings) ;
} ;
/*
make a modal to produce widgets
*/
function Plugin(element)
{
log('function Plugin') ;
this.element = element ;
this.ele$ = $(element) ;
this.args = Plugin.args ;
this.settings = this.mkSettings() ;
this.id = $[pg].id++ ;
log('this.settings:') ;
log(this.settings) ;
this.actors = {} ;
this.init() ;
}
/*
super power those widgets have
*/
Plugin.prototype =
{
mkSettings: function()
{
log('mkSettings') ;
var self = this ;
var tmpSet = $.extend({}, defaults, $[pg].settings, self.args[0], innerSettings) ;
if (typeof tmpSet.size === 'string')
{
tmpSet.size = Number( tmpSet.size.replace('px', '') ) ;
}
if (typeof tmpSet.padding === 'string')
{
tmpSet.padding = Number( tmpSet.padding.replace('px', '') ) ;
}
return tmpSet
}
, init: function()
{
log('init') ;
var self = this ;
self.target() ;
self.arrowDirection() ;
self.arrowSize() ;
self.arrowXY() ;
self.point() ;
self.effect(self.settings.removeMode) ;
}
, target: function()
{
log('target') ;
var self = this ;
if (self.settings.xy)
{
var tmpAry = self.settings.xy.split(',') ;
self.targetHalfW = 0 ;
self.targetHalfH = 0 ;
self.targetCenterX = Number( tmpAry[0] ) ;
self.targetCenterY = Number( tmpAry[1] ) ;
console.log(111) ;
}
else
{
var _offset = self.ele$.offset() ;
self.targetHalfW = self.ele$.outerWidth() / 2 ;
self.targetHalfH = self.ele$.outerHeight() / 2 ;
self.targetCenterX = _offset.left + self.targetHalfW ;
self.targetCenterY = _offset.top + self.targetHalfH ;
}
if (self.settings.border)
{
//is not so easy, u must put one new div on it.
var _offset = self.ele$.offset() ;
self.actors.border = $('<div />')
.css(
{
border: '2px dashed green'
, position: 'absolute'
, top:_offset.top-2 //border width
, left:_offset.left-2
, width:self.ele$.innerWidth()
, height:self.ele$.innerHeight()
})
.appendTo('body') ;
}
}
, arrowDirection: function()
{
log('arrowDirection') ;
var self = this ;
var _W = $(window).width() ;
var _H = $(window).height() ;
var _topLimit = (_W * 0.1) >> 0 ;
var _bottomLimit = (_H * 0.9) >> 0 ;
if (self.settings.direction)
{
var tmpD = self.settings.direction.toLowerCase() ;
switch(tmpD)
{
case 'right':
self.direction = 'pointRight' ;
self.rotateDegree = 90 ;
self.posture = 'horizontal' ;
break ;
case 'top':
self.direction = 'pointTop' ;
self.rotateDegree = 0 ;
self.posture = 'vertical' ;
break ;
case 'bottom':
self.direction = 'pointBottom' ;
self.rotateDegree = 180 ;
self.posture = 'vertical' ;
break ;
case 'left':
self.direction = 'pointLeft' ;
self.rotateDegree = -90 ;
self.posture = 'horizontal' ;
break ;
}
}
else
{
if (self.targetCenterX >= Math.max(self.settings.arrowLength))
{
self.direction = 'pointRight' ;
self.rotateDegree = 90 ;
self.posture = 'horizontal' ;
}
else if (self.targetCenterY <= _topLimit)
{
self.direction = 'pointTop' ;
self.rotateDegree = 0 ;
self.posture = 'vertical' ;
}
else if (self.targetCenterY >= _bottomLimit)
{
self.direction = 'pointBottom' ;
self.rotateDegree = 180 ;
self.posture = 'vertical' ;
}
else
{
self.direction = 'pointLeft' ;
self.rotateDegree = -90 ;
self.posture = 'horizontal' ;
}
}
self.actors.pointClass = pg + '-' + self.direction ;
}
, arrowSize: function()
{
log('arrowSize') ;
var self = this ;
self.settings.arrowLength = (self.settings.size)? self.settings.size : self.settings.arrowLength ;
}
, arrowXY: function()
{
log('arrowXY') ;
var self = this ;
if (self.direction === 'pointRight')
{
self.arrowX = self.targetCenterX - self.targetHalfW - self.settings.padding - self.settings.arrowLength ;
self.arrowY = self.targetCenterY - (self.settings.arrowLength / 2) ;
}
else if (self.direction === 'pointLeft')
{
self.arrowX = self.targetCenterX + self.targetHalfW + self.settings.padding ;
self.arrowY = self.targetCenterY - (self.settings.arrowLength / 2) ;
}
else if (self.direction === 'pointTop')
{
self.arrowX = self.targetCenterX - (self.settings.arrowLength / 2) ; ;
self.arrowY = self.targetCenterY + self.targetHalfH + self.settings.padding ;
}
else if (self.direction === 'pointBottom')
{
self.arrowX = self.targetCenterX - (self.settings.arrowLength / 2) ;
self.arrowY = self.targetCenterY - self.targetHalfH - self.settings.padding - self.settings.arrowLength ;
}
}
, point: function()
{
log('point') ;
var self = this ;
self.actors.arrowIndex = self.settings.indexPrefix + 'arrow' + self.settings.indexSuffix + self.id ;
self.arrowSrc = ( self.settings.color === 'green' )? self.settings.arrowSrcGreen : self.settings.arrowSrcRed ;
//arrow size
self.actors.arrow = $('<img />')
.attr('src', self.arrowSrc)
.css(
{
position: 'absolute'
, top: self.arrowY
, left: self.arrowX
, width: self.settings.size + 'px'
, '-webkit-transform': 'rotate('+ self.rotateDegree +'deg)'
})
.addClass(self.actors.arrowIndex + ' ' + self.actors.pointClass)
.attr(self.settings.pgAttr, self.id)
.appendTo('body') ;
}
, effect: function(_m)
{
log('effect') ;
var self = this ;
if (self.settings.effect && $.isFunction(self[self.settings.effect]))
{
self[self.settings.effect](_m) ;
}
}
, swing: function(_m)
{
log('swing') ;
var self = this ;
var animateOjb = {} ;
var _time = 5 ;
var _speed = 150 ;
var _diff = 12 ;
if (self.posture === 'vertical')
{
var obj1 =
{
top: '+='+_diff
} ;
var obj2 =
{
top: '-='+_diff
} ;
}
else
{
var obj1 =
{
left: '+='+_diff
} ;
var obj2 =
{
left: '-='+_diff
} ;
}
for(var i=1; i<= _time; i++ )
{
self.actors.arrow
.animate(
obj1, _speed)
self.actors.arrow
.animate(
obj2, _speed)
if (i === _time)
{
if (_m === 'afterEffect')
{
if (self.actors.border !== undefined)
{
self.actors.border.remove() ;
}
self.actors.arrow.fadeOut(function()
{
$(this).remove() ;
}) ;
}
else
{
$(document)
.one('click', function()
{
if (self.actors.border !== undefined)
{
self.actors.border.remove() ;
}
self.actors.arrow.stop(true, true) ;
self.actors.arrow.fadeOut(function()
{
$(this).remove() ;
}) ;
}) ;
}
}
}
}
}
$.fn[pg] = function()
{
//處裡套件全域設定
Plugin.args = Array.prototype.slice.call(arguments) ;
return this.each(function() {
if (pgType === 'troops')
{
$.data(this, pg+'Num', $[pg].id);
var tmpAry = ( $.isArray($.data(this, 'plugin_' + pg)) )? $.data(this, 'plugin_' + pg) : [] ;
tmpAry[$[pg].id] = new Plugin(this) ;
$.data(this, 'plugin_' + pg, tmpAry) ;
}
else
{
if (!$.data(this, 'plugin_' + pg))
{
$.data(this, 'plugin_' + pg, new Plugin(this));
}
else if ($.isFunction(Plugin.prototype[ Plugin.args[0] ]))
{
$.data(this, 'plugin_' + pg)[ Plugin.args[0] ](); //吃參數
}
else
{
console.log('wrong way to use this method:' + Plugin.args[0]) ;
}
}
log('$(this).data():') ;
log($(this).data()) ;
});
}
})( jQuery, window, document ) ;
$(function()
{
$(document).ryPoint(
{
xy: '450, 200'
, direction: 'top'
}) ;
$(document).ryPoint(
{
xy: '450, 200'
, direction: 'right'
}) ;
$(document).ryPoint(
{
xy: '450, 200'
, direction: 'bottom'
}) ;
$(document).ryPoint(
{
xy: '450, 200'
, direction: 'left'
}) ;
$('#cube1').ryPoint() ;
$('#cube2').ryPoint(
{
color: 'red' //green or red
}) ;
$('#cube3').ryPoint(
{
color: 'green' //green or red
, size: '100px'
}) ;
$('#cube4').ryPoint(
{
color: 'green' //green or red
, size: '100px'
, effect: 'swing'
}) ;
$('#cube5').ryPoint(
{
color: 'green' //green or red
, size: '100px'
, effect: 'swing'
, removeMode: 'afterClick'
}) ;
$('#cube6').ryPoint(
{
color: 'green' //green or red
, size: '100px'
, effect: 'swing'
, removeMode: 'afterClick'
, direction: 'left'
}) ;
$('#cube7').ryPoint(
{
color: 'green' //green or red
, size: '100px'
, effect: 'swing'
, removeMode: 'afterClick'
, direction: 'left'
, border: true
}) ;
$('#cube8').ryPoint(
{
color: 'green' //green or red
, size: '100px'
, effect: 'swing'
, removeMode: 'afterClick'
, direction: 'left'
, border: true
, padding: 50
}) ;
}) ;
</script>
<div id="cube1" class="cube" style="position:absolute;top:100px; left:100px;width:100px;height:150px;background-color:red;"></div>
<div id="cube2" class="cube" style="position:absolute;top:500px; left:100px;width:100px;height:150px;background-color:orange;"></div>
<div id="cube3" class="cube" style="position:absolute;top:250px; left:400px;width:100px;height:150px;background-color:yellow;"></div>
<div id="cube4" class="cube" style="position:absolute;top:100px; left:900px;width:100px;height:150px;background-color:green;"></div>
<div id="cube5" class="cube" style="position:absolute;top:500px; left:600px;width:100px;height:150px;background-color:blue;"></div>
<div id="cube6" class="cube" style="position:absolute;top:-80px; left:250px;width:100px;height:150px;background-color:purple;"></div>
<div id="cube7" class="cube" style="position:absolute;top:-80px; left:0px;width:100px;height:150px;background-color:black"></div>