├── .editorconfig ├── .gitignore ├── ReadMe.md ├── StarMap.js ├── build ├── StarMap.min.js ├── StarMap.min.js.map └── compress.json ├── demo ├── Repository.css └── Repository.html ├── index.html ├── package.json └── source ├── CanvasView.js ├── Color.js ├── Star.js └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://git-scm.com/docs/gitignore 2 | # https://help.github.com/articles/ignoring-files 3 | # Example .gitignore files: https://github.com/github/gitignore 4 | 5 | node_modules/* -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # 粒子/星图 交互式动画 2 | 3 | 4 | 5 | ## 【项目缘起】 6 | 7 | 公司同事为了适配 UI 设计图,在网上搜到 [@wangji5850](https://github.com/wangji5850) [原作](http://www.qdfuns.com/notes/26090/1fd69cab2d93ee4fc9c0b881a859abf5.html),用在一个业务系统(原型版)的登录页,效果甚佳。但内部试用后 UI 重做设计,就没最终采用。 8 | 9 | 后来发现两个同技术社区的朋友博客上都有这个动画,就想可以把 **自己在公司开发时重构的版本**分享出来,就建了这个代码仓库。 10 | 11 | 12 | 13 | ## 【参与开发】 14 | 15 | UNIX-Shell、Windows-CMD 通用脚本 —— 16 | 17 | ```Shell 18 | git clone https://github.com/TechQuery/StarMap.git 19 | 20 | npm install 21 | 22 | npm run build 23 | 24 | npm test 25 | ``` 26 | 27 | 28 | ## 【同类项目】 29 | 30 | - http://git.hust.cc/canvas-nest.js/ 31 | 32 | - https://github.com/hilongjw/Qarticles 33 | 34 | - http://vincentgarreau.com/particles.js/ -------------------------------------------------------------------------------- /StarMap.js: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by https://www.npmjs.com/package/amd-bundle 3 | // 4 | (function (factory) { 5 | 6 | if ((typeof define === 'function') && define.amd) 7 | define('StarMap', ['jquery', 'jQueryKit'], factory); 8 | else if (typeof module === 'object') 9 | module.exports = factory(require('jquery'), require('jQueryKit')); 10 | else 11 | this.StarMap = factory(this['jquery'], this['jQueryKit']); 12 | 13 | })(function (jquery, jQueryKit) { 14 | 15 | 16 | var Color = (function ($) { 17 | 18 | /* ----- RGB 颜色 ----- */ 19 | 20 | function Color(min) { 21 | 22 | min = min || 0; 23 | 24 | var _Self_ = this.constructor; 25 | 26 | this.red = _Self_.random( min ); 27 | this.green = _Self_.random( min ); 28 | this.blue = _Self_.random( min ); 29 | 30 | this.style = _Self_.getStyle(this.red, this.green, this.blue); 31 | } 32 | 33 | $.extend(Color, { 34 | random: function (min) { 35 | 36 | return Math.random() * 255 + min; 37 | }, 38 | getStyle: function (red, green, blue) { 39 | 40 | return 'rgba(' + [ 41 | Math.floor(red), Math.floor(green), Math.floor(blue), 0.8 42 | ].join(', ') + ')'; 43 | } 44 | }); 45 | 46 | return Color; 47 | 48 | })(jquery); 49 | 50 | 51 | var Star = (function ($, Color) { 52 | 53 | /* ----- 恒星点 ----- */ 54 | 55 | function Star(Max_X, Max_Y, iContext) { 56 | 57 | this.x = Math.random() * Max_X; 58 | this.y = Math.random() * Max_Y; 59 | 60 | this.vx = Math.random() - 0.5; 61 | this.vy = Math.random() - 0.5; 62 | 63 | this.radius = Math.random(); 64 | 65 | this.color = new Color(); 66 | 67 | this.context = iContext; 68 | } 69 | 70 | Star.mixValue = function (comp1, weight1, comp2, weight2) { 71 | 72 | return (comp1 * weight1 + comp2 * weight2) / (weight1 + weight2); 73 | }; 74 | 75 | $.extend(Star.prototype, { 76 | draw: function () { 77 | 78 | this.context.beginPath(); 79 | 80 | this.context.fillStyle = this.color.style; 81 | 82 | this.context.arc( 83 | this.x, this.y, this.radius, 0, Math.PI * 2, false 84 | ); 85 | this.context.fill(); 86 | }, 87 | mixColor: function (iOther) { 88 | 89 | return Color.getStyle( 90 | Star.mixValue( 91 | this.color.red, this.radius, iOther.color.red, iOther.radius 92 | ), 93 | Star.mixValue( 94 | this.color.green, this.radius, iOther.color.red, iOther.radius 95 | ), 96 | Star.mixValue( 97 | this.color.blue, this.radius, iOther.color.red, iOther.radius 98 | ) 99 | ); 100 | } 101 | }); 102 | 103 | return Star; 104 | 105 | })(jquery, Color); 106 | 107 | 108 | var CanvasView = (function ($) { 109 | 110 | /* ----- 星空图 ----- */ 111 | 112 | function CanvasView($_View) { 113 | 114 | this.$_View = $( $_View ); 115 | 116 | this.init(); 117 | 118 | $( self ).on('resize', $.throttle(this.init.bind( this ))); 119 | 120 | return this; 121 | } 122 | 123 | $.Class.extend(CanvasView, null, { 124 | init: function () { 125 | 126 | var $_View = this.$_View.offsetParent(); 127 | 128 | this.width = this.$_View[0].width = $_View.width(); 129 | this.height = this.$_View[0].height = $_View.height(); 130 | } 131 | }); 132 | 133 | return CanvasView; 134 | 135 | })(jquery); 136 | 137 | 138 | return (function ($, Color, Star, CanvasView) { 139 | 140 | function StarMap($_View, iMax, iDistance, iRadius) { 141 | 142 | $.extend(CanvasView.call(this, $_View), { 143 | length: 0, 144 | max: iMax || 250, 145 | distance: iDistance || 100, 146 | radius: iRadius || 150 147 | }); 148 | 149 | this.context = this.$_View[0].getContext('2d'); 150 | 151 | this.context.lineWidth = 0.3; 152 | this.context.strokeStyle = (new Color(150)).style; 153 | 154 | var MP = this.pointer = { 155 | x: 30 * this.width / 100, 156 | y: 30 * this.height / 100 157 | }; 158 | 159 | this.$_View.on('mousemove', function (iEvent) { 160 | 161 | MP.x = iEvent.pageX; 162 | MP.y = iEvent.pageY; 163 | 164 | }).on('mouseleave', function () { 165 | 166 | MP.x = -100; 167 | MP.y = -100 168 | }); 169 | } 170 | 171 | CanvasView.extend(StarMap, null, { 172 | move: function () { 173 | var _This_ = this; 174 | 175 | return $.each(this, function () { 176 | 177 | if ((this.y < 0) || (this.y > _This_.height)) 178 | this.vy = - this.vy; 179 | else if ((this.x < 0) || (this.x > _This_.width)) 180 | this.vx = - this.vx; 181 | 182 | this.x += this.vx; 183 | this.y += this.vy; 184 | }); 185 | }, 186 | connect: function () { 187 | var _This_ = this; 188 | 189 | return $.each(this, function () { 190 | 191 | for (var i = 0; _This_[i]; i++) 192 | if (( 193 | ((this.x - _This_[i].x) < _This_.distance) && 194 | ((this.y - _This_[i].y) < _This_.distance) && 195 | ((this.x - _This_[i].x) > -_This_.distance) && 196 | ((this.y - _This_[i].y) > -_This_.distance) 197 | ) && ( 198 | ((this.x - _This_.pointer.x) < _This_.radius) && 199 | ((this.y - _This_.pointer.y) < _This_.radius) && 200 | ((this.x - _This_.pointer.x) > -_This_.radius) && 201 | ((this.y - _This_.pointer.y) > -_This_.radius) 202 | )) { 203 | _This_.context.beginPath(); 204 | 205 | _This_.context.strokeStyle = this.mixColor( _This_[i] ); 206 | 207 | _This_.context.moveTo(this.x, this.y); 208 | 209 | _This_.context.lineTo(_This_[i].x, _This_[i].y); 210 | 211 | _This_.context.stroke(); 212 | 213 | _This_.context.closePath(); 214 | } 215 | }); 216 | }, 217 | animate: function () { 218 | this.context.clearRect(0, 0, this.width, this.height); 219 | 220 | $.each(this.move().connect(), Star.prototype.draw); 221 | 222 | self.requestAnimationFrame( arguments.callee.bind(this) ); 223 | }, 224 | render: function () { 225 | 226 | for (var i = 0; i < this.max; i++) 227 | this[ this.length++ ] = new Star( 228 | this.width, this.height, this.context 229 | ); 230 | 231 | self.requestAnimationFrame( this.animate.bind(this) ); 232 | } 233 | }); 234 | 235 | return StarMap; 236 | 237 | })(jquery, Color, Star, CanvasView); 238 | }); -------------------------------------------------------------------------------- /build/StarMap.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"function"==typeof define&&define.amd?define("StarMap",["jquery","jQueryKit"],t):"object"==typeof module?module.exports=t(require("jquery"),require("jQueryKit")):this.StarMap=t(this.jquery,this.jQueryKit)}(function(t,i){var e=function(i){function Color(t){t=t||0;var i=this.constructor;this.red=i.random(t),this.green=i.random(t),this.blue=i.random(t),this.style=i.getStyle(this.red,this.green,this.blue)}return t.extend(Color,{random:function(t){return 255*Math.random()+t},getStyle:function(t,i,e){return"rgba("+[Math.floor(t),Math.floor(i),Math.floor(e),.8].join(", ")+")"}}),Color}();return function(t,i,e,n){function StarMap(e,h,s,r){t.extend(n.call(this,e),{length:0,max:h||250,distance:s||100,radius:r||150}),this.context=this.$_View[0].getContext("2d"),this.context.lineWidth=.3,this.context.strokeStyle=new i(150).style;var o=this.pointer={x:30*this.width/100,y:30*this.height/100};this.$_View.on("mousemove",function(t){o.x=t.pageX,o.y=t.pageY}).on("mouseleave",function(){o.x=-100,o.y=-100})}return n.extend(StarMap,null,{move:function(){var i=this;return t.each(this,function(){this.y<0||this.y>i.height?this.vy=-this.vy:(this.x<0||this.x>i.width)&&(this.vx=-this.vx),this.x+=this.vx,this.y+=this.vy})},connect:function(){var i=this;return t.each(this,function(){for(var t=0;i[t];t++)this.x-i[t].x-i.distance&&this.y-i[t].y>-i.distance&&this.x-i.pointer.x-i.radius&&this.y-i.pointer.y>-i.radius&&(i.context.beginPath(),i.context.strokeStyle=this.mixColor(i[t]),i.context.moveTo(this.x,this.y),i.context.lineTo(i[t].x,i[t].y),i.context.stroke(),i.context.closePath())})},animate:function(){this.context.clearRect(0,0,this.width,this.height),t.each(this.move().connect(),e.prototype.draw),self.requestAnimationFrame(arguments.callee.bind(this))},render:function(){for(var t=0;t 2 | 3 |
5 | 6 | 29 |
30 |

31 | ${view.description} 32 | — 33 | 35 | Read More 36 | 37 |

38 | 41 |
42 |
43 |
44 | Latest commit to the ${view.default_branch} branch on 45 | ${(new Date( view.pushed_at )).toLocaleString()} 46 |
47 | 49 | Download as zip 50 | 51 |
52 |
-------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 粒子 / 星图 交互式动画 11 | 12 | 31 | 34 | 35 | 36 | 37 | 56 | 57 | 58 |
60 |
61 | 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "star-map", 3 | "version": "0.2.0", 4 | "description": "Particle / Star Map interactive animation", 5 | "main": "StarMap.js", 6 | "engines": { 7 | "node": "^5.0.0" 8 | }, 9 | "scripts": { 10 | "bundle": "cd source && amd-bundle ../StarMap.js", 11 | "compress": "uglifyjs StarMap.js -o build/StarMap.min.js --config-file build/compress.json", 12 | "build": "npm run bundle && npm run compress", 13 | "test": "opn index.html" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/TechQuery/StarMap.git" 18 | }, 19 | "keywords": [ 20 | "particle", 21 | "animation", 22 | "javascript", 23 | "canvas" 24 | ], 25 | "author": "shiy007@qq.com", 26 | "license": "ISC", 27 | "bugs": { 28 | "url": "https://github.com/TechQuery/StarMap/issues" 29 | }, 30 | "homepage": "https://github.com/TechQuery/StarMap#readme", 31 | "devDependencies": { 32 | "amd-bundle": "^0.4.2", 33 | "opn-cli": "^3.1.0", 34 | "uglify-js": "^3.0.24" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /source/CanvasView.js: -------------------------------------------------------------------------------- 1 | define(['jquery', 'jQueryKit'], function ($) { 2 | 3 | /* ----- 星空图 ----- */ 4 | 5 | function CanvasView($_View) { 6 | 7 | this.$_View = $( $_View ); 8 | 9 | this.init(); 10 | 11 | $( self ).on('resize', $.throttle(this.init.bind( this ))); 12 | 13 | return this; 14 | } 15 | 16 | $.Class.extend(CanvasView, null, { 17 | init: function () { 18 | 19 | var $_View = this.$_View.offsetParent(); 20 | 21 | this.width = this.$_View[0].width = $_View.width(); 22 | this.height = this.$_View[0].height = $_View.height(); 23 | } 24 | }); 25 | 26 | return CanvasView; 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /source/Color.js: -------------------------------------------------------------------------------- 1 | define(['jquery'], function ($) { 2 | 3 | /* ----- RGB 颜色 ----- */ 4 | 5 | function Color(min) { 6 | 7 | min = min || 0; 8 | 9 | var _Self_ = this.constructor; 10 | 11 | this.red = _Self_.random( min ); 12 | this.green = _Self_.random( min ); 13 | this.blue = _Self_.random( min ); 14 | 15 | this.style = _Self_.getStyle(this.red, this.green, this.blue); 16 | } 17 | 18 | $.extend(Color, { 19 | random: function (min) { 20 | 21 | return Math.random() * 255 + min; 22 | }, 23 | getStyle: function (red, green, blue) { 24 | 25 | return 'rgba(' + [ 26 | Math.floor(red), Math.floor(green), Math.floor(blue), 0.8 27 | ].join(', ') + ')'; 28 | } 29 | }); 30 | 31 | return Color; 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /source/Star.js: -------------------------------------------------------------------------------- 1 | define(['jquery', './Color'], function ($, Color) { 2 | 3 | /* ----- 恒星点 ----- */ 4 | 5 | function Star(Max_X, Max_Y, iContext) { 6 | 7 | this.x = Math.random() * Max_X; 8 | this.y = Math.random() * Max_Y; 9 | 10 | this.vx = Math.random() - 0.5; 11 | this.vy = Math.random() - 0.5; 12 | 13 | this.radius = Math.random(); 14 | 15 | this.color = new Color(); 16 | 17 | this.context = iContext; 18 | } 19 | 20 | Star.mixValue = function (comp1, weight1, comp2, weight2) { 21 | 22 | return (comp1 * weight1 + comp2 * weight2) / (weight1 + weight2); 23 | }; 24 | 25 | $.extend(Star.prototype, { 26 | draw: function () { 27 | 28 | this.context.beginPath(); 29 | 30 | this.context.fillStyle = this.color.style; 31 | 32 | this.context.arc( 33 | this.x, this.y, this.radius, 0, Math.PI * 2, false 34 | ); 35 | this.context.fill(); 36 | }, 37 | mixColor: function (iOther) { 38 | 39 | return Color.getStyle( 40 | Star.mixValue( 41 | this.color.red, this.radius, iOther.color.red, iOther.radius 42 | ), 43 | Star.mixValue( 44 | this.color.green, this.radius, iOther.color.red, iOther.radius 45 | ), 46 | Star.mixValue( 47 | this.color.blue, this.radius, iOther.color.red, iOther.radius 48 | ) 49 | ); 50 | } 51 | }); 52 | 53 | return Star; 54 | 55 | }); -------------------------------------------------------------------------------- /source/index.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', './Color', './Star', './CanvasView' 3 | ], function ($, Color, Star, CanvasView) { 4 | 5 | function StarMap($_View, iMax, iDistance, iRadius) { 6 | 7 | $.extend(CanvasView.call(this, $_View), { 8 | length: 0, 9 | max: iMax || 250, 10 | distance: iDistance || 100, 11 | radius: iRadius || 150 12 | }); 13 | 14 | this.context = this.$_View[0].getContext('2d'); 15 | 16 | this.context.lineWidth = 0.3; 17 | this.context.strokeStyle = (new Color(150)).style; 18 | 19 | var MP = this.pointer = { 20 | x: 30 * this.width / 100, 21 | y: 30 * this.height / 100 22 | }; 23 | 24 | this.$_View.on('mousemove', function (iEvent) { 25 | 26 | MP.x = iEvent.pageX; 27 | MP.y = iEvent.pageY; 28 | 29 | }).on('mouseleave', function () { 30 | 31 | MP.x = -100; 32 | MP.y = -100 33 | }); 34 | } 35 | 36 | CanvasView.extend(StarMap, null, { 37 | move: function () { 38 | var _This_ = this; 39 | 40 | return $.each(this, function () { 41 | 42 | if ((this.y < 0) || (this.y > _This_.height)) 43 | this.vy = - this.vy; 44 | else if ((this.x < 0) || (this.x > _This_.width)) 45 | this.vx = - this.vx; 46 | 47 | this.x += this.vx; 48 | this.y += this.vy; 49 | }); 50 | }, 51 | connect: function () { 52 | var _This_ = this; 53 | 54 | return $.each(this, function () { 55 | 56 | for (var i = 0; _This_[i]; i++) 57 | if (( 58 | ((this.x - _This_[i].x) < _This_.distance) && 59 | ((this.y - _This_[i].y) < _This_.distance) && 60 | ((this.x - _This_[i].x) > -_This_.distance) && 61 | ((this.y - _This_[i].y) > -_This_.distance) 62 | ) && ( 63 | ((this.x - _This_.pointer.x) < _This_.radius) && 64 | ((this.y - _This_.pointer.y) < _This_.radius) && 65 | ((this.x - _This_.pointer.x) > -_This_.radius) && 66 | ((this.y - _This_.pointer.y) > -_This_.radius) 67 | )) { 68 | _This_.context.beginPath(); 69 | 70 | _This_.context.strokeStyle = this.mixColor( _This_[i] ); 71 | 72 | _This_.context.moveTo(this.x, this.y); 73 | 74 | _This_.context.lineTo(_This_[i].x, _This_[i].y); 75 | 76 | _This_.context.stroke(); 77 | 78 | _This_.context.closePath(); 79 | } 80 | }); 81 | }, 82 | animate: function () { 83 | this.context.clearRect(0, 0, this.width, this.height); 84 | 85 | $.each(this.move().connect(), Star.prototype.draw); 86 | 87 | self.requestAnimationFrame( arguments.callee.bind(this) ); 88 | }, 89 | render: function () { 90 | 91 | for (var i = 0; i < this.max; i++) 92 | this[ this.length++ ] = new Star( 93 | this.width, this.height, this.context 94 | ); 95 | 96 | self.requestAnimationFrame( this.animate.bind(this) ); 97 | } 98 | }); 99 | 100 | return StarMap; 101 | 102 | }); 103 | --------------------------------------------------------------------------------