├── LICENSE ├── README.md ├── index.html └── static ├── css └── index.css ├── img ├── back.jpg └── earth.png ├── js ├── MusicVisualizer.js ├── breakImg.js └── makeSky.js └── res └── Routine.mp3 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 陈二狗不理包子脸 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 个人简历DEMO 2 | 3 | https://senschen.github.io/SensWorld/ 4 | 5 | ## 这是一个还没有构思完全就开始编码的作品,所以可以看到代码结构比较乱。 6 | - 比如一开始不打算使用jquery,但后来用上了我的一个依赖jquery的插件(图片破碎效果),于是还是开始用jquery; 7 | - 比如一开始想兼容IE10和部分低版本chrome内核的国产浏览器,但要做兼容的地方太多又无暇做得那么完美; 8 | - 比如很多想法都是临时想出来再加到代码里,比如每一步管理起来太乱,后面就又突然莫名其妙的用上了promise,而前面又用setTimeout的方式拼凑起来。 9 | 10 | 总之,是一个金玉其外败絮其中的作品吧- - 几乎包含了我会的所有ui方向的技术了。值得说明的是,按钮的按下特效、带尾巴的流星的绘制、音乐数据化的代码参考了其他优秀作品,自己加以重构利用,并非纯原创。谢侵删。 11 | 12 | ## 功能列表(按出现顺序) 13 | 1.keyframe实现的打字效果 14 | 2.判断是否加载完音乐,给出不同的提示 15 | 3.css制作的按钮ui/出现动画/点击动画 16 | 4.背景渐变色+背景位移动画实现的霓虹灯效果的文字 17 | 5.点击按钮强制全屏,并写入cookie,一天内不出现打字效果 18 | 6.canvas绘制的星空+旋转的流星 19 | 7.滚轮事件控制星空中移动的速度以及流星旋转速度 20 | 8.不断判断当前位移的距离,达到一定距离时出现地球 21 | 9.地球随瞬时音量的变化而缩放(这里音量的大小不是很准确,是取的所有声道的音量之和) 22 | 10.点击地球抖动动画 23 | 11.点击地球之后回到起点,执行破碎效果 24 | 12.黑屏,关闭鼠标指针,减慢音乐 25 | 13.定时改变页面html,实现代码的打字效果,同理实现css代码实时生效效果 26 | 14.定时器+公共动画实现简历一行一行飞入效果 27 | 15.***待实现的简历左右两个模块的视差滚动效果 28 | 29 | 2017-6-22 10:33:09 30 | 31 | 已经用vue重做了这个简历,感兴趣可在我的仓库里翻一下,代码重构之后顿时感觉世界清爽多了= = -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sens World 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 |
45 | 46 |
47 |
48 |
49 | 额,趁现在资源还在加载 50 | 我先给你讲一个冷笑话 51 | 有一个叫程思序的人 52 | 整天思程序 53 | ...... 54 | 好尴尬,我们来看看资源加载完没有 55 | 哇塞,居然没加载完! 56 | 哇塞,已经加载完了! 57 | 那别怪没音乐特效了~ 58 | 那我们就立刻开始吧! 59 | | 60 |
61 |
62 | 63 |
64 | 65 | 66 |

点击按钮后记得使用滚轮哟

67 |

68 | 代码地址1 69 |
70 | 代码地址2(vue版) 71 |

72 |
73 |
74 |
75 |
76 |
77 |
78 | 80 | 81 |
82 |
83 |
84 |
85 |
86 | 87 |
88 |
89 |
90 |
91 | 92 |
93 |
94 |
 95 |     
96 |
97 |
98 |

  我叫XXX,15年毕业于重庆理工大学计算机科学与技术学院

99 |

  15年年初开始在猪八戒网络有限公司品牌市场相关部门,从事前端开发工作

100 |

  擅长页面重构、动画(css、js、canvas)

101 |

  在公司主要做品牌、活动相关项目的开发以及外投用的下单页面的开发

102 |

  平时工作用到的框架技术FIS-Plus、Vue及相关技术栈、Nodejs

103 |

  部分参与的项目:

104 | 152 |
153 |
154 |
155 | 156 | 157 | 158 | 159 | 160 | 443 | 444 | 445 | -------------------------------------------------------------------------------- /static/css/index.css: -------------------------------------------------------------------------------- 1 | html,body{ 2 | margin: 0; 3 | padding: 0; 4 | min-height: 100vh; 5 | font-size: 14px; 6 | font-family: "Microsoft YaHei", sans-serif; 7 | background-color: #000; 8 | } 9 | body.nocursor{ 10 | cursor: none!important; 11 | } 12 | ::-webkit-scrollbar{ 13 | width: 8px; 14 | height: 8px; 15 | background-color: #2F73BC; 16 | border-radius: 10px; 17 | } 18 | ::-webkit-scrollbar-track{ 19 | border-radius: 10px; 20 | background-color: #6E8EB7; 21 | } 22 | ::-webkit-scrollbar-thumb{ 23 | border-radius: 10px; 24 | background-color: #0D4690; 25 | } 26 | 27 | .welcome-block,.sky-block{ 28 | user-select: none; 29 | -webkit-user-select: none; 30 | -moz-user-select: none; 31 | } 32 | .hide{ 33 | display: none; 34 | } 35 | img{ 36 | vertical-align: top; 37 | } 38 | p{ 39 | margin: .5em 0; 40 | } 41 | a{ 42 | color: #fff; 43 | text-decoration: none; 44 | } 45 | a:hover{ 46 | color: #ff6900; 47 | } 48 | a.ud{ 49 | border-bottom: 1px solid #fff; 50 | } 51 | a.img{ 52 | border-bottom: 1px dashed #fff; 53 | } 54 | a.img img{ 55 | display: none; 56 | max-width: 90%; 57 | } 58 | a.img:hover img{ 59 | display: inline; 60 | } 61 | .rel{ 62 | position: relative; 63 | } 64 | .preload-block img{ 65 | display: inline-block!important; 66 | width: 0!important; 67 | height: 0!important; 68 | visibility: hidden!important; 69 | line-height: 0!important; 70 | box-sizing: border-box!important; 71 | } 72 | 73 | .welcome-block{ 74 | position: fixed; 75 | width: 100%; 76 | height: 100%; 77 | top: 0; 78 | left: 0; 79 | z-index: 10; 80 | background: #DADCDF; 81 | transition: all 2s; 82 | } 83 | .welcome-block.fadeout{ 84 | opacity: 0; 85 | } 86 | .welcome-block-main{ 87 | position: absolute; 88 | top: 0; 89 | left: 0; 90 | width: 100%; 91 | height: 100%; 92 | color: #333; 93 | z-index: 10; 94 | text-align: center; 95 | } 96 | .welcome-block-main:after{ 97 | display: inline-block; 98 | height: 100%; 99 | content: ''; 100 | vertical-align: middle; 101 | } 102 | .welcome-box-center{ 103 | width: 320px; 104 | /*position: absolute;*/ 105 | /*top: 0;*/ 106 | /*left: 0;*/ 107 | /*right: 0;*/ 108 | /*bottom: 0;*/ 109 | /*margin: auto;*/ 110 | font-size: 0; 111 | display: inline-block; 112 | vertical-align: middle; 113 | text-align: left; 114 | } 115 | .welcome-box-center.die { 116 | transition: all 2s; 117 | transform: rotate(1800deg) scale(0,0); 118 | } 119 | .welcome-text{ 120 | display: inline-block; 121 | width: 0; 122 | overflow: hidden; 123 | vertical-align: top; 124 | font-size: 20px; 125 | white-space: nowrap; 126 | } 127 | .line1.play{ 128 | animation: lineShow1 2s forwards; 129 | animation-timing-function: steps(1,end); 130 | } 131 | .line2.play{ 132 | animation: lineShow2 1s forwards 2s; 133 | animation-timing-function: steps(10,end); 134 | } 135 | .line3.play{ 136 | animation: lineShow3 1s forwards 3.5s; 137 | animation-timing-function: steps(9,end); 138 | } 139 | .line4.play{ 140 | animation: lineShow4 .5s forwards 5s; 141 | animation-timing-function: steps(5,end); 142 | } 143 | .line5.play{ 144 | animation: lineShow5 1s forwards 6s; 145 | animation-timing-function: steps(6,end); 146 | } 147 | .line6.play{ 148 | animation: lineShow6 1s forwards 7s; 149 | animation-timing-function: steps(16,end); 150 | } 151 | .line7.play{ 152 | animation: lineShow7 1s forwards 8.5s; 153 | animation-timing-function: steps(10,end); 154 | } 155 | .line8.play{ 156 | animation: lineShow8 1s forwards 9.5s; 157 | animation-timing-function: steps(10,end); 158 | } 159 | 160 | @keyframes lineShow1 { 161 | 0%{ 162 | width: 0; 163 | } 164 | 10%{ 165 | width: 1em; 166 | } 167 | 20%{ 168 | width: 2em; 169 | } 170 | 60%{ 171 | width: 3em; 172 | } 173 | 65%{ 174 | width: 4em; 175 | } 176 | 70%{ 177 | width: 5em; 178 | } 179 | 75%{ 180 | width: 6em; 181 | } 182 | 80%{ 183 | width: 7em; 184 | } 185 | 85%{ 186 | width: 8em; 187 | } 188 | 90%{ 189 | width: 9em; 190 | } 191 | 95%{ 192 | width: 10em; 193 | } 194 | 99.99%{ 195 | width: 11em; 196 | } 197 | 100%{ 198 | width: 100%; 199 | } 200 | } 201 | @keyframes lineShow2 { 202 | 0%{ 203 | width: 0; 204 | } 205 | 99.99%{ 206 | width: 10em; 207 | } 208 | 100%{ 209 | width: 100%; 210 | } 211 | } 212 | @keyframes lineShow3 { 213 | 0%{ 214 | width: 0; 215 | } 216 | 99.99%{ 217 | width: 9em; 218 | } 219 | 100%{ 220 | width: 100%; 221 | } 222 | } 223 | @keyframes lineShow4 { 224 | 0%{ 225 | width: 0; 226 | } 227 | 99.99%{ 228 | width: 5em; 229 | } 230 | 100%{ 231 | width: 100%; 232 | } 233 | } 234 | @keyframes lineShow5 { 235 | 0%{ 236 | width: 0; 237 | } 238 | 99.99%{ 239 | width: 6em; 240 | } 241 | 100%{ 242 | width: 100%; 243 | } 244 | } 245 | @keyframes lineShow6 { 246 | 0%{ 247 | width: 0; 248 | } 249 | 99.99%{ 250 | width: 16em; 251 | } 252 | 100%{ 253 | width: 100%; 254 | } 255 | } 256 | @keyframes lineShow7 { 257 | 0%{ 258 | width: 0; 259 | } 260 | 99.99%{ 261 | width: 10em; 262 | } 263 | 100%{ 264 | width: 100%; 265 | } 266 | } 267 | @keyframes lineShow8 { 268 | 0%{ 269 | width: 0; 270 | } 271 | 99.99%{ 272 | width: 10em; 273 | } 274 | 100%{ 275 | width: 100%; 276 | } 277 | } 278 | 279 | .welcome-text-line{ 280 | animation: lineBling 1s infinite; 281 | animation-timing-function: steps(2,end); 282 | opacity: 1; 283 | font-size: 20px; 284 | } 285 | @keyframes lineBling { 286 | 0%{ 287 | opacity: 0; 288 | } 289 | 100%{ 290 | opacity: 1; 291 | } 292 | } 293 | .welcome-text-add{ 294 | position: absolute; 295 | width: 140px; 296 | top: 270px; 297 | text-decoration: underline; 298 | text-align: center; 299 | } 300 | .welcome-text-add a{ 301 | color: #ff7900; 302 | font-size: 16px; 303 | } 304 | 305 | .wrapper-block{ 306 | position: fixed; 307 | width: 100%; 308 | height: 100%; 309 | top: 0; 310 | left: 0; 311 | background: #060E1B; 312 | overflow: hidden; 313 | perspective: 1000px; 314 | perspective-origin: 50% 50%; 315 | } 316 | .wrapper-img{ 317 | position: absolute; 318 | top: 0; 319 | left: 0; 320 | width: 100%; 321 | min-height: 100%; 322 | vertical-align: top; 323 | z-index: 10; 324 | opacity: .5; 325 | } 326 | .wrapper-cvs{ 327 | position: absolute; 328 | top: 0; 329 | left: 0; 330 | z-index: 0; 331 | } 332 | .stage-block-back{ 333 | position: absolute; 334 | left: 0; 335 | top: 0; 336 | width: 100%; 337 | height: 100%; 338 | transform-style: preserve-3d; 339 | transform: translate3d(0,0,0); 340 | z-index: 20; 341 | } 342 | 343 | .wrapper-block-main{ 344 | position: fixed; 345 | width: 100%; 346 | height: 100%; 347 | top: 0; 348 | left: 0; 349 | perspective: 100000px; 350 | perspective-origin: 50% 50%; 351 | z-index: -1; 352 | transition: all 0.1s; 353 | } 354 | .stage-block-main{ 355 | position: absolute; 356 | left: 0; 357 | top: 0; 358 | width: 100%; 359 | height: 100%; 360 | transform-style: preserve-3d; 361 | transition: all 1s; 362 | transform: translate3d(0,0,-10000000px); 363 | } 364 | 365 | .stage-box-earth{ 366 | width: 408px; 367 | height: 408px; 368 | position: absolute; 369 | left: 50%; 370 | top: 50%; 371 | -webkit-transform: translate(-50%,-50%); 372 | -ms-transform: translate(-50%,-50%); 373 | transform:translate(-50%,-50%); 374 | border-radius: 50%; 375 | cursor: pointer; 376 | } 377 | .stage-box-earth.shake{ 378 | animation-name:anishake; 379 | animation-duration: .2s; 380 | animation-timing-function:linear; 381 | animation-iteration-count: 5; 382 | -webkit-animation-name:anishake; 383 | -webkit-animation-duration: .2s; 384 | -webkit-animation-timing-function:linear; 385 | -webkit-animation-iteration-count: 5 386 | } 387 | @keyframes anishake 388 | { 389 | 0% {transform: translate(-50%,-50%) rotate(0deg);} 390 | 25% {transform: translate(-70%,-50%) rotate(10deg);} 391 | 50% {transform: translate(-50%,-50%) rotate(0deg);} 392 | 75% {transform: translate(-30%,-50%) rotate(-10deg);} 393 | 100%{transform: translate(-50%,-50%) rotate(0deg);} 394 | } 395 | @-webkit-keyframes anishake 396 | { 397 | 0% {transform: translate(-50%,-50%) rotate(0deg);} 398 | 25% {transform: translate(-70%,-50%) rotate(10deg);} 399 | 50% {transform: translate(-50%,-50%) rotate(0deg);} 400 | 75% {transform: translate(-30%,-50%) rotate(-10deg);} 401 | 100%{transform: translate(-50%,-50%) rotate(0deg);} 402 | } 403 | 404 | 405 | .welcome-box-btn { 406 | display: inline-block; 407 | box-shadow: 408 | inset 0 0 35px 5px rgba(0, 0, 0, 0.25), 409 | inset 0 2px 1px 1px rgba(255, 255, 255, 0.9), 410 | inset 0 -2px 1px 0 rgba(0, 0, 0, 0.25); 411 | border-radius: 8px; 412 | background: #ccd0d4; 413 | position: relative; 414 | height: 140px; 415 | width: 140px; 416 | top: -1000px; 417 | transition: top 1s; 418 | } 419 | .welcome-box-btn.show{ 420 | top: 0; 421 | } 422 | 423 | .welcome-btn { 424 | -webkit-filter: blur(1px); 425 | -moz-filter: blur(1px); 426 | filter: blur(1px); 427 | transition: all 300ms ease; 428 | box-shadow: 429 | 0 15px 25px -4px rgba(0, 0, 0, 0.5), 430 | inset 0 -3px 4px -1px rgba(0, 0, 0, 0.2), 431 | 0 -10px 15px -1px rgba(255, 255, 255, 0.6), 432 | inset 0 3px 4px -1px rgba(255, 255, 255, 0.2), 433 | inset 0 0 5px 1px rgba(255, 255, 255, 0.8), 434 | inset 0 20px 30px 0 rgba(255, 255, 255, 0.2); 435 | border-radius: 50%; 436 | position: absolute; 437 | background: #ccd0d4; 438 | margin-left: -48.16px; 439 | margin-top: -48.16px; 440 | display: block; 441 | height: 96.32px; 442 | width: 96.32px; 443 | left: 50%; 444 | top: 50%; 445 | } 446 | .welcome-box-btn input { 447 | opacity: 0; 448 | position: absolute; 449 | cursor: pointer; 450 | z-index: 1; 451 | height: 100%; 452 | width: 100%; 453 | left: 0; 454 | top: 0; 455 | } 456 | .welcome-box-btn input:active ~ .welcome-btn { 457 | box-shadow: 458 | 0 15px 25px -4px rgba(0, 0, 0, 0.4), 459 | inset 0 -8px 30px 1px rgba(255, 255, 255, 0.9), 460 | 0 -10px 15px -1px rgba(255, 255, 255, 0.6), 461 | inset 0 8px 25px 0 rgba(0, 0, 0, 0.4), 462 | inset 0 0 10px 1px rgba(255, 255, 255, 0.6); 463 | } 464 | 465 | .welcome-box-btn input:focus ~ .welcome-btn { 466 | box-shadow: 467 | 0 15px 25px -4px rgba(0, 0, 0, 0.4), 468 | inset 0 -8px 25px -1px rgba(255, 255, 255, 0.9), 469 | 0 -10px 15px -1px rgba(255, 255, 255, 0.6), 470 | inset 0 8px 20px 0 rgba(0, 0, 0, 0.2), 471 | inset 0 0 5px 1px rgba(255, 255, 255, 0.6); 472 | } 473 | 474 | .welcome-text-tip{ 475 | position: absolute; 476 | white-space: nowrap; 477 | bottom: -120px; 478 | font-size: 30px; 479 | background-image: -webkit-linear-gradient(left, #147B96, #ff6900 25%, #147B96 50%, #ff6900 75%, #147B96); 480 | -webkit-background-clip: text; 481 | -webkit-text-fill-color: transparent; 482 | transform: translate(-50%,0); 483 | left: 50%; 484 | -webkit-background-size: 200% 100%; 485 | animation: masked 1s infinite linear; 486 | } 487 | @keyframes masked { 488 | 0% { 489 | background-position: 0 0; 490 | } 491 | 100% { 492 | background-position: -100% 0; 493 | } 494 | } 495 | 496 | .wrapper-box-link{ 497 | position: fixed; 498 | z-index: 100; 499 | left: 50%; 500 | } 501 | 502 | 503 | 504 | .intro-block{ 505 | overflow: hidden; 506 | perspective: 1000px; 507 | perspective-origin: 10px 400px; 508 | } 509 | .display-block{ 510 | color: #fff; 511 | } 512 | .intro-box{ 513 | color: #eee; 514 | font-size: 18px; 515 | line-height: 1.5; 516 | } 517 | .c-fff{ 518 | color: #fff; 519 | } 520 | .intro-text-desc{ 521 | font-size: 14px; 522 | color: #ececec; 523 | } 524 | .intro-list-task>li{ 525 | margin-bottom: 40px; 526 | } 527 | .intro-box-hide{ 528 | visibility: hidden; 529 | } 530 | .intro-box-hide.show{ 531 | animation: show 1s; 532 | animation-fill-mode: forwards; 533 | } 534 | @keyframes show { 535 | 0%{ 536 | visibility: visible; 537 | opacity: 0; 538 | transform: translate(100px,-20px); 539 | } 540 | 100%{ 541 | opacity: 1; 542 | visibility: visible; 543 | transform: translate(0,0); 544 | } 545 | } -------------------------------------------------------------------------------- /static/img/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senschen/SensWorld/cf740c5a279f3e1800e30d33b79ec3437970709e/static/img/back.jpg -------------------------------------------------------------------------------- /static/img/earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senschen/SensWorld/cf740c5a279f3e1800e30d33b79ec3437970709e/static/img/earth.png -------------------------------------------------------------------------------- /static/js/MusicVisualizer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sens on 2017/2/17. 3 | */ 4 | function MusicVisualizer(obj) { 5 | this.source = null; 6 | 7 | this.count = 0; 8 | 9 | this.analyser = this.audioCtx.createAnalyser(); 10 | this.size = obj.size; 11 | this.analyser.fftSize = this.size * 2; 12 | 13 | this.gainNode = this.audioCtx[this.audioCtx.createGain ? "createGain" : "createGainNode"](); 14 | this.gainNode.connect(this.audioCtx.destination); 15 | 16 | // this.filter = this.audioCtx.createBiquadFilter(); 17 | // this.filter.frequency.value = 800; 18 | // this.filter.connect(this.gainNode); 19 | 20 | this.analyser.connect(this.gainNode); 21 | 22 | this.xhr = new XMLHttpRequest(); 23 | 24 | this.visualizer = obj.visualizer; 25 | 26 | this.visualize(); 27 | } 28 | 29 | MusicVisualizer.prototype = { 30 | audioCtx: new (window.AudioContext || window.webkitAudioContext)(), 31 | load: function (url, fun) { 32 | var self = this; 33 | this.xhr.abort(); 34 | this.xhr.open("GET", url); 35 | this.xhr.responseType = "arraybuffer"; 36 | this.xhr.onload = function () { 37 | fun(self.xhr.response); 38 | }; 39 | this.xhr.send(); 40 | }, 41 | decode: function (arraybuffer, fun) { 42 | this.audioCtx.decodeAudioData(arraybuffer, function (buffer) { 43 | fun(buffer); 44 | }, function (err) { 45 | console.error(err); 46 | }); 47 | }, 48 | play: function (url,callback) { 49 | var self = this; 50 | var n = ++this.count; 51 | this.source && this.stop(); 52 | this.load(url, function (arraybuffer) { 53 | self.decode(arraybuffer, function (buffer) { 54 | if (n != self.count) return; 55 | var bs = self.audioCtx.createBufferSource(); 56 | bs.loop = true; 57 | bs.connect(self.analyser); 58 | bs.buffer = buffer; 59 | self.source = bs; 60 | callback && callback(); 61 | }) 62 | }); 63 | }, 64 | start: function () { 65 | this.source[this.source.start ? "start" : "noteOn"](0); 66 | }, 67 | stop: function () { 68 | this.source[this.source.stop ? "stop" : "noteOff"](0); 69 | }, 70 | changeVolume: function (percent) { 71 | this.gainNode.gain.value = percent * percent; 72 | }, 73 | visualize: function () { 74 | var arr = new Uint8Array(this.analyser.frequencyBinCount); 75 | 76 | requestAnimationFrame = window.requestAnimationFrame || 77 | window.webkitRequestAnimationFrame || 78 | window.mozRequestAnimationFrame; 79 | var self = this; 80 | 81 | function v() { 82 | self.analyser.getByteFrequencyData(arr); 83 | self.visualizer(arr); 84 | requestAnimationFrame(v); 85 | } 86 | 87 | requestAnimationFrame(v); 88 | }, 89 | slow: function () { 90 | var self = this; 91 | self.source.playbackRate.value = 0.5; 92 | } 93 | }; -------------------------------------------------------------------------------- /static/js/breakImg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sens on 2017/4/29. 3 | */ 4 | function MakeBreakImg(obj) { 5 | this.el = obj.el instanceof jQuery ? obj.el : $(obj.el); 6 | this.cont = obj.container || null; 7 | if(this.el.width() === 0 && !this.el.complete){ 8 | console.warn('this picture is not loaded now'); 9 | } 10 | else { 11 | this.wid = this.el.width(); 12 | this.hei = this.el.height(); 13 | } 14 | this.strStyle = obj.strStyle; 15 | this.itemSpl = obj.itemSpl || 5; 16 | this.itemWid = this.wid / this.itemSpl; 17 | this.itemSplSub = Math.ceil(this.hei / this.itemWid); 18 | this.backUrl = obj.url || this.el[0].src || this.attr('src'); 19 | this.arrItem = []; 20 | if(this.el){ 21 | this.init(); 22 | } 23 | } 24 | MakeBreakImg.prototype = { 25 | Constructor: MakeBreakImg, 26 | init : function () { 27 | var obj = this; 28 | var _$dom = null; 29 | if(!obj.cont){ 30 | _$dom = $('
'); 31 | _$dom.css({ 32 | width: obj.wid, 33 | height: obj.hei, 34 | display: obj.el.css('display') === 'inline' ? 'inline-block':'block', 35 | margin: obj.el.css('margin'), 36 | fontSize: 0, 37 | perspective: '10000px', 38 | perspectiveOrigin: '50% 50%' 39 | }); 40 | _$dom[0].style.cssText = _$dom[0].style.cssText + obj.strStyle; 41 | obj.cont = _$dom; 42 | } 43 | for (var j = 0; j < obj.itemSplSub; j++) { 44 | for (var i = 0; i < obj.itemSpl; i++) { 45 | _$dom = $('
'); 46 | _$dom.css({ 47 | width: obj.itemWid, 48 | height: obj.itemWid, 49 | display: 'inline-block', 50 | background: 'url(' + obj.backUrl + ') no-repeat ' + (-i * obj.itemWid) + 'px ' + (-j * obj.itemWid) + 'px', 51 | backgroundSize: this.wid + 'px ' + this.hei + 'px', 52 | transition: 'all 1s linear' 53 | }); 54 | obj.arrItem.push(_$dom); 55 | _$dom.appendTo(obj.cont); 56 | } 57 | } 58 | obj.el.replaceWith(obj.cont); 59 | }, 60 | 61 | makeBreak : function () { 62 | var obj = this; 63 | setTimeout(function () { 64 | $(obj.arrItem).each(function (idx, item) { 65 | item.css('transform','translate3d(0,0,' + (15000 - Math.random()*5000) + 'px)' 66 | + ' rotateX(' + (360 - Math.random()*720) + 'deg) ' 67 | + 'rotateY(' + (360 - Math.random()*720) + 'deg) ' 68 | + 'rotate(' + (360 - Math.random()*720) + 'deg) ' 69 | + 'skew(' + (45 - Math.random()*90) + 'deg) ' 70 | ) 71 | }); 72 | },0) 73 | }, 74 | makeResume: function () { 75 | var obj = this; 76 | $(obj.arrItem).each(function (idx, item) { 77 | item.css('transform',''); 78 | }); 79 | } 80 | }; -------------------------------------------------------------------------------- /static/js/makeSky.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sens on 2017/2/17. 3 | */ 4 | 5 | //封装一下事件绑定函数,其实没啥意义啊,反正IE9以下都GG。主要还是封装滚轮事件。 6 | var addEvent = (function(window, undefined) { //强行模仿jQuery源码 - - 7 | var _eventCompat = function(event) { 8 | var type = event.type; 9 | //火狐和chrome的delta居然值差那么远。。。 10 | if (type == 'DOMMouseScroll' || type == 'mousewheel') { 11 | event.delta = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; 12 | } 13 | if (event.srcElement && !event.target) { 14 | event.target = event.srcElement; 15 | } 16 | if (!event.preventDefault && event.returnValue !== undefined) { 17 | event.preventDefault = function() { 18 | event.returnValue = false; 19 | }; 20 | } 21 | 22 | return event; 23 | }; 24 | if (window.addEventListener) { 25 | return function(el, type, fn, capture) { 26 | if (type === "mousewheel" && document.mozHidden !== undefined) { 27 | type = "DOMMouseScroll"; 28 | } 29 | el.addEventListener(type, function(event) { 30 | fn.call(this, _eventCompat(event)); 31 | }, capture || false); 32 | } 33 | } else if (window.attachEvent) { 34 | return function(el, type, fn) { 35 | el.attachEvent("on" + type, function(event) { 36 | event = event || window.event; 37 | fn.call(el, _eventCompat(event)); 38 | }); 39 | } 40 | } 41 | return function() {}; 42 | })(window); 43 | 44 | var makeSky = (function (doc, window, addEvent) { 45 | //还是兼容一下国产浏览器用低版本chrome内核的情况吧。。。 46 | var REQ = window.requestAnimationFrame || 47 | window.webkitRequestAnimationFrame || 48 | window.mozRequestAnimationFrame || 49 | window.oRequestAnimationFrame || 50 | window.msRequestAnimationFrame; 51 | var cancelREQ = 52 | window.cancelRequestAnimationFrame 53 | || window.cancelAnimationFrame 54 | || window.webkitCancelAnimationFrame 55 | || window.webkitCancelRequestAnimationFrame 56 | || window.mozCancelRequestAnimationFrame 57 | || window.oCancelRequestAnimationFrame 58 | || window.msCancelRequestAnimationFrame; 59 | var tReq = null; 60 | var flagStop = false; 61 | 62 | var cvs = doc.getElementById('wrapper-cvs'); 63 | var ctx = cvs.getContext('2d'); 64 | 65 | //那么多获取浏览器可用宽高的写法,感觉还是这个最靠谱 66 | cvs.width = doc.documentElement.clientWidth; 67 | cvs.height = doc.documentElement.clientHeight; 68 | 69 | var stageBack = doc.getElementById('j-stage-block-back'), 70 | hue = 217, 71 | stars = [], 72 | count = 0, //其实叫index更合适。。用来保存当前生成到了第count个星星。重绘时清0再来。 73 | far = 0, 74 | maxStars = 500, 75 | canvas2 = document.createElement('canvas'), 76 | ctx2 = canvas2.getContext('2d'); 77 | //canvas2用来离屏画星星 78 | canvas2.width = 100; 79 | canvas2.height = 100; 80 | var half = canvas2.width / 2; 81 | var gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half); 82 | 83 | //缩放窗口触发重计算时会用上的flag 84 | var flagRestartStar = false; 85 | var flagRestartSky = false; 86 | 87 | //星星就是渐变的圆啦 88 | gradient2.addColorStop(0.025, '#CCC'); 89 | gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)'); 90 | gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)'); 91 | gradient2.addColorStop(1, 'transparent'); 92 | ctx2.fillStyle = gradient2; 93 | ctx2.beginPath(); 94 | ctx2.arc(half, half, half, 0, Math.PI * 2); 95 | ctx2.fill(); 96 | 97 | //这两个函数,生成星星的时候要用到 98 | function random(min, max) { 99 | if (arguments.length < 2) { 100 | max = min; 101 | min = 0; 102 | } 103 | if (min > max) { 104 | var hold = max; 105 | max = min; 106 | min = hold; 107 | } 108 | return Math.floor(Math.random() * (max - min + 1)) + min; 109 | } 110 | function maxOrbit(x, y) { 111 | var max = Math.max(x, y), 112 | diameter = Math.round(Math.sqrt(max * max + max * max)); 113 | return diameter / 2; 114 | } 115 | 116 | function Star(w,h) { 117 | this.orbitRadius = random(maxOrbit(w, h)); 118 | this.radius = random(60, this.orbitRadius) / 8; 119 | this.orbitX = w / 2; 120 | this.orbitY = h / 2; 121 | this.timePassed = random(0, maxStars); 122 | this.speed = random(this.orbitRadius) / 50000; 123 | this.alpha = random(2, 10) / 10; 124 | 125 | count++; 126 | stars[count] = this; 127 | } 128 | //每帧都要给一堆星星遍历执行这些位置和透明度计算 129 | Star.prototype.draw = function () { 130 | var x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX, 131 | y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY, 132 | twinkle = random(10); 133 | 134 | if (twinkle === 1 && this.alpha > 0) { 135 | this.alpha -= 0.05; 136 | } else if (twinkle === 2 && this.alpha < 1) { 137 | this.alpha += 0.05; 138 | } 139 | 140 | ctx.globalAlpha = this.alpha; 141 | ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius); 142 | if (mouseAniSpeed > minAniSpeed) { 143 | this.timePassed += this.speed * mouseAniSpeed * ratioAniSpeed; 144 | } 145 | else { 146 | this.timePassed += this.speed; 147 | } 148 | }; 149 | 150 | //用来判断是否正在滚动滚轮的flag以及计算动画速度的变量 151 | var isMouseWheel = false; 152 | var synMouseWheel; 153 | var minAniSpeed = 0.2; 154 | var ratioAniSpeed = 1 / minAniSpeed; 155 | var maxAniSpeed = 1; 156 | var mouseAniSpeed = minAniSpeed; 157 | 158 | //这个函数用来画旋转的星星,传入canvas的尺寸 159 | function animation(w,h) { 160 | if(flagRestartStar) { 161 | flagRestartStar = false; 162 | return; 163 | } 164 | //稍微保留一下之前的画面,形成星星的尾巴 165 | ctx.globalCompositeOperation = 'source-over'; 166 | ctx.globalAlpha = 0.3; 167 | 168 | ctx.fillRect(0, 0, w, h); 169 | 170 | ctx.globalCompositeOperation = 'lighter'; 171 | for (var i = 1, l = stars.length; i < l; i++) { 172 | stars[i].draw(); 173 | } 174 | 175 | REQ(function () { 176 | animation(w,h); 177 | }); 178 | } 179 | 180 | //用来节流的时间戳 181 | var timestampRunEvent = +new Date(); 182 | //触发play时候的回调函数,居然写成作一个全局变量,在init的时候赋值 183 | var onplayFunc = null; 184 | //这个函数控制离终点的距离 185 | function skyAnimation() { 186 | if(flagRestartSky) { 187 | flagRestartSky = false; 188 | return; 189 | } 190 | 191 | //这人是真的懒,懒得写window.cancelAnimationFrame来节省那一点性能了。。。要判断一辈子了。 192 | if (far < 800) { 193 | //正在滚动滚轮时达到最快速度 194 | if (isMouseWheel) { 195 | mouseAniSpeed = maxAniSpeed; 196 | far += maxAniSpeed; 197 | } 198 | //滚动停止时逐渐减速 199 | else { 200 | mouseAniSpeed = mouseAniSpeed > minAniSpeed ? mouseAniSpeed - 0.01 : minAniSpeed; 201 | far += mouseAniSpeed; 202 | } 203 | //改变画布在Z轴上的距离来制造接近是视觉,没有回流重绘应该性能还是可以的。。。吧? 204 | stageBack.style.transform = 'translate3d(0,0,' + far + 'px)'; 205 | 206 | //触发play事件时还是节流一下吧。。。另外,没有引入jquery就懒得搞成发布订阅模式了- -,直接执行咯。 207 | if(+new Date() - timestampRunEvent > 1000){ 208 | onplayFunc && onplayFunc(far); 209 | timestampRunEvent = +new Date(); 210 | } 211 | tReq = REQ(skyAnimation); 212 | } 213 | } 214 | 215 | function makeStars(w,h) { 216 | count = 0; 217 | for (var i = 0; i < maxStars; i++) { 218 | new Star(w,h); 219 | } 220 | } 221 | 222 | function init(onplay) { 223 | if (typeof onplay === 'function'){ 224 | onplayFunc = onplay; 225 | } 226 | addEvent(doc.body, "mousewheel", function (event) { 227 | if(flagStop) return; 228 | if (event.delta < 0 && far < 800) { 229 | clearTimeout(synMouseWheel); 230 | synMouseWheel = setTimeout(function () { 231 | isMouseWheel = false; 232 | mouseAniSpeed = maxAniSpeed; 233 | }, 500); 234 | if (isMouseWheel) { 235 | return; 236 | } 237 | isMouseWheel = true; 238 | } 239 | }); 240 | cvs.width = doc.documentElement.clientWidth; 241 | cvs.height = doc.documentElement.clientHeight; 242 | makeStars(cvs.width,cvs.height); 243 | REQ(function () { 244 | animation(cvs.width, cvs.height); 245 | skyAnimation(); 246 | }) 247 | } 248 | function restart() { 249 | flagRestartStar = true; 250 | flagRestartSky = true; 251 | cvs.width = doc.documentElement.clientWidth; 252 | cvs.height = doc.documentElement.clientHeight; 253 | makeStars(cvs.width, cvs.height); 254 | REQ(function () { 255 | animation(cvs.width, cvs.height); 256 | skyAnimation(); 257 | }) 258 | } 259 | function stop() { 260 | cancelREQ && cancelREQ(tReq); 261 | flagStop = true; 262 | } 263 | function backToStart(fun) { 264 | stageBack.style.transition = 'all 1s'; 265 | stop(); 266 | stageBack.style.transform = 'translate3d(0,0,0)'; 267 | setTimeout(fun,1000); 268 | } 269 | 270 | return { 271 | init: init, 272 | restart: restart, 273 | stop: stop, 274 | backToStart: backToStart 275 | }; 276 | 277 | })(document, window, addEvent); -------------------------------------------------------------------------------- /static/res/Routine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senschen/SensWorld/cf740c5a279f3e1800e30d33b79ec3437970709e/static/res/Routine.mp3 --------------------------------------------------------------------------------