diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..08e19ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +npm-debug.log +node_modules +bower_components diff --git a/README.md b/README.md new file mode 100644 index 0000000..eccc97a --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +# lottery [刮刮卡,大转盘,老虎机] + +## 文档说明 + +lottery都继承了**Events**类 插件操作传递数据都通过on绑定 都包含了3个事件[start,end,reset]
+start => (next) 抽奖前触发,主要用于抽奖信息处理,传递回调函数next,需进行调用。
+end => () 抽奖结束触发
+reset => () 抽奖重置触发,主要出现调用了lottery.reset()
+ +lottery都包含了3个操作函数 [setResult,reset,draw]
+setResult => (result) 设置抽奖结果
+reset => () 重置抽奖
+draw => () 开始抽奖(注:刮刮卡调用此方法后会直接显示结果)
+ +### 刮刮卡 + +```html + + +``` + +```javascript +var lottery = new Lottery.Scratch(document.getElementById('js_lottery'),{ + size: 20, //滑动区域大小 + percent: 50, //激活百分比到谋个值 就全显示 + variable: true //canvas的大小是否是可变的 +}); +lottery.on('start',function(next){ + next(); + //中奖结果,传递是中奖结果图片地址 + lottery.setResult('...imageSrc'); +}).on('end',function(){}).on('reset',function(){}); +``` + +### 大转盘 + +```html +
+
+ +
+
+``` + +```javascript +var lottery = new Lottery.Dial(document.getElementById('js_pointer'), { + speed: 30, //每帧速度 + areaNumber: 8 //奖区数量 + }); + var index = -1; + lottery.on('start', function (next) { + next(); + //请求获取中奖结果 + index = Math.round(Math.random() * 7); + //中奖结果,传递停留奖区下标0开始 + lottery.setResult(index); + }).on('end', function () { + console.log('中奖奖区:' + index); + }).on('reset',function(){}); +``` + +### 老虎机 + +```html +
+
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
+
+``` + +```javascript +//老虎机动画因为性能问题采用css3 所以需要完成2个动画fx-bounce fx-roll 详细查看examples +var lottery = new Tiger(document.getElementById('js_toggle'), document.querySelectorAll('.roller'), { + timeout: 300, //每个roller间动画间隔 + timeDiff: 6000, //动画执行最少时间 + variable: true //roller大小是否是可变的 + }); + lottery.on('start', function (next) { + next(); + setTimeout(function () { + var ret = [Math.round(Math.random() * 2), Math.round(Math.random() * 2), Math.round(Math.random() * 2)]; + //中奖结果,传递每个roller停留下标0开始 + lottery.setResult(ret); + }, 1000); + }).on('end', function(){}).on('reset',function(){}); +``` + + +## 浏览器支持 + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | Latest ✔ | \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..1f17c19 --- /dev/null +++ b/bower.json @@ -0,0 +1,23 @@ +{ + "name": "lottery", + "homepage": "https://github.com/TOP-Chao/lottery", + "authors": [ + "wenchao " + ], + "description": "", + "main": "gulpfile.js", + "moduleType": [], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests", + "examples" + ], + "devDependencies": { + "angular": "~1.4.7", + "top-webapp": "0.0.1" + } +} diff --git a/dist/ui-lottery.js b/dist/ui-lottery.js new file mode 100644 index 0000000..0bc7f9a --- /dev/null +++ b/dist/ui-lottery.js @@ -0,0 +1,11 @@ +(function () { + if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { + define(function () { + return Lottery; + }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Lottery; + } else { + window.Lottery = Lottery; + } +})(); \ No newline at end of file diff --git a/dist/ui-lottery.min.js b/dist/ui-lottery.min.js new file mode 100644 index 0000000..11940b9 --- /dev/null +++ b/dist/ui-lottery.min.js @@ -0,0 +1 @@ +!function(){"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return Lottery}):"undefined"!=typeof module&&module.exports?module.exports=Lottery:window.Lottery=Lottery}(); \ No newline at end of file diff --git a/examples/css/style.css b/examples/css/style.css new file mode 100644 index 0000000..3f5cad8 --- /dev/null +++ b/examples/css/style.css @@ -0,0 +1 @@ +*{margin:0;padding:0}html{font-size:20px;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}html,body{width:100%;height:100%;-webkit-user-select:none;-ms-user-select:none;-moz-user-select:none;user-select:none}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}img,video{max-width:100%;height:auto;border:0 none;vertical-align:bottom}li{list-style:none}svg:not(:root){overflow:hidden}a{text-decoration:none}a,img,button,input[type='button'],input[type='submit'],input[type='reset']{outline:none;-webkit-tap-highlight-color:rgba(255,255,255,0)}input:-ms-clear{display:none}input[type='search']::-webkit-search-cancel-button{display:none}input,textarea{-webkit-user-modify:read-write-plaintext-only;-webkit-appearance:none;outline:none}button,input,textarea{border:0 none}body,button,input,textarea,select,option,pre,optgroup{line-height:1.5;font-family:"Microsoft YaHei","微软雅黑",Helvetica,Arial;color:#333;font-size:0.6rem}.f-cb:after,.f-cb li:after{content:'';display:table;clear:both}.f-wsn{word-wrap:normal;white-space:nowrap}.f-wwb{white-space:normal;word-wrap:break-word;word-break:break-all}.f-toe{overflow:hidden;word-wrap:normal;white-space:nowrap;text-overflow:ellipsis}.f-ma{margin-left:auto;margin-right:auto}.f-box{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.m-alert{position:fixed;top:0;left:0;z-index:10000;width:100%;height:100%;background-color:transparent}.m-alert .text{width:11rem;padding:1.25rem 0.75rem;text-align:center;line-height:1.4rem;font-size:0.8rem;color:#fff;background-color:rgba(0,0,0,0.7);white-space:normal;word-wrap:break-word;word-break:break-all;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);border-radius:0.25rem}.m-alert.fx-fadeIn,.m-alert.fx-fadeOut{-webkit-animation-duration:0.3s;animation-duration:0.3s;-webkit-animation-fill-mode:ease;animation-fill-mode:ease}[class*='fx-']{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.fx-bug{-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-backface-visibility:visible;backface-visibility:visible}.fx-gpu,.m-lottery-tiger .game .item .roller{-webkit-transform:"translateZ(0)";transform:"translateZ(0)";-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.fx-infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.fx-fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.fx-fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@media screen and (min-width: 320px){html{font-size:20px}}@media screen and (min-width: 360px){html{font-size:22.5px}}@media screen and (min-width: 375px){html{font-size:23.4375px}}@media screen and (min-width: 384px){html{font-size:24px}}@media screen and (min-width: 400px){html{font-size:25px}}@media screen and (min-width: 412px){html{font-size:25.75px}}@media screen and (min-width: 414px){html{font-size:25.875px}}@media screen and (min-width: 533px){html{font-size:33.3125px}}@media screen and (min-width: 600px){html{font-size:37.5px}}@media screen and (min-width: 768px){html{font-size:48px}}.m-ui-dial{position:relative;width:499px;height:499px;margin:0 auto;background:url("../images/dial_bg.png") no-repeat center;background-size:100%}.m-ui-dial .pointer{margin-top:-139px !important;background:url("../images/dial_pointer.png") no-repeat center;background-size:100%;position:absolute;top:50%;left:50%;display:block;width:150px;height:238px;margin:-119px 0 0 -75px;-webkit-transform-origin:75px 139px;transform-origin:75px 139px}.m-ui-dial .btn{position:absolute;top:64px;left:0;display:block;width:150px;height:150px;border-radius:75px}.m-ui-scratch{display:block;width:300px;height:172.5px;margin:20px auto;background:no-repeat center;background-size:100%}.m-ui-button{display:block;width:160px;height:32px;margin:0 auto;text-align:center;line-height:32px;font-size:12px;color:#fff;background-color:#f94804;cursor:pointer;border-radius:5px}.m-ui-tiger{position:relative;width:640px;height:432px;margin:20px auto;background:url("../images/tiger_bg.png") no-repeat}.m-ui-tiger .toggle{position:absolute;top:306px;left:119px;display:block;width:404px;height:50px}.m-ui-tiger .item{position:absolute;top:77px;left:139px;display:block;width:110px;height:135px;overflow:hidden}.m-ui-tiger .item:nth-child(2){left:265px}.m-ui-tiger .item:nth-child(3){left:391px}.m-ui-tiger .roller{position:relative}.m-ui-tiger .roller li{width:110px;height:135px;overflow:hidden}.m-ui-tiger .roller li:last-child{position:absolute;top:100%;left:0}.m-ui-tiger .roller img{display:block;width:110px;height:135px}.m-ui-tiger .roller.fx-roll{-webkit-filter:blur(3px);filter:blur(3px);-webkit-animation:fx-roll 0.5s 0s infinite linear;animation:fx-roll 0.5s 0s infinite linear}.m-ui-tiger .roller.fx-bounce{-webkit-animation-duration:0.3s;animation-duration:0.3s}.m-lottery-scratch{position:relative;width:16rem;min-height:100%;margin:0 auto;padding-top:9rem;background:url("../images/scratch_page_bg.jpg") no-repeat #ff5e01;background-size:100% auto}.m-lottery-scratch .game{position:relative;display:block;width:10rem;margin:0 auto;height:5.75rem}.m-lottery-scratch .game canvas{position:absolute;top:0;left:0;display:block;width:100%;height:100%;background-size:100% 100%}.m-lottery-scratch .game button{display:block;width:5rem;height:1.5rem;margin:0 auto;text-align:center;line-height:1.4rem;font-size:0.7rem;color:#fff;background-color:#ff5e01;border:0 none;cursor:pointer;border-radius:0.3rem}.m-lottery-scratch .game button.z-dis{background-color:#bcbcbc}.m-lottery-scratch .game .ceiling{position:absolute;top:0;left:0;z-index:3;width:100%;height:4rem;padding:0.5rem 0 1.25rem;background:url("../images/scratch_ceiling.jpg") no-repeat;background-size:100% 100%;overflow:hidden}.m-lottery-scratch .game .ceiling .tip{display:block;height:2.5rem;line-height:2.5rem;text-align:center;font-size:0.8rem;color:#ff5e01;overflow:hidden}.m-lottery-scratch .des{margin-top:2.35rem;padding:0 1.1rem 0.5rem;line-height:1.15rem;font-size:0.6rem;color:#fff}.m-lottery-scratch .des dt{line-height:1.2rem;font-size:0.7rem;font-weight:700}.m-lottery-dial{position:relative;width:16rem;min-height:100%;margin:0 auto;padding-top:7rem;background:url("../images/dial_page_bg.jpg") no-repeat #f94804;background-size:100% auto}.m-lottery-dial .game-dial{position:relative;width:12.5rem;height:12.5rem;margin:0 auto}.m-lottery-dial .game-dial .dial{width:100%;height:100%;background-size:100% auto}.m-lottery-dial .game-dial .pointer{position:absolute;top:50%;left:50%;width:3.75rem;height:5.95rem;margin:-3.4rem 0 0 -1.875rem;background-size:100% auto;-webkit-transform-origin:1.875rem 3.4rem;transform-origin:1.875rem 3.4rem}.m-lottery-dial .game-dial .pointer span{position:absolute;top:1.6rem;left:0;display:block;width:3.75rem;height:3.75rem;cursor:pointer}.m-lottery-dial .des{margin-top:4.2rem;padding:0 1.1rem 0.5rem;line-height:1.15rem;font-size:0.6rem;color:#fff}.m-lottery-dial .des dt{line-height:1.2rem;font-size:0.7rem;font-weight:700}.m-lottery-tiger{position:relative;width:16rem;min-height:100%;margin:0 auto;padding-top:5.5rem;background:url("../images/tiger_page_bg.jpg") no-repeat #ffeec6;background-size:100% auto}.m-lottery-tiger .game{position:relative}.m-lottery-tiger .game .back{width:16rem;height:10.8rem;background-size:100%;background-repeat:no-repeat}.m-lottery-tiger .game .item{position:absolute;top:1.925rem;width:2.75rem;height:3.375rem;overflow:hidden}.m-lottery-tiger .game .item:nth-child(1){left:3.475rem}.m-lottery-tiger .game .item:nth-child(2){left:6.625rem}.m-lottery-tiger .game .item:nth-child(3){left:9.775rem}.m-lottery-tiger .game .item .roller{position:relative}.m-lottery-tiger .game .item .roller li.z-last{position:absolute;top:100%;left:0}.m-lottery-tiger .game .item .roller.fx-bounce{-webkit-animation-duration:0.3s;animation-duration:0.3s}.m-lottery-tiger .game .item .roller.fx-roll{-webkit-filter:blur(3px);filter:blur(3px);-webkit-animation:fx-roll 0.3s 0s infinite linear;animation:fx-roll 0.3s 0s infinite linear}.m-lottery-tiger .game .item img{display:block;width:2.75rem;height:3.375rem}.m-lottery-tiger .game .btn{position:absolute;left:50%;top:7.65rem;width:10.1rem;height:1.25rem;margin-left:-5.05rem;background-size:100%;background-repeat:no-repeat}.m-lottery-tiger .game .btn span{display:block;width:100%;height:100%;cursor:pointer}.m-lottery-tiger .des{padding:0 1.1rem 0.5rem;line-height:1.15rem;font-size:0.6rem;color:#b26722}.m-lottery-tiger .des dt{line-height:1.2rem;font-size:0.7rem;font-weight:700}@-webkit-keyframes fx-roll{0%{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}100%{-webkit-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0)}}@keyframes fx-roll{0%{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}100%{-webkit-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0)}}.fx-bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes bounce{0%,20%,53%,80%,100%{-webkit-animation-timing-function:cubic-bezier(0.215, 0.61, 0.355, 1);animation-timing-function:cubic-bezier(0.215, 0.61, 0.355, 1);-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0)}70%{-webkit-animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0)}90%{-webkit-transform:translate3d(0, -4px, 0);transform:translate3d(0, -4px, 0)}}@keyframes bounce{0%,20%,53%,80%,100%{-webkit-animation-timing-function:cubic-bezier(0.215, 0.61, 0.355, 1);animation-timing-function:cubic-bezier(0.215, 0.61, 0.355, 1);-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0)}70%{-webkit-animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);animation-timing-function:cubic-bezier(0.755, 0.05, 0.855, 0.06);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0)}90%{-webkit-transform:translate3d(0, -4px, 0);transform:translate3d(0, -4px, 0)}} diff --git a/examples/images/dial_bg.png b/examples/images/dial_bg.png new file mode 100644 index 0000000..b928f45 Binary files /dev/null and b/examples/images/dial_bg.png differ diff --git a/examples/images/dial_page_bg.jpg b/examples/images/dial_page_bg.jpg new file mode 100644 index 0000000..32c880c Binary files /dev/null and b/examples/images/dial_page_bg.jpg differ diff --git a/examples/images/dial_pointer.png b/examples/images/dial_pointer.png new file mode 100644 index 0000000..06c5fb2 Binary files /dev/null and b/examples/images/dial_pointer.png differ diff --git a/examples/images/scratch_ceiling.jpg b/examples/images/scratch_ceiling.jpg new file mode 100644 index 0000000..cbdcbf1 Binary files /dev/null and b/examples/images/scratch_ceiling.jpg differ diff --git a/examples/images/scratch_no.png b/examples/images/scratch_no.png new file mode 100644 index 0000000..12e8a39 Binary files /dev/null and b/examples/images/scratch_no.png differ diff --git a/examples/images/scratch_page_bg.jpg b/examples/images/scratch_page_bg.jpg new file mode 100644 index 0000000..1f1def0 Binary files /dev/null and b/examples/images/scratch_page_bg.jpg differ diff --git a/examples/images/tiger_awards_1.png b/examples/images/tiger_awards_1.png new file mode 100644 index 0000000..7398b54 Binary files /dev/null and b/examples/images/tiger_awards_1.png differ diff --git a/examples/images/tiger_awards_2.png b/examples/images/tiger_awards_2.png new file mode 100644 index 0000000..171b00d Binary files /dev/null and b/examples/images/tiger_awards_2.png differ diff --git a/examples/images/tiger_awards_3.png b/examples/images/tiger_awards_3.png new file mode 100644 index 0000000..132c20d Binary files /dev/null and b/examples/images/tiger_awards_3.png differ diff --git a/examples/images/tiger_bg.png b/examples/images/tiger_bg.png new file mode 100644 index 0000000..d478bbb Binary files /dev/null and b/examples/images/tiger_bg.png differ diff --git a/examples/images/tiger_page_bg.jpg b/examples/images/tiger_page_bg.jpg new file mode 100644 index 0000000..b80298b Binary files /dev/null and b/examples/images/tiger_page_bg.jpg differ diff --git a/examples/js/ng-lottery.js b/examples/js/ng-lottery.js new file mode 100644 index 0000000..2d5e96f --- /dev/null +++ b/examples/js/ng-lottery.js @@ -0,0 +1,763 @@ +(function () { + var lottery = angular.module('ngLottery', []); + lottery.config(['$httpProvider', function ($httpProvider) { + //解决$http.post取不到值 + $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'; + var param = function (obj) { + var query = '', name, value, fullSubName, subName, subValue, innerObj, i; + for (name in obj) { + value = obj[name]; + if (value instanceof Array) { + for (i = 0; i < value.length; ++i) { + subValue = value[i]; + fullSubName = name + '[' + i + ']'; + innerObj = {}; + innerObj[fullSubName] = subValue; + query += param(innerObj) + '&'; + } + } + else if (value instanceof Object) { + for (subName in value) { + subValue = value[subName]; + fullSubName = name + '[' + subName + ']'; + innerObj = {}; + innerObj[fullSubName] = subValue; + query += param(innerObj) + '&'; + } + } + else if (value !== undefined && value !== null) + query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; + } + + return query.length ? query.substr(0, query.length - 1) : query; + }; + $httpProvider.defaults.transformRequest = [function (data) { + return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data; + }]; + }]); + lottery.factory('LotteryRequest', ['$http', function ($http) { + var Request = function (config) { + this.config = config; + }; + Request.prototype = { + _request: function (index, callback) { + $http.post(this.config.url, { + ifName: this.config.ifName[index], + data: JSON.stringify(this.config.data) + }).success(function (ret) { + if (ret.code == 0) { + (callback['success'] || angular.noop)(ret.result); + } else { + (callback['error'] || angular.noop)(ret.msg); + } + }).error(function () { + (callback['error'] || angular.noop)('服务器繁忙,连接失败!'); + }); + }, + get: function (callback) { + this._request(0, callback); //向服务器获取数据 + }, + post: function (callback) { + this._request(1, callback); //向服务器提交数据 + } + }; + return Request; + }]); + lottery.service('lotteryState', function () { + return function (state, next) { + if (state == -1) return; + if (state == 3) { + alert('亲,活动还未开始!', 'z-warn'); //未开始 + } else if (state == 2) { + alert('亲,活动已经结束!', 'z-warn'); //已结束 + } else if (state == 1) { + alert('亲,活动暂停中!', 'z-warn'); //暂停中 + } else { + next(); + } + } + }); + lottery.factory('Lottery', function () { + var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; + var Lottery; + (function (Lottery) { + var Tool = (function () { + function Tool() { + } + Tool.extends = function (opt) { + var more = []; + for (var _i = 1; _i < arguments.length; _i++) { + more[_i - 1] = arguments[_i]; + } + opt = opt || {}; + for (var i = 1; i < arguments.length; i++) { + if (!!arguments[i]) { + for (var key in arguments[i]) { + if (arguments[i].hasOwnProperty(key)) { + opt[key] = arguments[i][key]; + } + } + } + } + return opt; + }; + Tool.camelCase = function (str) { + return str.replace(/-([a-z])/ig, function (all, letter) { + return letter.toUpperCase(); + }); + }; + Tool.css = function (element, property, value) { + if (element.style[property] === undefined) { + for (var i = 0; i < this._vendors.length; i++) { + property = this.camelCase(this._vendors[i] + '-' + property); + if (element.style[property] !== undefined) { + break; + } + } + } + element.style[property] = value; + return property; + }; + Tool._vendors = ['webkit', 'ms', 'moz', 'o']; + return Tool; + })(); + var Events = (function () { + function Events() { + this._queue = {}; + } + Events.prototype.on = function (key, callback) { + this._queue[key] = this._queue[key] || []; + this._queue[key].push(callback); + return this; + }; + Events.prototype.off = function (key, callback) { + if (!this._queue[key]) + return this; + var index = typeof (callback) == "undefined" ? -2 : this._queue[key].indexOf(callback); + if (index == -2) { + delete this._queue[key]; + } + else if (index != -1) { + this._queue[key].splice(index, 1); + } + if (this._queue[key] && this._queue[key].length == 0) + delete this._queue[key]; + return this; + }; + Events.prototype.has = function (key) { + return !!this._queue[key]; + }; + Events.prototype.trigger = function (key) { + var value = []; + for (var _i = 1; _i < arguments.length; _i++) { + value[_i - 1] = arguments[_i]; + } + if (!this._queue[key]) + return this; + for (var i = 0; i < this._queue[key].length; i++) { + this._queue[key][i].apply(null, value); + } + return this; + }; + return Events; + })(); + var TigerRoller = (function () { + function TigerRoller(elem, variable) { + this.index = 0; + this.state = 0; + this.elem = elem; + this.items = elem.children; + this.height = this.items[0].clientHeight; + //克隆第一个节点 用于制作无限滚动效果 + this.elem.appendChild(this.items[0].cloneNode(true)); + //如果大小是可变的就绑定resize事件 + if (variable) + window.addEventListener('onorientationchange' in document ? 'orientationchange' : 'resize', this._onResize.bind(this)); + } + TigerRoller.prototype.reset = function () { + this.elem.classList.remove('fx-roll'); + this.elem.style.marginTop = 0; + this.callback = null; + this.index = 0; + this.state = 0; + }; + TigerRoller.prototype.start = function (timeout) { + var _this = this; + if (timeout === void 0) { timeout = 0; } + this.state = 1; + setTimeout(function () { + if (_this.state != 1) + return; + _this.elem.style.marginTop = 0; + _this.elem.classList.add('fx-roll'); + }, timeout); + }; + TigerRoller.prototype.stop = function (index, callback, timeout) { + var _this = this; + if (timeout === void 0) { timeout = 0; } + this.callback = callback; + this.index = index; + setTimeout(function () { + if (_this.state != 1) + return; + _this.elem.style.marginTop = -index * _this.height + 'px'; + _this.elem.classList.remove('fx-roll'); + _this.elem.classList.add('fx-bounce'); + window['animationEnd'](_this.elem, function () { + _this.state = 0; + _this.elem.classList.remove('fx-bounce'); + if (_this.callback) + _this.callback.call(_this); + }, true); + }, timeout); + }; + TigerRoller.prototype._onResize = function () { + this.height = this.items[0].clientHeight; + if (!this.elem.classList.contains('fx-roll')) + this.elem.style.marginTop = -this.index * this.height + 'px'; + }; + return TigerRoller; + })(); + var Dial = (function (_super) { + __extends(Dial, _super); + function Dial(pointer, config) { + var _this = this; + _super.call(this); + this.config = { + speed: 30, + areaNumber: 8 //奖区数量 + }; + this._transform = 'transform'; + this._runAngle = 0; + this._targetAngle = -1; + this.pointer = pointer; + this.config = Tool.extends({}, this.config, config); + //初始化样式设定 + this._transform = Tool.css(this.pointer, this._transform, 'translate3d(0,0,0)'); + Tool.css(this.pointer, 'backfaceVisibility', 'hidden'); + Tool.css(this.pointer, 'perspective', '1000px'); + //事件注入 (当设置结果时) + this.on('__setResult', function (index) { + //得到中奖结果 index:中奖奖区下标 + var singleAngle = 360 / _this.config.areaNumber, //单个奖区角度值 + endAngle = Math.ceil((Math.random() * singleAngle) + (index * singleAngle)); //随机得出结果角度 + _this._runAngle = 0; + _this._targetAngle = endAngle + (Math.floor(Math.random() * 4) + 4) * 360; //随机旋转几圈再停止 + }); + } + Dial.prototype.setResult = function (index) { + this.trigger('__setResult', index); + }; + Dial.prototype.reset = function (event) { + if (event === void 0) { event = 'reset'; } + if (!this._raf) + return; + window.cancelAnimationFrame(this._raf); + this._raf = null; + this._runAngle = 0; + this._targetAngle = -1; + this.trigger(event); + if (event == 'reset') + Tool.css(this.pointer, this._transform, 'translate3d(0,0,0) rotate(0deg)'); + }; + Dial.prototype.draw = function () { + if (this._raf) + return; + var _draw = function () { + var angle = 0; + var step = function () { + //如果没有设置结束点 就匀速不停旋转 + //如果设置了结束点 就减速到达结束点 + if (this._targetAngle == -1) { + this._runAngle += this.config.speed; + } + else { + angle = (this._targetAngle - this._runAngle) / this.config.speed; + angle = angle > this.config.speed ? this.config.speed : angle < 0.5 ? 0.5 : angle; + this._runAngle += angle; + this._runAngle = this._runAngle > this._targetAngle ? this._targetAngle : this._runAngle; + } + //指针旋转 + Tool.css(this.pointer, this._transform, 'translate3d(0,0,0) rotate(' + (this._runAngle % 360) + 'deg)'); + if (this._runAngle == this._targetAngle) { + this.reset('end'); + } + else { + this._raf = window.requestAnimationFrame(step.bind(this)); + } + }; + this._raf = window.requestAnimationFrame(step.bind(this)); + }; + this.has('start') ? this.trigger('start', _draw.bind(this)) : _draw.call(this); + }; + return Dial; + })(Events); + Lottery.Dial = Dial; + var Scratch = (function (_super) { + __extends(Scratch, _super); + function Scratch(canvas, config) { + _super.call(this); + this.config = { + size: 20, + percent: 50, + variable: true //canvas的大小是否是可变的 + }; + this._state = 'load'; + this._touch = false; + this._request = false; + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + this.config = Tool.extends({}, this.config, config); + //初始化 + this._state = 'init'; + this._init(); + //绑定事件 + this.canvas.addEventListener('ontouchstart' in document ? 'touchstart' : 'mousedown', this._onTouchStart.bind(this), false); + this.canvas.addEventListener('ontouchmove' in document ? 'touchmove' : 'mousemove', this._onTouchMove.bind(this), false); + document.addEventListener('ontouchend' in document ? 'touchend' : 'mouseup', this._onTouchEnd.bind(this)); + window.addEventListener('onorientationchange' in document ? 'orientationchange' : 'resize', this._onResize.bind(this)); + } + Scratch.prototype.setResult = function (url) { + this.canvas.style.backgroundImage = 'url(' + url + ')'; + }; + Scratch.prototype.draw = function () { + if (this._state == 'end') + return; + this.ctx.clearRect(0, 0, this.width, this.height); + this._state = 'end'; + this.trigger('end'); + }; + Scratch.prototype.reset = function () { + this._state = 'init'; + this._request = false; + this._touch = false; + this.canvas.style.backgroundImage = null; + this._init(); + this.trigger('reset'); + }; + Scratch.prototype._init = function () { + this._setCanvasSize(); + this._getCanvasOffset(); + this.ctx.closePath(); + this.ctx.globalCompositeOperation = 'source-over'; + this.ctx.fillStyle = 'gray'; + this.ctx.fillRect(0, 0, this.width, this.height); + this.ctx.globalCompositeOperation = 'destination-out'; + }; + Scratch.prototype._scratchPercent = function () { + var hits = 0, imageData = this.ctx.getImageData(0, 0, this.width, this.height); + for (var i = 0, ii = imageData.data.length; i < ii; i = i + 4) { + if (imageData.data[i] === 0 && imageData.data[i + 1] === 0 && imageData.data[i + 2] === 0 && imageData.data[i + 3] === 0) { + hits++; + } + } + return (hits / (this.width * this.height)) * 100; + }; + Scratch.prototype._setCanvasSize = function () { + this.width = this.canvas.clientWidth; + this.height = this.canvas.clientHeight; + this.canvas.width = this.width; + this.canvas.height = this.height; + }; + Scratch.prototype._getCanvasOffset = function () { + var box = this.canvas.getBoundingClientRect(); + var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; + var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft; + var clientTop = document.documentElement.clientTop || document.body.clientTop || 0; + var clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0; + this.offsetX = Math.round(box.left + scrollLeft - clientLeft); + this.offsetY = Math.round(box.top + scrollTop - clientTop); + }; + Scratch.prototype._getEventXY = function (e) { + e = e.changedTouches ? e.changedTouches[0] : e; + return { + x: e.pageX - this.offsetX, + y: e.pageY - this.offsetY + }; + }; + Scratch.prototype._onTouchStart = function (e) { + e.preventDefault(); + if (this._state == 'end') + return; + var _draw = function (e) { + var point = this._getEventXY(e); + this._state = 'start'; + this._touch = true; + this._request = true; + this.ctx.beginPath(); + this.ctx.arc(point.x, point.y, this.config.size / 2, 0, Math.PI * 2, true); + this.ctx.closePath(); + this.ctx.fill(); + this.ctx.beginPath(); + this.ctx.lineWidth = this.config.size; + this.ctx.moveTo(point.x, point.y); + }; + this.has('start') && !this._request ? this.trigger('start', _draw.bind(this, e)) : _draw.call(this, e); + }; + Scratch.prototype._onTouchMove = function (e) { + e.preventDefault(); + if (!this._touch) + return; + var point = this._getEventXY(e); + this.ctx.lineTo(point.x, point.y); + this.ctx.stroke(); + }; + Scratch.prototype._onTouchEnd = function (e) { + if (!this._touch) + return; + var point = this._getEventXY(e); + this._touch = false; + this.ctx.closePath(); + this.ctx.beginPath(); + this.ctx.arc(point.x, point.y, this.config.size / 2, 0, Math.PI * 2, true); + this.ctx.closePath(); + this.ctx.fill(); + if (this._scratchPercent() >= this.config.percent) { + this.ctx.clearRect(0, 0, this.width, this.height); + this._state = 'end'; + this.trigger('end'); + } + }; + Scratch.prototype._onResize = function () { + this._touch = false; + if (this.config.variable) { + if (this._state == 'end') { + this._setCanvasSize(); + } + else { + this._init(); + } + } + else { + this._getCanvasOffset(); + } + }; + return Scratch; + })(Events); + Lottery.Scratch = Scratch; + var Tiger = (function (_super) { + __extends(Tiger, _super); + function Tiger(toggle, roller, config) { + _super.call(this); + this.config = { + timeout: 300, + timeDiff: 6000, + variable: true //roller大小是否是可变的 + }; + this.rollerQueue = []; + this.toggle = toggle; + this.config = Tool.extends({}, this.config, config); + //初始化滚轴 + for (var i = 0; i < roller.length; i++) { + this.rollerQueue.push(new TigerRoller(roller[i], this.config.variable)); + } + } + Tiger.prototype.setResult = function (ret) { + var _this = this; + //保证动画执行时间 + var endTime = (new Date()).getTime(); + setTimeout(function () { + for (var i = 0, l = _this.rollerQueue.length; i < l; i++) { + _this.rollerQueue[i].stop(ret[i], (i == l - 1 ? function () { + _this.toggle.classList.remove('z-active'); + _this.trigger('end'); + } : null), i * _this.config.timeout); + } + }, endTime - this._startTime > this.config.timeDiff ? 0 : this.config.timeDiff - (endTime - this._startTime)); + }; + Tiger.prototype.reset = function () { + this.toggle.classList.remove('z-active'); + for (var i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].reset(); + } + this.trigger('reset'); + }; + Tiger.prototype.draw = function () { + if (this.toggle.classList.contains('z-active')) + return; + var _draw = function () { + this.toggle.classList.add('z-active'); + for (var i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].start(i * this.config.timeout); + } + }; + this._startTime = (new Date()).getTime(); + this.has('start') ? this.trigger('start', _draw.bind(this)) : _draw.call(this); + }; + return Tiger; + })(Events); + Lottery.Tiger = Tiger; + })(Lottery || (Lottery = {})); + return Lottery; + }); + lottery.directive('uiLotteryScratch', ['$timeout', 'Lottery', 'LotteryRequest', 'lotteryState', 'lotteryConfig', + function ($timeout, Lottery, LotteryRequest, lotteryState, lotteryConfig) { + return { + restrict: 'A', + scope: { + lottery: '=', + onReady: '&', + onResult: '&' + }, + controller: ['$scope', function ($scope) { + $scope.lottery = { + state: -1, + result: null, + config: null, + start: angular.noop, + reset: angular.noop + }; + }], + link: function (scope, el, attr) { + var timeout = lotteryConfig.timeout || 500, + request = new LotteryRequest(lotteryConfig.request); + + var init = function () { + var lotteryObj = new Lottery.Scratch(el[0].querySelector('canvas'), lotteryConfig.game || {}); + lotteryObj.on('start', function (next) { + next(); + //获取抽奖结果 + request.post({ + 'success': function (ret) { + lotteryObj.setResult(ret.web_des); + scope.lottery.result = ret; + }, + 'error': function (msg) { + lotteryObj.reset(); + alert(msg, 'z-error'); + } + }); + }).on('end', function () { + $timeout(function () { + scope.lottery.state = 3; + scope.onResult({'result': scope.lottery.result}); + }, timeout); + }).on('reset', function () { + scope.lottery.result = null; + scope.lottery.state = 0; + }); + + //提供给外部调用方法 + scope.lottery.start = function () { + //抽奖状态过滤 + lotteryState(scope.lottery.config ? scope.lottery.config.state : -1, function () { + scope.lottery.state = scope.lottery.state == 0 ? 1 : scope.lottery.state; + }); + }; + scope.lottery.reset = function () { + lotteryObj.reset(); + scope.lottery.state = 1; + }; + }; + + //获取抽奖信息 + request.get({ + 'success': function (ret) { + scope.lottery.state = 0; + scope.lottery.config = ret; + scope.onReady({config: ret}); + $timeout(init, 50); + }, + 'error': function (msg) { + alert(msg, 'z-error'); + } + }); + } + } + }]); + lottery.directive('uiLotteryDial', ['$timeout', 'Lottery', 'LotteryRequest', 'lotteryState', 'lotteryConfig', + function ($timeout, Lottery, LotteryRequest, lotteryState, lotteryConfig) { + return { + restrict: 'A', + scope: { + lottery: '=', + onReady: '&', + onResult: '&' + }, + templateUrl: 'template/lottery-dial.ejs', + controller: ['$scope', function ($scope) { + $scope.lottery = { + result: null, + config: null, + start: angular.noop, + dialBackground: {}, + pointerBackground: {} + }; + }], + link: function (scope, el, attr) { + var request = new LotteryRequest(lotteryConfig.request); + var init = function () { + var lotteryObj = new Lottery.Dial(el[0].querySelector('.pointer'), lotteryConfig.game || {}); + lotteryObj.on('start', function (next) { + next(); + //获取抽奖结果 + request.post({ + 'success': function (ret) { + lotteryObj.setResult(ret.sectors_number); + scope.lottery.result = ret; + }, + 'error': function (msg) { + lotteryObj.reset(); + alert(msg, 'z-error'); + } + }); + }).on('end', function () { + scope.onResult({'result': scope.lottery.result}); + }).on('reset', function () { + scope.lottery.result = null; + }); + + //提供给外部调用方法 + scope.lottery.start = function () { + //抽奖状态过滤 + lotteryState(scope.lottery.config ? scope.lottery.config.state : -1, lotteryObj.draw.bind(lotteryObj)); + }; + }; + + //获取抽奖信息 + request.get({ + 'success': function (ret) { + scope.lottery.config = ret; + scope.lottery.dialBackground = {'background-image': 'url(' + ret.back_web_des + ')'}; + scope.lottery.pointerBackground = {'background-image': 'url(' + ret.btn_web_des + ')'}; + scope.onReady({config: ret}); + $timeout(init, 50); + }, + 'error': function (msg) { + alert(msg, 'z-error'); + } + }); + } + } + }]); + lottery.directive('uiLotteryTiger', ['$timeout', 'Lottery', 'LotteryRequest', 'lotteryState', 'lotteryConfig', + function ($timeout, Lottery, LotteryRequest, lotteryState, lotteryConfig) { + return { + restrict: 'A', + scope: { + lottery: '=', + onReady: '&', + onResult: '&' + }, + templateUrl: 'template/lottery-tiger.ejs', + controller: ['$scope', function ($scope) { + $scope.lottery = { + result: null, + config: null, + start: angular.noop, + backBackground: {}, + btnBackground: {} + }; + }], + link: function (scope, el, attr) { + lotteryConfig.rankCount = lotteryConfig.rankCount || 3; + scope.ranks = []; + for (var i = 0; i < lotteryConfig.rankCount; i++) { + scope.ranks[i] = i; + } + var request = new LotteryRequest(lotteryConfig.request); + + var init = function () { + var lotteryObj = new Lottery.Tiger(el[0].querySelector('.toggle'), el[0].querySelectorAll('.roller'), lotteryConfig.game); + lotteryObj.on('start', function (next) { + next(); + //获取抽奖结果 + request.post({ + 'success': function (ret) { + lotteryObj.setResult(ret.sectors_index); + scope.lottery.result = ret; + }, + 'error': function (msg) { + lotteryObj.reset(); + alert(msg, 'z-error'); + } + }); + }).on('end', function () { + scope.onResult({'result': scope.lottery.result}); + }).on('reset', function () { + scope.lottery.result = null; + }); + + //提供给外部调用方法 + scope.lottery.start = function () { + //抽奖状态过滤 + lotteryState(scope.lottery.config ? scope.lottery.config.state : -1, lotteryObj.draw.bind(lotteryObj)); + }; + }; + + //读取抽奖信息 + request.get({ + 'success': function (ret) { + scope.lottery.config = ret; + scope.lottery.backBackground = {'background-image': 'url(' + ret.back_web_des + ')'}; + scope.lottery.btnBackground = {'background-image': 'url(' + ret.btn_web_des + ')'}; + scope.onReady({config: ret}); + $timeout(init, 50); + }, + 'error': function (msg) { + alert(msg, 'z-error'); + } + }); + } + } + }]); + lottery.directive('uiLotteryButton', ['LotteryRequest', 'lotteryState', 'lotteryConfig', + function (LotteryRequest, lotteryState, lotteryConfig) { + return { + restrict: 'A', + scope: { + lottery: '=', + onReady: '&', + onResult: '&' + }, + controller: ['$scope', function ($scope) { + $scope.lottery = { + state: -1, + result: null, + config: null, + start: angular.noop + }; + }], + link: function (scope, el, attr) { + var request = new LotteryRequest(lotteryConfig.request); + + //读取抽奖信息 + request.get({ + 'success': function (ret) { + scope.lottery.state = 0; + scope.lottery.config = ret; + scope.onReady({config: ret}); + }, + 'error': function (msg) { + alert(msg, 'z-error'); + } + }); + //开始抽奖 + scope.lottery.start = function () { + if (scope.lottery.state == 0) { + //抽奖状态过滤 + lotteryState(scope.lottery.config ? scope.lottery.config.state : -1, function () { + scope.lottery.state = 1; + //获取抽奖结果 + request.post({ + 'success': function (ret) { + scope.lottery.state = 0; + scope.lottery.result = ret; + scope.onResult({'result': ret}); + }, + 'error': function (msg) { + scope.lottery.state = 0; + alert(msg, 'z-error'); + } + }); + }); + } + } + } + } + }]); +})(); \ No newline at end of file diff --git a/examples/js/ng-lottery.min.js b/examples/js/ng-lottery.min.js new file mode 100644 index 0000000..bd96611 --- /dev/null +++ b/examples/js/ng-lottery.min.js @@ -0,0 +1 @@ +!function(){var t=angular.module("ngLottery",[]);t.config(["$httpProvider",function(t){t.defaults.headers.post["Content-Type"]="application/x-www-form-urlencoded;charset=utf-8";var e=function(t){var n,i,o,s,r,a,c,u="";for(n in t)if(i=t[n],i instanceof Array)for(c=0;cthis.config.speed?this.config.speed:.5>t?.5:t,this._runAngle+=t,this._runAngle=this._runAngle>this._targetAngle?this._targetAngle:this._runAngle),n.css(this.pointer,this._transform,"translate3d(0,0,0) rotate("+this._runAngle%360+"deg)"),this._runAngle==this._targetAngle?this.reset("end"):this._raf=window.requestAnimationFrame(e.bind(this))};this._raf=window.requestAnimationFrame(e.bind(this))};this.has("start")?this.trigger("start",t.bind(this)):t.call(this)}},i}(i);t.Dial=s;var r=function(t){function i(e,i){t.call(this),this.config={size:20,percent:50,variable:!0},this._state="load",this._touch=!1,this._request=!1,this.canvas=e,this.ctx=e.getContext("2d"),this.config=n["extends"]({},this.config,i),this._state="init",this._init(),this.canvas.addEventListener("ontouchstart"in document?"touchstart":"mousedown",this._onTouchStart.bind(this),!1),this.canvas.addEventListener("ontouchmove"in document?"touchmove":"mousemove",this._onTouchMove.bind(this),!1),document.addEventListener("ontouchend"in document?"touchend":"mouseup",this._onTouchEnd.bind(this)),window.addEventListener("onorientationchange"in document?"orientationchange":"resize",this._onResize.bind(this))}return e(i,t),i.prototype.setResult=function(t){this.canvas.style.backgroundImage="url("+t+")"},i.prototype.draw=function(){"end"!=this._state&&(this.ctx.clearRect(0,0,this.width,this.height),this._state="end",this.trigger("end"))},i.prototype.reset=function(){this._state="init",this._request=!1,this._touch=!1,this.canvas.style.backgroundImage=null,this._init(),this.trigger("reset")},i.prototype._init=function(){this._setCanvasSize(),this._getCanvasOffset(),this.ctx.closePath(),this.ctx.globalCompositeOperation="source-over",this.ctx.fillStyle="gray",this.ctx.fillRect(0,0,this.width,this.height),this.ctx.globalCompositeOperation="destination-out"},i.prototype._scratchPercent=function(){for(var t=0,e=this.ctx.getImageData(0,0,this.width,this.height),n=0,i=e.data.length;i>n;n+=4)0===e.data[n]&&0===e.data[n+1]&&0===e.data[n+2]&&0===e.data[n+3]&&t++;return t/(this.width*this.height)*100},i.prototype._setCanvasSize=function(){this.width=this.canvas.clientWidth,this.height=this.canvas.clientHeight,this.canvas.width=this.width,this.canvas.height=this.height},i.prototype._getCanvasOffset=function(){var t=this.canvas.getBoundingClientRect(),e=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop,n=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,i=document.documentElement.clientTop||document.body.clientTop||0,o=document.documentElement.clientLeft||document.body.clientLeft||0;this.offsetX=Math.round(t.left+n-o),this.offsetY=Math.round(t.top+e-i)},i.prototype._getEventXY=function(t){return t=t.changedTouches?t.changedTouches[0]:t,{x:t.pageX-this.offsetX,y:t.pageY-this.offsetY}},i.prototype._onTouchStart=function(t){if(t.preventDefault(),"end"!=this._state){var e=function(t){var e=this._getEventXY(t);this._state="start",this._touch=!0,this._request=!0,this.ctx.beginPath(),this.ctx.arc(e.x,e.y,this.config.size/2,0,2*Math.PI,!0),this.ctx.closePath(),this.ctx.fill(),this.ctx.beginPath(),this.ctx.lineWidth=this.config.size,this.ctx.moveTo(e.x,e.y)};this.has("start")&&!this._request?this.trigger("start",e.bind(this,t)):e.call(this,t)}},i.prototype._onTouchMove=function(t){if(t.preventDefault(),this._touch){var e=this._getEventXY(t);this.ctx.lineTo(e.x,e.y),this.ctx.stroke()}},i.prototype._onTouchEnd=function(t){if(this._touch){var e=this._getEventXY(t);this._touch=!1,this.ctx.closePath(),this.ctx.beginPath(),this.ctx.arc(e.x,e.y,this.config.size/2,0,2*Math.PI,!0),this.ctx.closePath(),this.ctx.fill(),this._scratchPercent()>=this.config.percent&&(this.ctx.clearRect(0,0,this.width,this.height),this._state="end",this.trigger("end"))}},i.prototype._onResize=function(){this._touch=!1,this.config.variable?"end"==this._state?this._setCanvasSize():this._init():this._getCanvasOffset()},i}(i);t.Scratch=r;var a=function(t){function i(e,i,s){t.call(this),this.config={timeout:300,timeDiff:6e3,variable:!0},this.rollerQueue=[],this.toggle=e,this.config=n["extends"]({},this.config,s);for(var r=0;rn;n++)e.rollerQueue[n].stop(t[n],n==i-1?function(){e.toggle.classList.remove("z-active"),e.trigger("end")}:null,n*e.config.timeout)},n-this._startTime>this.config.timeDiff?0:this.config.timeDiff-(n-this._startTime))},i.prototype.reset=function(){this.toggle.classList.remove("z-active");for(var t=0,e=this.rollerQueue.length;e>t;t++)this.rollerQueue[t].reset();this.trigger("reset")},i.prototype.draw=function(){if(!this.toggle.classList.contains("z-active")){var t=function(){this.toggle.classList.add("z-active");for(var t=0,e=this.rollerQueue.length;e>t;t++)this.rollerQueue[t].start(t*this.config.timeout)};this._startTime=(new Date).getTime(),this.has("start")?this.trigger("start",t.bind(this)):t.call(this)}},i}(i);t.Tiger=a}(t||(t={})),t}),t.directive("uiLotteryScratch",["$timeout","Lottery","LotteryRequest","lotteryState","lotteryConfig",function(t,e,n,i,o){return{restrict:"A",scope:{lottery:"=",onReady:"&",onResult:"&"},controller:["$scope",function(t){t.lottery={state:-1,result:null,config:null,start:angular.noop,reset:angular.noop}}],link:function(s,r,a){var c=o.timeout||500,u=new n(o.request),l=function(){var n=new e.Scratch(r[0].querySelector("canvas"),o.game||{});n.on("start",function(t){t(),u.post({success:function(t){n.setResult(t.web_des),s.lottery.result=t},error:function(t){n.reset(),alert(t,"z-error")}})}).on("end",function(){t(function(){s.lottery.state=3,s.onResult({result:s.lottery.result})},c)}).on("reset",function(){s.lottery.result=null,s.lottery.state=0}),s.lottery.start=function(){i(s.lottery.config?s.lottery.config.state:-1,function(){s.lottery.state=0==s.lottery.state?1:s.lottery.state})},s.lottery.reset=function(){n.reset(),s.lottery.state=1}};u.get({success:function(e){s.lottery.state=0,s.lottery.config=e,s.onReady({config:e}),t(l,50)},error:function(t){alert(t,"z-error")}})}}}]),t.directive("uiLotteryDial",["$timeout","Lottery","LotteryRequest","lotteryState","lotteryConfig",function(t,e,n,i,o){return{restrict:"A",scope:{lottery:"=",onReady:"&",onResult:"&"},template:'
',controller:["$scope",function(t){t.lottery={result:null,config:null,start:angular.noop,dialBackground:{},pointerBackground:{}}}],link:function(s,r,a){var c=new n(o.request),u=function(){var t=new e.Dial(r[0].querySelector(".pointer"),o.game||{});t.on("start",function(e){e(),c.post({success:function(e){t.setResult(e.sectors_number),s.lottery.result=e},error:function(e){t.reset(),alert(e,"z-error")}})}).on("end",function(){s.onResult({result:s.lottery.result})}).on("reset",function(){s.lottery.result=null}),s.lottery.start=function(){i(s.lottery.config?s.lottery.config.state:-1,t.draw.bind(t))}};c.get({success:function(e){s.lottery.config=e,s.lottery.dialBackground={"background-image":"url("+e.back_web_des+")"},s.lottery.pointerBackground={"background-image":"url("+e.btn_web_des+")"},s.onReady({config:e}),t(u,50)},error:function(t){alert(t,"z-error")}})}}}]),t.directive("uiLotteryTiger",["$timeout","Lottery","LotteryRequest","lotteryState","lotteryConfig",function(t,e,n,i,o){return{restrict:"A",scope:{lottery:"=",onReady:"&",onResult:"&"},template:'
',controller:["$scope",function(t){t.lottery={result:null,config:null,start:angular.noop,backBackground:{},btnBackground:{}}}],link:function(s,r,a){o.rankCount=o.rankCount||3,s.ranks=[];for(var c=0;c + + + + + + + + + 大转盘 + + + + +
+
+
+
【摇奖机规则】
+
+
【奖品兑换】
+
+
+
+ + + + + diff --git a/examples/ng-scratch.html b/examples/ng-scratch.html new file mode 100644 index 0000000..bc604e0 --- /dev/null +++ b/examples/ng-scratch.html @@ -0,0 +1,66 @@ + + + + + + + + + + 刮刮卡 + + + + +
+
+ +
+ + + +
+
+
+
【摇奖规则】
+
+
【奖品兑换】
+
+
+
+ + + + + diff --git a/examples/ng-tiger.html b/examples/ng-tiger.html new file mode 100644 index 0000000..cd76d40 --- /dev/null +++ b/examples/ng-tiger.html @@ -0,0 +1,58 @@ + + + + + + + + + + 老虎机 + + + + +
+
+
+
【摇奖规则】
+
+
【奖品兑换】
+
+
+
+ + + + + diff --git a/examples/scss/style.scss b/examples/scss/style.scss new file mode 100644 index 0000000..11564dc --- /dev/null +++ b/examples/scss/style.scss @@ -0,0 +1,87 @@ +@import "../../bower_components/top-webapp/scss/mixins"; +@import "../../bower_components/top-webapp/scss/base"; + +.m-ui-dial{position: relative;width: 499px;height: 499px;margin: 0 auto;background: url("../images/dial_bg.png") no-repeat center;background-size: 100%;} +.m-ui-dial .pointer{margin-top: -139px !important;background: url("../images/dial_pointer.png") no-repeat center;background-size: 100%; + @include box-center(150px, 238px); + @include transform-origin(75px 139px); +} +.m-ui-dial .btn{position: absolute;top: 64px;left: 0;display: block;width: 150px;height: 150px; + @include border-radius(75px); +} + +.m-ui-scratch{display: block;width: 300px;height: 172.5px;margin: 20px auto;background: no-repeat center;background-size: 100%;} + +.m-ui-button{display: block;width: 160px;height: 32px;margin: 0 auto;text-align: center;line-height: 32px;font-size: 12px;color: #fff;background-color: #f94804;cursor: pointer; + @include border-radius(5px); +} + +.m-ui-tiger{position: relative;width: 640px;height: 432px;margin: 20px auto;background: url("../images/tiger_bg.png") no-repeat;} +.m-ui-tiger .toggle{position: absolute;top: 306px;left: 119px;display: block;width: 404px;height: 50px;} +.m-ui-tiger .item{position: absolute;top: 77px;left: 139px;display: block;width: 110px;height: 135px;overflow: hidden;} +.m-ui-tiger .item:nth-child(2){left: 265px;} +.m-ui-tiger .item:nth-child(3){left: 391px;} +.m-ui-tiger .roller{position: relative;} +.m-ui-tiger .roller li{width: 110px;height: 135px;overflow: hidden;} +.m-ui-tiger .roller li:last-child{position: absolute;top: 100%;left: 0;} +.m-ui-tiger .roller img{display: block;width: 110px;height: 135px;} +.m-ui-tiger .roller.fx-roll{ + @include css-prefix(filter, blur(3px)); + @include animation(fx-roll .5s 0s infinite linear); +} +.m-ui-tiger .roller.fx-bounce{@include css-prefix(animation-duration, .3s);} + +.m-lottery-scratch{position: relative;width: 16rem;min-height: 100%;margin: 0 auto;padding-top: 9rem;background: url("../images/scratch_page_bg.jpg") no-repeat #ff5e01;background-size: 100% auto;} +.m-lottery-scratch .game{position: relative;display: block;width: 10rem;margin: 0 auto;height: 5.75rem;} +.m-lottery-scratch .game canvas{position: absolute;top: 0;left: 0;display: block;width: 100%;height: 100%;background-size: 100% 100%;} +.m-lottery-scratch .game button{display: block;width: 5rem;height: 1.5rem;margin: 0 auto;text-align: center;line-height: 1.4rem;font-size: 0.7rem;color: #fff;background-color: #ff5e01;border: 0 none;cursor: pointer; + @include border-radius(0.3rem); +} +.m-lottery-scratch .game button.z-dis{background-color: #bcbcbc;} +.m-lottery-scratch .game .ceiling{position: absolute;top: 0;left: 0;z-index: 3;width: 100%;height: 4rem;padding: 0.5rem 0 1.25rem;background: url("../images/scratch_ceiling.jpg") no-repeat;background-size: 100% 100%;overflow: hidden;} +.m-lottery-scratch .game .ceiling .tip{display: block;height: 2.5rem;line-height: 2.5rem;text-align: center;font-size: 0.8rem;color: #ff5e01;overflow: hidden;} +.m-lottery-scratch .des{margin-top: 2.35rem;padding: 0 1.1rem 0.5rem;line-height: 1.15rem;font-size: 0.6rem;color: #fff;} +.m-lottery-scratch .des dt{line-height: 1.2rem;font-size: 0.7rem;font-weight: 700;} + +.m-lottery-dial{position: relative;width: 16rem;min-height: 100%;margin: 0 auto;padding-top: 7rem;background: url("../images/dial_page_bg.jpg") no-repeat #f94804;background-size: 100% auto;} +.m-lottery-dial .game-dial{position: relative;width: 12.5rem;height: 12.5rem;margin: 0 auto;} +.m-lottery-dial .game-dial .dial{width: 100%;height: 100%;background-size: 100% auto;} +.m-lottery-dial .game-dial .pointer{position: absolute;top: 50%;left: 50%;width: 3.75rem;height: 5.95rem;margin: -3.4rem 0 0 -1.875rem;background-size: 100% auto; + @include transform-origin(1.875rem 3.4rem); +} +.m-lottery-dial .game-dial .pointer span{position: absolute;top: 1.6rem;left: 0;display: block;width: 3.75rem;height: 3.75rem;cursor: pointer;} +.m-lottery-dial .des{margin-top: 4.2rem;padding: 0 1.1rem 0.5rem;line-height: 1.15rem;font-size: 0.6rem;color: #fff;} +.m-lottery-dial .des dt{line-height: 1.2rem;font-size: 0.7rem;font-weight: 700;} + +.m-lottery-tiger{position: relative;width: 16rem;min-height: 100%;margin: 0 auto;padding-top: 5.5rem;background: url("../images/tiger_page_bg.jpg") no-repeat #ffeec6;background-size: 100% auto;} +.m-lottery-tiger .game{position: relative;} +.m-lottery-tiger .game .back{width: 16rem;height: 10.8rem;background-size: 100%;background-repeat: no-repeat;} +.m-lottery-tiger .game .item{position: absolute;top: 1.925rem;width: 2.75rem;height: 3.375rem;overflow: hidden;} +.m-lottery-tiger .game .item:nth-child(1){left: 3.475rem;} +.m-lottery-tiger .game .item:nth-child(2){left: 6.625rem;} +.m-lottery-tiger .game .item:nth-child(3){left: 9.775rem;} +.m-lottery-tiger .game .item .roller{position: relative; + @extend .fx-gpu; +} +.m-lottery-tiger .game .item .roller li.z-last{position: absolute;top: 100%;left: 0;} +.m-lottery-tiger .game .item .roller.fx-bounce{@include css-prefix(animation-duration, .3s);} +.m-lottery-tiger .game .item .roller.fx-roll{ + @include css-prefix(filter,blur(3px)); + @include animation(fx-roll .3s 0s infinite linear) +} +.m-lottery-tiger .game .item img{display: block;width: 2.75rem;height: 3.375rem;} +.m-lottery-tiger .game .btn{position: absolute;left: 50%;top: 7.65rem;width: 10.1rem;height: 1.25rem;margin-left: -5.05rem;background-size: 100%;background-repeat: no-repeat;} +.m-lottery-tiger .game .btn span{display: block;width: 100%;height: 100%;cursor: pointer;} +.m-lottery-tiger .des{padding: 0 1.1rem 0.5rem;line-height: 1.15rem;font-size: 0.6rem;color: #b26722;} +.m-lottery-tiger .des dt{line-height: 1.2rem;font-size: 0.7rem;font-weight: 700;} + +@include keyframes(fx-roll) { + 0% { + @include transform(translate3d(0, 0, 0)); + } + 100% { + @include transform(translate3d(0, -100%, 0)); + } +} + +@include bounce(); diff --git a/examples/template/lottery-dial.ejs b/examples/template/lottery-dial.ejs new file mode 100644 index 0000000..20834af --- /dev/null +++ b/examples/template/lottery-dial.ejs @@ -0,0 +1,4 @@ +
+
+ +
\ No newline at end of file diff --git a/examples/template/lottery-tiger.ejs b/examples/template/lottery-tiger.ejs new file mode 100644 index 0000000..338f9fa --- /dev/null +++ b/examples/template/lottery-tiger.ejs @@ -0,0 +1,12 @@ +
+
+
    +
  • + +
  • +
+
+
+
+ +
\ No newline at end of file diff --git a/examples/ui-dial.html b/examples/ui-dial.html new file mode 100644 index 0000000..e33cc67 --- /dev/null +++ b/examples/ui-dial.html @@ -0,0 +1,40 @@ + + + + + + + + + + 大转盘 + + + + +
+
+ +
+
+ + + + diff --git a/examples/ui-scratch.html b/examples/ui-scratch.html new file mode 100644 index 0000000..154f25f --- /dev/null +++ b/examples/ui-scratch.html @@ -0,0 +1,29 @@ + + + + + + + + + + 刮刮卡 + + + + + + + + + + diff --git a/examples/ui-tiger.html b/examples/ui-tiger.html new file mode 100644 index 0000000..558661b --- /dev/null +++ b/examples/ui-tiger.html @@ -0,0 +1,73 @@ + + + + + + + + + + 老虎机 + + + + +
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
+ + + + diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..118f351 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,45 @@ +var gulp = require('gulp'), + concat = require('gulp-concat'), + uglify = require('gulp-uglify'), + rename = require('gulp-rename'), + replace = require('gulp-template-replace'); + +var path = require('path'); + +gulp.task('release', function () { + //合并ui-lottery + gulp.src(['./src/js/intro.js', './src/js/ui-lottery.js', './src/js/outro.js']) + .pipe(concat('ui-lottery.js')) + .pipe(gulp.dest('./dist/')); + + //生成min文件 + gulp.src(['./src/js/intro.js', './src/js/ui-lottery.js', './src/js/outro.js']) + .pipe(concat('ui-lottery.min.js')) + .pipe(uglify()) + .pipe(gulp.dest('./dist/')); + + //处理ng-lottery.js + gulp.src('./examples/js/ng-lottery.js') + .pipe(replace([ + { + "rule": "templateUrl: 'template/lottery-dial.ejs'", + "file": path.join(__dirname, "./examples/template/lottery-dial.ejs"), + "fileRead": function (text) { + return "template: " + text; + } + }, + { + "rule": "templateUrl: 'template/lottery-tiger.ejs'", + "file": path.join(__dirname, "./examples/template/lottery-tiger.ejs"), + "fileRead": function (text) { + return "template: " + text; + } + } + ])) + .pipe(uglify()) + .pipe(rename('ng-lottery.min.js')) + .pipe(gulp.dest('./examples/js/')); +}); + +gulp.task('default', function () { +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..b53cb10 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "lottery", + "version": "1.0.0", + "description": "", + "main": "./dist/ui-lottery.js", + "directories": { + "example": "examples" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/TOP-Chao/lottery.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/TOP-Chao/lottery/issues" + }, + "homepage": "https://github.com/TOP-Chao/lottery#readme", + "devDependencies": { + "gulp": "^3.9.0", + "gulp-concat": "^2.6.0", + "gulp-rename": "^1.2.2", + "gulp-template-replace": "^0.0.1", + "gulp-uglify": "^1.4.2" + } +} diff --git a/src/js/intro.js b/src/js/intro.js new file mode 100644 index 0000000..6130253 --- /dev/null +++ b/src/js/intro.js @@ -0,0 +1 @@ +(function () { \ No newline at end of file diff --git a/src/js/outro.js b/src/js/outro.js new file mode 100644 index 0000000..eaed85f --- /dev/null +++ b/src/js/outro.js @@ -0,0 +1,10 @@ + if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { + define(function () { + return Lottery; + }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Lottery; + } else { + window.Lottery = Lottery; + } +})(); \ No newline at end of file diff --git a/src/ts/ui-lottery.js b/src/ts/ui-lottery.js new file mode 100644 index 0000000..b1ed235 --- /dev/null +++ b/src/ts/ui-lottery.js @@ -0,0 +1,414 @@ +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Lottery; +(function (Lottery) { + var Tool = (function () { + function Tool() { + } + Tool.extends = function (opt) { + var more = []; + for (var _i = 1; _i < arguments.length; _i++) { + more[_i - 1] = arguments[_i]; + } + opt = opt || {}; + for (var i = 1; i < arguments.length; i++) { + if (!!arguments[i]) { + for (var key in arguments[i]) { + if (arguments[i].hasOwnProperty(key)) { + opt[key] = arguments[i][key]; + } + } + } + } + return opt; + }; + Tool.camelCase = function (str) { + return str.replace(/-([a-z])/ig, function (all, letter) { + return letter.toUpperCase(); + }); + }; + Tool.css = function (element, property, value) { + if (element.style[property] === undefined) { + for (var i = 0; i < this._vendors.length; i++) { + property = this.camelCase(this._vendors[i] + '-' + property); + if (element.style[property] !== undefined) { + break; + } + } + } + element.style[property] = value; + return property; + }; + Tool._vendors = ['webkit', 'ms', 'moz', 'o']; + return Tool; + })(); + var Events = (function () { + function Events() { + this._queue = {}; + } + Events.prototype.on = function (key, callback) { + this._queue[key] = this._queue[key] || []; + this._queue[key].push(callback); + return this; + }; + Events.prototype.off = function (key, callback) { + if (!this._queue[key]) + return this; + var index = typeof (callback) == "undefined" ? -2 : this._queue[key].indexOf(callback); + if (index == -2) { + delete this._queue[key]; + } + else if (index != -1) { + this._queue[key].splice(index, 1); + } + if (this._queue[key] && this._queue[key].length == 0) + delete this._queue[key]; + return this; + }; + Events.prototype.has = function (key) { + return !!this._queue[key]; + }; + Events.prototype.trigger = function (key) { + var value = []; + for (var _i = 1; _i < arguments.length; _i++) { + value[_i - 1] = arguments[_i]; + } + if (!this._queue[key]) + return this; + for (var i = 0; i < this._queue[key].length; i++) { + this._queue[key][i].apply(null, value); + } + return this; + }; + return Events; + })(); + var TigerRoller = (function () { + function TigerRoller(elem, variable) { + this.index = 0; + this.state = 0; + this.elem = elem; + this.items = elem.children; + this.height = this.items[0].clientHeight; + //克隆第一个节点 用于制作无限滚动效果 + this.elem.appendChild(this.items[0].cloneNode(true)); + //如果大小是可变的就绑定resize事件 + if (variable) + window.addEventListener('onorientationchange' in document ? 'orientationchange' : 'resize', this._onResize.bind(this)); + } + TigerRoller.prototype.reset = function () { + this.elem.classList.remove('fx-roll'); + this.elem.style.marginTop = 0; + this.callback = null; + this.index = 0; + this.state = 0; + }; + TigerRoller.prototype.start = function (timeout) { + var _this = this; + if (timeout === void 0) { timeout = 0; } + this.state = 1; + setTimeout(function () { + if (_this.state != 1) + return; + _this.elem.style.marginTop = 0; + _this.elem.classList.add('fx-roll'); + }, timeout); + }; + TigerRoller.prototype.stop = function (index, callback, timeout) { + var _this = this; + if (timeout === void 0) { timeout = 0; } + this.callback = callback; + this.index = index; + setTimeout(function () { + if (_this.state != 1) + return; + _this.elem.style.marginTop = -index * _this.height + 'px'; + _this.elem.classList.remove('fx-roll'); + _this.elem.classList.add('fx-bounce'); + window['animationEnd'](_this.elem, function () { + _this.state = 0; + _this.elem.classList.remove('fx-bounce'); + if (_this.callback) + _this.callback.call(_this); + }, true); + }, timeout); + }; + TigerRoller.prototype._onResize = function () { + this.height = this.items[0].clientHeight; + if (!this.elem.classList.contains('fx-roll')) + this.elem.style.marginTop = -this.index * this.height + 'px'; + }; + return TigerRoller; + })(); + var Dial = (function (_super) { + __extends(Dial, _super); + function Dial(pointer, config) { + var _this = this; + _super.call(this); + this.config = { + speed: 30, + areaNumber: 8 //奖区数量 + }; + this._transform = 'transform'; + this._runAngle = 0; + this._targetAngle = -1; + this.pointer = pointer; + this.config = Tool.extends({}, this.config, config); + //初始化样式设定 + this._transform = Tool.css(this.pointer, this._transform, 'translate3d(0,0,0)'); + Tool.css(this.pointer, 'backfaceVisibility', 'hidden'); + Tool.css(this.pointer, 'perspective', '1000px'); + //事件注入 (当设置结果时) + this.on('__setResult', function (index) { + //得到中奖结果 index:中奖奖区下标 + var singleAngle = 360 / _this.config.areaNumber, //单个奖区角度值 + endAngle = Math.ceil((Math.random() * singleAngle) + (index * singleAngle)); //随机得出结果角度 + _this._runAngle = 0; + _this._targetAngle = endAngle + (Math.floor(Math.random() * 4) + 4) * 360; //随机旋转几圈再停止 + }); + } + Dial.prototype.setResult = function (index) { + this.trigger('__setResult', index); + }; + Dial.prototype.reset = function (event) { + if (event === void 0) { event = 'reset'; } + if (!this._raf) + return; + window.cancelAnimationFrame(this._raf); + this._raf = null; + this._runAngle = 0; + this._targetAngle = -1; + this.trigger(event); + if (event == 'reset') + Tool.css(this.pointer, this._transform, 'translate3d(0,0,0) rotate(0deg)'); + }; + Dial.prototype.draw = function () { + if (this._raf) + return; + var _draw = function () { + var angle = 0; + var step = function () { + //如果没有设置结束点 就匀速不停旋转 + //如果设置了结束点 就减速到达结束点 + if (this._targetAngle == -1) { + this._runAngle += this.config.speed; + } + else { + angle = (this._targetAngle - this._runAngle) / this.config.speed; + angle = angle > this.config.speed ? this.config.speed : angle < 0.5 ? 0.5 : angle; + this._runAngle += angle; + this._runAngle = this._runAngle > this._targetAngle ? this._targetAngle : this._runAngle; + } + //指针旋转 + Tool.css(this.pointer, this._transform, 'translate3d(0,0,0) rotate(' + (this._runAngle % 360) + 'deg)'); + if (this._runAngle == this._targetAngle) { + this.reset('end'); + } + else { + this._raf = window.requestAnimationFrame(step.bind(this)); + } + }; + this._raf = window.requestAnimationFrame(step.bind(this)); + }; + this.has('start') ? this.trigger('start', _draw.bind(this)) : _draw.call(this); + }; + return Dial; + })(Events); + Lottery.Dial = Dial; + var Scratch = (function (_super) { + __extends(Scratch, _super); + function Scratch(canvas, config) { + _super.call(this); + this.config = { + size: 20, + percent: 50, + variable: true //canvas的大小是否是可变的 + }; + this._state = 'load'; + this._touch = false; + this._request = false; + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + this.config = Tool.extends({}, this.config, config); + //初始化 + this._state = 'init'; + this._init(); + //绑定事件 + this.canvas.addEventListener('ontouchstart' in document ? 'touchstart' : 'mousedown', this._onTouchStart.bind(this), false); + this.canvas.addEventListener('ontouchmove' in document ? 'touchmove' : 'mousemove', this._onTouchMove.bind(this), false); + document.addEventListener('ontouchend' in document ? 'touchend' : 'mouseup', this._onTouchEnd.bind(this)); + window.addEventListener('onorientationchange' in document ? 'orientationchange' : 'resize', this._onResize.bind(this)); + } + Scratch.prototype.setResult = function (url) { + this.canvas.style.backgroundImage = 'url(' + url + ')'; + }; + Scratch.prototype.draw = function () { + if (this._state == 'end') + return; + this.ctx.clearRect(0, 0, this.width, this.height); + this._state = 'end'; + this.trigger('end'); + }; + Scratch.prototype.reset = function () { + this._state = 'init'; + this._request = false; + this._touch = false; + this.canvas.style.backgroundImage = null; + this._init(); + this.trigger('reset'); + }; + Scratch.prototype._init = function () { + this._setCanvasSize(); + this._getCanvasOffset(); + this.ctx.closePath(); + this.ctx.globalCompositeOperation = 'source-over'; + this.ctx.fillStyle = 'gray'; + this.ctx.fillRect(0, 0, this.width, this.height); + this.ctx.globalCompositeOperation = 'destination-out'; + }; + Scratch.prototype._scratchPercent = function () { + var hits = 0, imageData = this.ctx.getImageData(0, 0, this.width, this.height); + for (var i = 0, ii = imageData.data.length; i < ii; i = i + 4) { + if (imageData.data[i] === 0 && imageData.data[i + 1] === 0 && imageData.data[i + 2] === 0 && imageData.data[i + 3] === 0) { + hits++; + } + } + return (hits / (this.width * this.height)) * 100; + }; + Scratch.prototype._setCanvasSize = function () { + this.width = this.canvas.clientWidth; + this.height = this.canvas.clientHeight; + this.canvas.width = this.width; + this.canvas.height = this.height; + }; + Scratch.prototype._getCanvasOffset = function () { + var box = this.canvas.getBoundingClientRect(); + var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; + var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft; + var clientTop = document.documentElement.clientTop || document.body.clientTop || 0; + var clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0; + this.offsetX = Math.round(box.left + scrollLeft - clientLeft); + this.offsetY = Math.round(box.top + scrollTop - clientTop); + }; + Scratch.prototype._getEventXY = function (e) { + e = e.changedTouches ? e.changedTouches[0] : e; + return { + x: e.pageX - this.offsetX, + y: e.pageY - this.offsetY + }; + }; + Scratch.prototype._onTouchStart = function (e) { + e.preventDefault(); + if (this._state == 'end') + return; + var _draw = function (e) { + var point = this._getEventXY(e); + this._state = 'start'; + this._touch = true; + this._request = true; + this.ctx.beginPath(); + this.ctx.arc(point.x, point.y, this.config.size / 2, 0, Math.PI * 2, true); + this.ctx.closePath(); + this.ctx.fill(); + this.ctx.beginPath(); + this.ctx.lineWidth = this.config.size; + this.ctx.moveTo(point.x, point.y); + }; + this.has('start') && !this._request ? this.trigger('start', _draw.bind(this, e)) : _draw.call(this, e); + }; + Scratch.prototype._onTouchMove = function (e) { + e.preventDefault(); + if (!this._touch) + return; + var point = this._getEventXY(e); + this.ctx.lineTo(point.x, point.y); + this.ctx.stroke(); + }; + Scratch.prototype._onTouchEnd = function (e) { + if (!this._touch) + return; + var point = this._getEventXY(e); + this._touch = false; + this.ctx.closePath(); + this.ctx.beginPath(); + this.ctx.arc(point.x, point.y, this.config.size / 2, 0, Math.PI * 2, true); + this.ctx.closePath(); + this.ctx.fill(); + if (this._scratchPercent() >= this.config.percent) { + this.ctx.clearRect(0, 0, this.width, this.height); + this._state = 'end'; + this.trigger('end'); + } + }; + Scratch.prototype._onResize = function () { + this._touch = false; + if (this.config.variable) { + if (this._state == 'end') { + this._setCanvasSize(); + } + else { + this._init(); + } + } + else { + this._getCanvasOffset(); + } + }; + return Scratch; + })(Events); + Lottery.Scratch = Scratch; + var Tiger = (function (_super) { + __extends(Tiger, _super); + function Tiger(toggle, roller, config) { + _super.call(this); + this.config = { + timeout: 300, + timeDiff: 6000, + variable: true //roller大小是否是可变的 + }; + this.rollerQueue = []; + this.toggle = toggle; + this.config = Tool.extends({}, this.config, config); + //初始化滚轴 + for (var i = 0; i < roller.length; i++) { + this.rollerQueue.push(new TigerRoller(roller[i], this.config.variable)); + } + } + Tiger.prototype.setResult = function (ret) { + var _this = this; + //保证动画执行时间 + var endTime = (new Date()).getTime(); + setTimeout(function () { + for (var i = 0, l = _this.rollerQueue.length; i < l; i++) { + _this.rollerQueue[i].stop(ret[i], (i == l - 1 ? function () { + _this.toggle.classList.remove('z-active'); + _this.trigger('end'); + } : null), i * _this.config.timeout); + } + }, endTime - this._startTime > this.config.timeDiff ? 0 : this.config.timeDiff - (endTime - this._startTime)); + }; + Tiger.prototype.reset = function () { + this.toggle.classList.remove('z-active'); + for (var i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].reset(); + } + this.trigger('reset'); + }; + Tiger.prototype.draw = function () { + if (this.toggle.classList.contains('z-active')) + return; + var _draw = function () { + this.toggle.classList.add('z-active'); + for (var i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].start(i * this.config.timeout); + } + }; + this._startTime = (new Date()).getTime(); + this.has('start') ? this.trigger('start', _draw.bind(this)) : _draw.call(this); + }; + return Tiger; + })(Events); + Lottery.Tiger = Tiger; +})(Lottery || (Lottery = {})); diff --git a/src/ts/ui-lottery.ts b/src/ts/ui-lottery.ts new file mode 100644 index 0000000..91329fd --- /dev/null +++ b/src/ts/ui-lottery.ts @@ -0,0 +1,442 @@ +module Lottery { + + class Tool { + static _vendors:string[] = ['webkit', 'ms', 'moz', 'o']; + + static extends(opt, ...more) { + opt = opt || {}; + for (let i = 1; i < arguments.length; i++) { + if (!!arguments[i]) { + for (var key in arguments[i]) { + if (arguments[i].hasOwnProperty(key)) { + opt[key] = arguments[i][key]; + } + } + } + } + return opt; + } + + static camelCase(str:string):string { + return str.replace(/-([a-z])/ig, function (all, letter) { + return letter.toUpperCase(); + }); + } + + static css(element, property:string, value:string):string { + if (element.style[property] === undefined) { + for (let i = 0; i < this._vendors.length; i++) { + property = this.camelCase(this._vendors[i] + '-' + property); + if (element.style[property] !== undefined) { + break; + } + } + } + element.style[property] = value; + return property; + } + + constructor() { + } + } + + class Events { + private _queue = {}; + + on(key:string, callback) { + this._queue[key] = this._queue[key] || []; + this._queue[key].push(callback); + return this; + } + + off(key:string, callback?) { + if (!this._queue[key]) return this; + let index = typeof (callback) == "undefined" ? -2 : this._queue[key].indexOf(callback); + if (index == -2) { + delete this._queue[key]; + } else if (index != -1) { + this._queue[key].splice(index, 1); + } + if (this._queue[key] && this._queue[key].length == 0) delete this._queue[key]; + return this; + } + + has(key) { + return !!this._queue[key]; + } + + trigger(key, ...value) { + if (!this._queue[key]) return this; + for (let i = 0; i < this._queue[key].length; i++) { + this._queue[key][i].apply(null, value); + } + return this; + } + } + + class TigerRoller { + private elem; + private items:any[]; + private height:number; + private callback; + private variable:boolean; + private index:number = 0; + private state:number = 0; + + constructor(elem, variable) { + this.elem = elem; + this.items = elem.children; + this.height = this.items[0].clientHeight; + + //克隆第一个节点 用于制作无限滚动效果 + this.elem.appendChild(this.items[0].cloneNode(true)); + + //如果大小是可变的就绑定resize事件 + if (variable) window.addEventListener('onorientationchange' in document ? 'orientationchange' : 'resize', this._onResize.bind(this)); + } + + public reset() { + this.elem.classList.remove('fx-roll'); + this.elem.style.marginTop = 0; + this.callback = null; + this.index = 0; + this.state = 0; + } + + public start(timeout:number = 0) { + this.state = 1; + setTimeout(() => { + if (this.state != 1) return; + this.elem.style.marginTop = 0; + this.elem.classList.add('fx-roll'); + }, timeout); + } + + public stop(index:number, callback, timeout:number = 0) { + this.callback = callback; + this.index = index; + setTimeout(()=> { + if (this.state != 1) return; + this.elem.style.marginTop = -index * this.height + 'px'; + this.elem.classList.remove('fx-roll'); + this.elem.classList.add('fx-bounce'); + window['animationEnd'](this.elem, ()=> { + this.state = 0; + this.elem.classList.remove('fx-bounce'); + if (this.callback) this.callback.call(this); + }, true); + }, timeout); + } + + private _onResize() { + this.height = this.items[0].clientHeight; + if (!this.elem.classList.contains('fx-roll')) this.elem.style.marginTop = -this.index * this.height + 'px'; + } + } + + interface Lottery extends Events { + setResult(ret:any):void; + reset():void; + draw():void; + } + + export class Dial extends Events implements Lottery { + private pointer; + private _raf; + private config = { + speed: 30, //每帧速度 + areaNumber: 8 //奖区数量 + }; + private _transform:string = 'transform'; + private _runAngle:number = 0; + private _targetAngle:number = -1; + + constructor(pointer, config?) { + super(); + this.pointer = pointer; + this.config = Tool.extends({}, this.config, config); + + //初始化样式设定 + this._transform = Tool.css(this.pointer, this._transform, 'translate3d(0,0,0)'); + Tool.css(this.pointer, 'backfaceVisibility', 'hidden'); + Tool.css(this.pointer, 'perspective', '1000px'); + + //事件注入 (当设置结果时) + this.on('__setResult', (index)=> { + //得到中奖结果 index:中奖奖区下标 + var singleAngle = 360 / this.config.areaNumber, //单个奖区角度值 + endAngle = Math.ceil((Math.random() * singleAngle) + (index * singleAngle)); //随机得出结果角度 + + this._runAngle = 0; + this._targetAngle = endAngle + (Math.floor(Math.random() * 4) + 4) * 360; //随机旋转几圈再停止 + }); + } + + public setResult(index:number):void { + this.trigger('__setResult', index); + } + + public reset(event:string = 'reset'):void { + if (!this._raf) return; + window.cancelAnimationFrame(this._raf); + this._raf = null; + this._runAngle = 0; + this._targetAngle = -1; + this.trigger(event); + if (event == 'reset') Tool.css(this.pointer, this._transform, 'translate3d(0,0,0) rotate(0deg)'); + } + + public draw():void { + if (this._raf) return; + var _draw = function () { + var angle = 0; + + var step = function () { + //如果没有设置结束点 就匀速不停旋转 + //如果设置了结束点 就减速到达结束点 + if (this._targetAngle == -1) { + this._runAngle += this.config.speed; + } else { + angle = (this._targetAngle - this._runAngle) / this.config.speed; + angle = angle > this.config.speed ? this.config.speed : angle < 0.5 ? 0.5 : angle; + this._runAngle += angle; + this._runAngle = this._runAngle > this._targetAngle ? this._targetAngle : this._runAngle; + } + //指针旋转 + Tool.css(this.pointer, this._transform, 'translate3d(0,0,0) rotate(' + (this._runAngle % 360) + 'deg)'); + + if (this._runAngle == this._targetAngle) { + this.reset('end'); + } else { + this._raf = window.requestAnimationFrame(step.bind(this)); + } + }; + + this._raf = window.requestAnimationFrame(step.bind(this)) + }; + this.has('start') ? this.trigger('start', _draw.bind(this)) : _draw.call(this); + } + } + + export class Scratch extends Events implements Lottery { + private canvas; + private ctx; + private width:number; + private height:number; + private offsetX:number; + private offsetY:number; + private config = { + size: 20, //滑动区域大小 + percent: 50, //激活百分比到谋个值 就全显示 + variable: true //canvas的大小是否是可变的 + }; + private _state:string = 'load'; + private _touch:boolean = false; + private _request:boolean = false; + + constructor(canvas, config) { + super(); + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + this.config = Tool.extends({}, this.config, config); + + //初始化 + this._state = 'init'; + this._init(); + + //绑定事件 + this.canvas.addEventListener('ontouchstart' in document ? 'touchstart' : 'mousedown', this._onTouchStart.bind(this), false); + this.canvas.addEventListener('ontouchmove' in document ? 'touchmove' : 'mousemove', this._onTouchMove.bind(this), false); + document.addEventListener('ontouchend' in document ? 'touchend' : 'mouseup', this._onTouchEnd.bind(this)); + window.addEventListener('onorientationchange' in document ? 'orientationchange' : 'resize', this._onResize.bind(this)); + } + + public setResult(url):void { + this.canvas.style.backgroundImage = 'url(' + url + ')'; + } + + public draw():void { + if (this._state == 'end') return; + this.ctx.clearRect(0, 0, this.width, this.height); + this._state = 'end'; + this.trigger('end'); + } + + public reset():void { + this._state = 'init'; + this._request = false; + this._touch = false; + this.canvas.style.backgroundImage = null; + this._init(); + this.trigger('reset'); + } + + private _init():void { + this._setCanvasSize(); + this._getCanvasOffset(); + + this.ctx.closePath(); + this.ctx.globalCompositeOperation = 'source-over'; + this.ctx.fillStyle = 'gray'; + this.ctx.fillRect(0, 0, this.width, this.height); + this.ctx.globalCompositeOperation = 'destination-out'; + } + + private _scratchPercent():number { + var hits = 0, + imageData = this.ctx.getImageData(0, 0, this.width, this.height); + + for (let i = 0, ii = imageData.data.length; i < ii; i = i + 4) { + if (imageData.data[i] === 0 && imageData.data[i + 1] === 0 && imageData.data[i + 2] === 0 && imageData.data[i + 3] === 0) { + hits++; + } + } + + return (hits / (this.width * this.height)) * 100; + } + + private _setCanvasSize():void { + this.width = this.canvas.clientWidth; + this.height = this.canvas.clientHeight; + this.canvas.width = this.width; + this.canvas.height = this.height; + } + + private _getCanvasOffset():void { + var box = this.canvas.getBoundingClientRect(); + + var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; + var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft; + + var clientTop = document.documentElement.clientTop || document.body.clientTop || 0; + var clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0; + + this.offsetX = Math.round(box.left + scrollLeft - clientLeft); + this.offsetY = Math.round(box.top + scrollTop - clientTop); + } + + private _getEventXY(e) { + e = e.changedTouches ? e.changedTouches[0] : e; + return { + x: e.pageX - this.offsetX, + y: e.pageY - this.offsetY + } + } + + private _onTouchStart(e):void { + e.preventDefault(); + if (this._state == 'end') return; + var _draw = function (e) { + var point = this._getEventXY(e); + this._state = 'start'; + this._touch = true; + this._request = true; + + this.ctx.beginPath(); + this.ctx.arc(point.x, point.y, this.config.size / 2, 0, Math.PI * 2, true); + this.ctx.closePath(); + this.ctx.fill(); + + this.ctx.beginPath(); + this.ctx.lineWidth = this.config.size; + this.ctx.moveTo(point.x, point.y); + }; + + this.has('start') && !this._request ? this.trigger('start', _draw.bind(this, e)) : _draw.call(this, e); + } + + private _onTouchMove(e):void { + e.preventDefault(); + if (!this._touch) return; + var point = this._getEventXY(e); + this.ctx.lineTo(point.x, point.y); + this.ctx.stroke(); + } + + private _onTouchEnd(e) { + if (!this._touch) return; + var point = this._getEventXY(e); + this._touch = false; + + this.ctx.closePath(); + this.ctx.beginPath(); + this.ctx.arc(point.x, point.y, this.config.size / 2, 0, Math.PI * 2, true); + this.ctx.closePath(); + this.ctx.fill(); + + if (this._scratchPercent() >= this.config.percent) { + this.ctx.clearRect(0, 0, this.width, this.height); + this._state = 'end'; + this.trigger('end'); + } + } + + private _onResize():void { + this._touch = false; + if (this.config.variable) { + if (this._state == 'end') { + this._setCanvasSize(); + } else { + this._init() + } + } else { + this._getCanvasOffset(); + } + } + } + + export class Tiger extends Events implements Lottery { + private toggle; + private config = { + timeout: 300, //每个roller间动画间隔 + timeDiff: 6000, //动画执行最少时间 + variable: true //roller大小是否是可变的 + }; + private rollerQueue:any[] = []; + private _startTime:number; + + constructor(toggle, roller, config) { + super(); + this.toggle = toggle; + this.config = Tool.extends({}, this.config, config); + + //初始化滚轴 + for (let i = 0; i < roller.length; i++) { + this.rollerQueue.push(new TigerRoller(roller[i], this.config.variable)); + } + } + + setResult(ret):void { + //保证动画执行时间 + var endTime = (new Date()).getTime(); + setTimeout(() => { + for (let i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].stop(ret[i], (i == l - 1 ? () => { + this.toggle.classList.remove('z-active'); + this.trigger('end'); + } : null), i * this.config.timeout); + } + }, endTime - this._startTime > this.config.timeDiff ? 0 : this.config.timeDiff - (endTime - this._startTime)); + } + + reset():void { + this.toggle.classList.remove('z-active'); + for (let i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].reset(); + } + this.trigger('reset'); + } + + draw():void { + if (this.toggle.classList.contains('z-active')) return; + var _draw = function () { + this.toggle.classList.add('z-active'); + for (let i = 0, l = this.rollerQueue.length; i < l; i++) { + this.rollerQueue[i].start(i * this.config.timeout); + } + }; + this._startTime = (new Date()).getTime(); + this.has('start') ? this.trigger('start', _draw.bind(this)) : _draw.call(this); + } + } +} \ No newline at end of file