├── .gitignore ├── .idea ├── jsLibraryMappings.xml ├── misc.xml ├── modules.xml ├── paint_game.iml ├── vcs.xml └── workspace.xml ├── README.md ├── package.json └── server ├── db.js ├── db.json ├── dbimport.js ├── server.js ├── static ├── bootstrap.css ├── index.html ├── io.js ├── js.js └── style.css └── words.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/paint_game.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 136 | 137 | 138 | 143 | 145 | 146 | 161 | 162 | 163 | 164 | 165 | true 166 | 167 | 168 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 211 | 212 | 213 | 214 | 217 | 218 | 221 | 222 | 223 | 224 | 227 | 228 | 231 | 232 | 235 | 236 | 237 | 238 | 241 | 242 | 245 | 246 | 249 | 250 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 308 | 309 | project 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | project 326 | 327 | 328 | true 329 | 330 | bdd 331 | 332 | DIRECTORY 333 | 334 | false 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 1463878784238 358 | 386 | 387 | 1464141493040 388 | 393 | 394 | 1464151353139 395 | 400 | 401 | 1464152039184 402 | 407 | 408 | 1464152974469 409 | 414 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 455 | 458 | 459 | 460 | 462 | 463 | 470 | 471 | 472 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Paint Game # 2 | 3 | [Demo](http://paintgame.moyuyc.xyz/) 4 | 5 | npm install 6 | 7 | node server/server.js 8 | 9 | http://localhost:4000/ 10 | 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paint_game", 3 | "version": "1.0.0", 4 | "description": "[Demo](http://paintgame.moyuyc.xyz/)", 5 | "main": "server/server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "node", 11 | "socket.io" 12 | ], 13 | "dependencies": { 14 | "socket.io": "^1.4.6" 15 | }, 16 | "author": "moyu", 17 | "license": "ISC", 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/moyuyc/paint_game.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/moyuyc/paint_game/issues" 24 | }, 25 | "homepage": "https://github.com/moyuyc/paint_game#readme" 26 | } 27 | -------------------------------------------------------------------------------- /server/db.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Yc on 2016/5/26. 3 | */ 4 | var fs = require('fs'); 5 | var db = (function () { 6 | var file = __dirname+'/db.json'; 7 | var db = JSON.parse(fs.readFileSync(file)); 8 | return { 9 | save : function () { 10 | fs.writeFile(file,JSON.stringify(db,null,4)); 11 | }, 12 | add : function (word,tip) { 13 | if(db.findIndex(x=>{return x.word===word;})!=-1){ 14 | console.error(new Error(word+' existed')); 15 | return false; 16 | } 17 | db.push({word:word,tip:tip}); 18 | return true; 19 | }, 20 | randomWord :function () { 21 | return db[Math.floor(Math.random()*db.length)]; 22 | }, 23 | _db:db 24 | } 25 | })(); 26 | 27 | module.exports = db; -------------------------------------------------------------------------------- /server/db.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "word": "手机", 4 | "tip": "不离身" 5 | }, 6 | { 7 | "word": "苹果", 8 | "tip": "水果" 9 | }, 10 | { 11 | "word": "香蕉", 12 | "tip": "水果" 13 | }, 14 | { 15 | "word": "蜡笔小新", 16 | "tip": "卡通人物" 17 | }, 18 | { 19 | "word": "白鸽", 20 | "tip": "动物" 21 | }, 22 | { 23 | "word": "布娃娃", 24 | "tip": "玩具" 25 | }, 26 | { 27 | "word": "餐巾", 28 | "tip": "生活用品" 29 | }, 30 | { 31 | "word": "CD", 32 | "tip": "娱乐用品" 33 | }, 34 | { 35 | "word": "瓷器", 36 | "tip": "易碎" 37 | }, 38 | { 39 | "word": "长江三峡", 40 | "tip": "伟大的工程" 41 | }, 42 | { 43 | "word": "长颈漏斗", 44 | "tip": "化学器材" 45 | }, 46 | { 47 | "word": "赤壁", 48 | "tip": "一个地方" 49 | }, 50 | { 51 | "word": "除草剂", 52 | "tip": "喷剂" 53 | }, 54 | { 55 | "word": "大头鱼", 56 | "tip": "yyf" 57 | }, 58 | { 59 | "word": "刀", 60 | "tip": "很危险的东西" 61 | }, 62 | { 63 | "word": "豆沙包", 64 | "tip": "甜的吃的" 65 | }, 66 | { 67 | "word": "耳机", 68 | "tip": "电子用品" 69 | }, 70 | { 71 | "word": "飞碟", 72 | "tip": "很难看到" 73 | }, 74 | { 75 | "word": "荷花", 76 | "tip": "朱自清" 77 | }, 78 | { 79 | "word": "虎", 80 | "tip": "女人" 81 | }, 82 | { 83 | "word": "蝴蝶", 84 | "tip": "庞龙" 85 | }, 86 | { 87 | "word": "护膝", 88 | "tip": "运动保护" 89 | }, 90 | { 91 | "word": "花朵", 92 | "tip": "形容小朋友" 93 | }, 94 | { 95 | "word": "环保", 96 | "tip": "可持续发展" 97 | }, 98 | { 99 | "word": "欢乐谷", 100 | "tip": "小朋友的天堂" 101 | }, 102 | { 103 | "word": "击剑", 104 | "tip": "运动" 105 | }, 106 | { 107 | "word": "教师", 108 | "tip": "令人尊敬" 109 | }, 110 | { 111 | "word": "KTV", 112 | "tip": "释放压力" 113 | }, 114 | { 115 | "word": "老爷车", 116 | "tip": "" 117 | }, 118 | { 119 | "word": "刘翔", 120 | "tip": "" 121 | }, 122 | { 123 | "word": "落地灯", 124 | "tip": "" 125 | }, 126 | { 127 | "word": "棉花", 128 | "tip": "" 129 | }, 130 | { 131 | "word": "母亲", 132 | "tip": "" 133 | }, 134 | { 135 | "word": "NBA", 136 | "tip": "" 137 | }, 138 | { 139 | "word": "内裤", 140 | "tip": "" 141 | }, 142 | { 143 | "word": "牛奶糖", 144 | "tip": "" 145 | }, 146 | { 147 | "word": "牛肉干", 148 | "tip": "" 149 | }, 150 | { 151 | "word": "牛肉面", 152 | "tip": "" 153 | }, 154 | { 155 | "word": "排插", 156 | "tip": "" 157 | }, 158 | { 159 | "word": "秦始皇兵马俑", 160 | "tip": "" 161 | }, 162 | { 163 | "word": "全家桶", 164 | "tip": "" 165 | }, 166 | { 167 | "word": "沙僧", 168 | "tip": "" 169 | }, 170 | { 171 | "word": "圣经", 172 | "tip": "" 173 | }, 174 | { 175 | "word": "升旗", 176 | "tip": "" 177 | }, 178 | { 179 | "word": "实验室", 180 | "tip": "" 181 | }, 182 | { 183 | "word": "狮子座", 184 | "tip": "" 185 | }, 186 | { 187 | "word": "守门员", 188 | "tip": "" 189 | }, 190 | { 191 | "word": "首饰", 192 | "tip": "" 193 | }, 194 | { 195 | "word": "手套", 196 | "tip": "" 197 | }, 198 | { 199 | "word": "水波", 200 | "tip": "" 201 | }, 202 | { 203 | "word": "土豆", 204 | "tip": "" 205 | }, 206 | { 207 | "word": "丸子", 208 | "tip": "" 209 | }, 210 | { 211 | "word": "网址", 212 | "tip": "" 213 | }, 214 | { 215 | "word": "鲜橙多", 216 | "tip": "" 217 | }, 218 | { 219 | "word": "鲜花", 220 | "tip": "" 221 | }, 222 | { 223 | "word": "小霸王", 224 | "tip": "" 225 | }, 226 | { 227 | "word": "腰带", 228 | "tip": "" 229 | }, 230 | { 231 | "word": "烟斗", 232 | "tip": "" 233 | }, 234 | { 235 | "word": "扬州炒饭", 236 | "tip": "" 237 | }, 238 | { 239 | "word": "衣橱", 240 | "tip": "" 241 | }, 242 | { 243 | "word": "医生", 244 | "tip": "" 245 | }, 246 | { 247 | "word": "音响", 248 | "tip": "" 249 | }, 250 | { 251 | "word": "鹦鹉", 252 | "tip": "" 253 | }, 254 | { 255 | "word": "油", 256 | "tip": "" 257 | }, 258 | { 259 | "word": "语文书", 260 | "tip": "" 261 | }, 262 | { 263 | "word": "针筒", 264 | "tip": "" 265 | }, 266 | { 267 | "word": "纸杯", 268 | "tip": "" 269 | }, 270 | { 271 | "word": "钻戒", 272 | "tip": "" 273 | } 274 | ] -------------------------------------------------------------------------------- /server/dbimport.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Yc on 2016/5/26. 3 | */ 4 | var db = require('./db'); 5 | var fs = require('fs'); 6 | 7 | fs.readFile('words.txt',function (err, data) { 8 | if(err) throw err; 9 | var data = data.toString(); 10 | data = data.split('\r\n'); 11 | data.forEach(x=>{ 12 | x = x.split(','); 13 | console.log(x); 14 | if(x.length===1){ 15 | db.add(x[0],''); 16 | }else if(x.length>1){ 17 | db.add(x[0],x[1]); 18 | } 19 | }) 20 | db.save(); 21 | }) 22 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Yc on 2016/5/21. 3 | */ 4 | var httpd = require('http').createServer(handler); 5 | var io = require('socket.io').listen(httpd); 6 | var fs = require('fs'); 7 | var db = require('./db'); 8 | httpd.listen(4000); 9 | 10 | function handler(req,res) { 11 | fs.readFile(__dirname+'/static/'+(req.url==='/'?'index.html':req.url), 12 | function (err,data) { 13 | if(err){ 14 | res.writeHead(500); 15 | return res.end('Error loading index.html'); 16 | } 17 | res.writeHead(200); 18 | res.end(data); 19 | } 20 | ); 21 | } 22 | 23 | 24 | 25 | var paths = []; 26 | var tops = (function () { 27 | var _tops = [],idmap={},n=10; 28 | return { 29 | set : function (id,name,v) { 30 | if(this.isExists(id)) 31 | this.remove(id); 32 | var i = _tops.findIndex(x=>{return idmap[x].v{ 55 | if(i>=n) return false; 56 | arr.push({id:x,v:idmap[x].v,name:idmap[x].name}); 57 | return true; 58 | }); 59 | return arr; 60 | } 61 | } 62 | }()); 63 | 64 | 65 | function doCmd(msg,socket) { 66 | if(msg[0]==='#'){ 67 | var msg = msg.substring(1), 68 | sockets = getSockets(socket); 69 | switch (msg) { 70 | case 'show paths': 71 | socket.emit('cmd',JSON.stringify(paths)); 72 | socket.emit('server msg','指令操作成功!'); 73 | return true; 74 | case 'show users': 75 | socket.emit('cmd',JSON.stringify(sockets.map(x=>x=x.name))); 76 | socket.emit('server msg','指令操作成功!'); 77 | return true; 78 | case 'clear paths': 79 | paths = []; 80 | socket.emit('server msg','指令操作成功!'); 81 | socket.emit('paint paths',JSON.stringify(paths)); 82 | return true; 83 | case 'show word': 84 | socket.emit('server msg','指令操作成功!'); 85 | socket.emit('cmd',JSON.stringify(Game.player?Game.player.word:null)); 86 | return true; 87 | case 'show words': 88 | socket.emit('server msg','指令操作成功!'); 89 | socket.emit('cmd',JSON.stringify(db._db)); 90 | return true; 91 | } 92 | if(msg.startsWith('add word')){ 93 | var s = msg.substring(8).trim(); 94 | s = s.split(' '); 95 | if(s.length===2){ 96 | if(db.add(s[0],s[1])) { 97 | db.save(); 98 | socket.emit('server msg', '指令操作成功!'); 99 | } 100 | else 101 | socket.emit('server msg','指令操作失败。'); 102 | }else 103 | socket.emit('server msg','指令操作失败!'); 104 | }else{ 105 | return false; 106 | } 107 | return true; 108 | }else{ 109 | return false; 110 | } 111 | } 112 | 113 | function escapeHTML(data) { 114 | var s = ''; 115 | for(var i = 0 ;i': 125 | d = '>'; break; 126 | case ' ': 127 | d = ' '; break; 128 | } 129 | s+=d; 130 | } 131 | return s; 132 | } 133 | function getSockets(s,sort) { 134 | s = s.server.sockets.sockets; 135 | var a = [] 136 | for(var k in s) 137 | a.push(getSocket(s[k])); 138 | if(sort) 139 | a = a.sort((x,y)=>{ 140 | if(!x.in || !y.in) return 0; 141 | return x.in-y.in; 142 | }); 143 | return a; 144 | } 145 | function getSocket(s) { 146 | return { 147 | id : s.id.substring(2), 148 | in : s.attrin, 149 | name : s.name 150 | } 151 | } 152 | Game = {}; 153 | Game.inQueue = []; 154 | Game.player = null; 155 | io.sockets.on('connection',function (socket) { 156 | socket.on('login',function (name) { 157 | this.name = name || "无名游客"; 158 | this.attrin = false; 159 | this.emit('server msg','欢迎, '+this.name+' !'); 160 | this.broadcast.emit('server msg','欢迎, '+this.name+' !'); 161 | this.emit('paint paths',JSON.stringify(paths)); 162 | var users = Game.inQueue.map(x=>{return getSocket(x)}); 163 | this.emit('reset in users',JSON.stringify(users)); 164 | 165 | tops.set(this.id.substring(2),this.name,0); 166 | var j = JSON.stringify(tops); 167 | this.emit('tops',j); 168 | this.broadcast.emit('tops',j); 169 | this.on('in',function () { 170 | if(this.attrin) return; 171 | this.attrin = Date.now(); 172 | Game.inQueue.push(this); 173 | var json = JSON.stringify(getSocket(this)); 174 | this.broadcast.emit('new in user',json); 175 | this.emit('in',json); 176 | 177 | setTimeout(function () { 178 | if(Game.player || !Game.inQueue.length) return; 179 | Game.run = arguments.callee 180 | var t=Game.inQueue[0]; 181 | Game.player = t; 182 | t.time = 60;t.word = db.randomWord(); 183 | t.emit('mytime',JSON.stringify({name:t.name,word:t.word.word,time:t.time})); 184 | t.broadcast.emit('othertime',JSON.stringify({name:t.name,time:t.time})); 185 | Game.timer = setTimeout(function () { 186 | console.log(t.time,t.name); 187 | if(t.time === 0){ 188 | delete t.time; 189 | delete Game.player; 190 | delete t.attrin; 191 | paths=[]; 192 | Game.inQueue.shift(); 193 | setTimeout(Game.run,4000); 194 | t.emit('mytimeout',t.id.substring(2)); 195 | t.broadcast.emit('timeout',JSON.stringify({id:t.id.substring(2),word:t.word.word})); 196 | t.emit('clear paint'); 197 | t.broadcast.emit('clear paint'); 198 | return; 199 | } 200 | t.time--;var o = {name:t.name,time:t.time,word:t.word.word.length+'个字'}; 201 | if(t.time <= 30) { 202 | o.word = o.word +',' + t.word.tip; 203 | } 204 | o = JSON.stringify(o); 205 | t.emit('update my time',o); 206 | t.broadcast.emit('update time',o); 207 | Game.timer = setTimeout(arguments.callee,1000); 208 | },1000); 209 | },4000); 210 | }); 211 | this.on('erase',function (x,y,w,h) { 212 | paths.push({tag:'erase',x:x,y:y,w:w,h:h}); 213 | this.broadcast.emit('erase',x,y,w,h); 214 | }); 215 | this.on('out',function () { 216 | console.log('before',Game.inQueue.length); 217 | Game.inQueue.splice(Game.inQueue.findIndex(x=>{x.id===this.id})); 218 | console.log('after',Game.inQueue.length); 219 | this.attrin = false; 220 | this.emit('out',this.id.substring(2)); 221 | this.broadcast.emit('out user',this.id.substring(2)); 222 | }); 223 | this.on('client msg',function (msg) { 224 | if(!doCmd(msg,this)) { 225 | msg = escapeHTML(msg); 226 | if(Game.player && Game.player.word.word === msg){ 227 | if(this.prev && this.prev.player === Game.player&& this.prev.word === msg){ 228 | this.emit('server msg',"您已经正确回答过了!"); 229 | return; 230 | } 231 | tops.set(this.id.substring(2),this.name,tops.get(this.id.substring(2)).v+1); 232 | this.emit('server msg',"真棒!回答正确!"); 233 | this.broadcast.emit('server msg',"恭喜!"+this.name+" 回答正确!"); 234 | var j = JSON.stringify(tops); 235 | this.broadcast.emit('tops',j); 236 | this.emit('tops',j); 237 | this.prev = { 238 | player:Game.player, 239 | word:msg 240 | }; 241 | return; 242 | } 243 | var date = new Date().format('yyyy-MM-dd hh:mm:ss'); 244 | this.emit('server msg',date+'
'+ this.name + ' 说: ' + msg); 245 | this.broadcast.emit('server msg',date+'
'+ this.name + ' 说: ' + msg); 246 | } 247 | }); 248 | this.on('disconnect',function () { 249 | if(Game.player && this.id === Game.player.id) { 250 | delete Game.player; 251 | paths=[]; 252 | Game.inQueue.shift(); 253 | if(Game.timer!=null) { 254 | clearTimeout(Game.timer); 255 | setTimeout(Game.run,4000); 256 | } 257 | this.broadcast.emit('othertime',JSON.stringify({name:this.name+'(已退出)',time:0})); 258 | this.broadcast.emit('clear paint'); 259 | } 260 | if(tops.isExists(this.id.substring(2))) 261 | tops.remove(this.id.substring(2)); 262 | var i =Game.inQueue.indexOf(this); 263 | if(i!=-1) 264 | Game.inQueue.splice(i,1); 265 | this.broadcast.emit('server msg','拜, '+this.name +'。'); 266 | this.broadcast.emit('out user',this.id.substring(2)); 267 | this.broadcast.emit('tops',JSON.stringify(tops)); 268 | }); 269 | this.on('paint',function (data) { 270 | if(!Game.player || Game.player.id !== this.id) return; 271 | data = JSON.parse(data); 272 | var pts = data.data; 273 | switch (data.status){ 274 | case 'ing' : 275 | this.broadcast.emit('paint pts',JSON.stringify(pts)); 276 | break; 277 | case 'end' : 278 | this.broadcast.emit('paint pts',JSON.stringify(pts)); 279 | pts.tag = 'pts'; 280 | paths.push(pts); 281 | break; 282 | } 283 | }); 284 | this.on('repaint',function () { 285 | this.emit('paint paths',JSON.stringify(paths)); 286 | }) 287 | this.on('clear paths',function () { 288 | if(this === Game.player) { 289 | console.log('clear all'); 290 | paths = []; 291 | this.emit('clear paint'); 292 | this.broadcast.emit('clear paint'); 293 | } 294 | }) 295 | }); 296 | socket.emit('login'); 297 | }) 298 | 299 | Date.prototype.format = function (fmt) { //author: meizz 300 | var o = { 301 | "M+": this.getMonth() + 1, //月份 302 | "d+": this.getDate(), //日 303 | "h+": this.getHours(), //小时 304 | "m+": this.getMinutes(), //分 305 | "s+": this.getSeconds(), //秒 306 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度 307 | "S": this.getMilliseconds() //毫秒 308 | }; 309 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 310 | for (var k in o) 311 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 312 | return fmt; 313 | } -------------------------------------------------------------------------------- /server/static/bootstrap.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /*! 8 | * Generated using the Bootstrap Customizer (http://v3.bootcss.com/customize/?id=c8dec8bd2ba35ab3f089d921bd489389) 9 | * Config saved to config.json and https://gist.github.com/c8dec8bd2ba35ab3f089d921bd489389 10 | */ 11 | /*! 12 | * Bootstrap v3.3.5 (http://getbootstrap.com) 13 | * Copyright 2011-2015 Twitter, Inc. 14 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 15 | */ 16 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 17 | html { 18 | font-family: sans-serif; 19 | -ms-text-size-adjust: 100%; 20 | -webkit-text-size-adjust: 100%; 21 | } 22 | body { 23 | margin: 0; 24 | } 25 | article, 26 | aside, 27 | details, 28 | figcaption, 29 | figure, 30 | footer, 31 | header, 32 | hgroup, 33 | main, 34 | menu, 35 | nav, 36 | section, 37 | summary { 38 | display: block; 39 | } 40 | audio, 41 | canvas, 42 | progress, 43 | video { 44 | display: inline-block; 45 | vertical-align: baseline; 46 | } 47 | audio:not([controls]) { 48 | display: none; 49 | height: 0; 50 | } 51 | [hidden], 52 | template { 53 | display: none; 54 | } 55 | a { 56 | background-color: transparent; 57 | } 58 | a:active, 59 | a:hover { 60 | outline: 0; 61 | } 62 | abbr[title] { 63 | border-bottom: 1px dotted; 64 | } 65 | b, 66 | strong { 67 | font-weight: bold; 68 | } 69 | dfn { 70 | font-style: italic; 71 | } 72 | h1 { 73 | font-size: 2em; 74 | margin: 0.67em 0; 75 | } 76 | mark { 77 | background: #ff0; 78 | color: #000; 79 | } 80 | small { 81 | font-size: 80%; 82 | } 83 | sub, 84 | sup { 85 | font-size: 75%; 86 | line-height: 0; 87 | position: relative; 88 | vertical-align: baseline; 89 | } 90 | sup { 91 | top: -0.5em; 92 | } 93 | sub { 94 | bottom: -0.25em; 95 | } 96 | img { 97 | border: 0; 98 | } 99 | svg:not(:root) { 100 | overflow: hidden; 101 | } 102 | figure { 103 | margin: 1em 40px; 104 | } 105 | hr { 106 | -webkit-box-sizing: content-box; 107 | -moz-box-sizing: content-box; 108 | box-sizing: content-box; 109 | height: 0; 110 | } 111 | pre { 112 | overflow: auto; 113 | } 114 | code, 115 | kbd, 116 | pre, 117 | samp { 118 | font-family: monospace, monospace; 119 | font-size: 1em; 120 | } 121 | button, 122 | input, 123 | optgroup, 124 | select, 125 | textarea { 126 | color: inherit; 127 | font: inherit; 128 | margin: 0; 129 | } 130 | button { 131 | overflow: visible; 132 | } 133 | button, 134 | select { 135 | text-transform: none; 136 | } 137 | button, 138 | html input[type="button"], 139 | input[type="reset"], 140 | input[type="submit"] { 141 | -webkit-appearance: button; 142 | cursor: pointer; 143 | } 144 | button[disabled], 145 | html input[disabled] { 146 | cursor: default; 147 | } 148 | button::-moz-focus-inner, 149 | input::-moz-focus-inner { 150 | border: 0; 151 | padding: 0; 152 | } 153 | input { 154 | line-height: normal; 155 | } 156 | input[type="checkbox"], 157 | input[type="radio"] { 158 | -webkit-box-sizing: border-box; 159 | -moz-box-sizing: border-box; 160 | box-sizing: border-box; 161 | padding: 0; 162 | } 163 | input[type="number"]::-webkit-inner-spin-button, 164 | input[type="number"]::-webkit-outer-spin-button { 165 | height: auto; 166 | } 167 | input[type="search"] { 168 | -webkit-appearance: textfield; 169 | -webkit-box-sizing: content-box; 170 | -moz-box-sizing: content-box; 171 | box-sizing: content-box; 172 | } 173 | input[type="search"]::-webkit-search-cancel-button, 174 | input[type="search"]::-webkit-search-decoration { 175 | -webkit-appearance: none; 176 | } 177 | fieldset { 178 | border: 1px solid #c0c0c0; 179 | margin: 0 2px; 180 | padding: 0.35em 0.625em 0.75em; 181 | } 182 | legend { 183 | border: 0; 184 | padding: 0; 185 | } 186 | textarea { 187 | overflow: auto; 188 | } 189 | optgroup { 190 | font-weight: bold; 191 | } 192 | table { 193 | border-collapse: collapse; 194 | border-spacing: 0; 195 | } 196 | td, 197 | th { 198 | padding: 0; 199 | } 200 | * { 201 | -webkit-box-sizing: border-box; 202 | -moz-box-sizing: border-box; 203 | box-sizing: border-box; 204 | } 205 | *:before, 206 | *:after { 207 | -webkit-box-sizing: border-box; 208 | -moz-box-sizing: border-box; 209 | box-sizing: border-box; 210 | } 211 | html { 212 | font-size: 10px; 213 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 214 | } 215 | body { 216 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 217 | font-size: 14px; 218 | line-height: 1.42857143; 219 | color: #333333; 220 | background-color: #ffffff; 221 | } 222 | input, 223 | button, 224 | select, 225 | textarea { 226 | font-family: inherit; 227 | font-size: inherit; 228 | line-height: inherit; 229 | } 230 | a { 231 | color: #337ab7; 232 | text-decoration: none; 233 | } 234 | a:hover, 235 | a:focus { 236 | color: #23527c; 237 | text-decoration: underline; 238 | } 239 | a:focus { 240 | outline: thin dotted; 241 | outline: 5px auto -webkit-focus-ring-color; 242 | outline-offset: -2px; 243 | } 244 | figure { 245 | margin: 0; 246 | } 247 | img { 248 | vertical-align: middle; 249 | } 250 | .img-responsive { 251 | display: block; 252 | max-width: 100%; 253 | height: auto; 254 | } 255 | .img-rounded { 256 | border-radius: 6px; 257 | } 258 | .img-thumbnail { 259 | padding: 4px; 260 | line-height: 1.42857143; 261 | background-color: #ffffff; 262 | border: 1px solid #dddddd; 263 | border-radius: 4px; 264 | -webkit-transition: all 0.2s ease-in-out; 265 | -o-transition: all 0.2s ease-in-out; 266 | transition: all 0.2s ease-in-out; 267 | display: inline-block; 268 | max-width: 100%; 269 | height: auto; 270 | } 271 | .img-circle { 272 | border-radius: 50%; 273 | } 274 | hr { 275 | margin-top: 20px; 276 | margin-bottom: 20px; 277 | border: 0; 278 | border-top: 1px solid #eeeeee; 279 | } 280 | .sr-only { 281 | position: absolute; 282 | width: 1px; 283 | height: 1px; 284 | margin: -1px; 285 | padding: 0; 286 | overflow: hidden; 287 | clip: rect(0, 0, 0, 0); 288 | border: 0; 289 | } 290 | .sr-only-focusable:active, 291 | .sr-only-focusable:focus { 292 | position: static; 293 | width: auto; 294 | height: auto; 295 | margin: 0; 296 | overflow: visible; 297 | clip: auto; 298 | } 299 | [role="button"] { 300 | cursor: pointer; 301 | } 302 | .container { 303 | margin-right: auto; 304 | margin-left: auto; 305 | padding-left: 15px; 306 | padding-right: 15px; 307 | } 308 | @media (min-width: 768px) { 309 | .container { 310 | width: 750px; 311 | } 312 | } 313 | @media (min-width: 992px) { 314 | .container { 315 | width: 970px; 316 | } 317 | } 318 | @media (min-width: 1200px) { 319 | .container { 320 | width: 1170px; 321 | } 322 | } 323 | .container-fluid { 324 | margin-right: auto; 325 | margin-left: auto; 326 | padding-left: 15px; 327 | padding-right: 15px; 328 | } 329 | .row { 330 | margin-left: -15px; 331 | margin-right: -15px; 332 | } 333 | .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { 334 | position: relative; 335 | min-height: 1px; 336 | padding-left: 15px; 337 | padding-right: 15px; 338 | } 339 | .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { 340 | float: left; 341 | } 342 | .col-xs-12 { 343 | width: 100%; 344 | } 345 | .col-xs-11 { 346 | width: 91.66666667%; 347 | } 348 | .col-xs-10 { 349 | width: 83.33333333%; 350 | } 351 | .col-xs-9 { 352 | width: 75%; 353 | } 354 | .col-xs-8 { 355 | width: 66.66666667%; 356 | } 357 | .col-xs-7 { 358 | width: 58.33333333%; 359 | } 360 | .col-xs-6 { 361 | width: 50%; 362 | } 363 | .col-xs-5 { 364 | width: 41.66666667%; 365 | } 366 | .col-xs-4 { 367 | width: 33.33333333%; 368 | } 369 | .col-xs-3 { 370 | width: 25%; 371 | } 372 | .col-xs-2 { 373 | width: 16.66666667%; 374 | } 375 | .col-xs-1 { 376 | width: 8.33333333%; 377 | } 378 | .col-xs-pull-12 { 379 | right: 100%; 380 | } 381 | .col-xs-pull-11 { 382 | right: 91.66666667%; 383 | } 384 | .col-xs-pull-10 { 385 | right: 83.33333333%; 386 | } 387 | .col-xs-pull-9 { 388 | right: 75%; 389 | } 390 | .col-xs-pull-8 { 391 | right: 66.66666667%; 392 | } 393 | .col-xs-pull-7 { 394 | right: 58.33333333%; 395 | } 396 | .col-xs-pull-6 { 397 | right: 50%; 398 | } 399 | .col-xs-pull-5 { 400 | right: 41.66666667%; 401 | } 402 | .col-xs-pull-4 { 403 | right: 33.33333333%; 404 | } 405 | .col-xs-pull-3 { 406 | right: 25%; 407 | } 408 | .col-xs-pull-2 { 409 | right: 16.66666667%; 410 | } 411 | .col-xs-pull-1 { 412 | right: 8.33333333%; 413 | } 414 | .col-xs-pull-0 { 415 | right: auto; 416 | } 417 | .col-xs-push-12 { 418 | left: 100%; 419 | } 420 | .col-xs-push-11 { 421 | left: 91.66666667%; 422 | } 423 | .col-xs-push-10 { 424 | left: 83.33333333%; 425 | } 426 | .col-xs-push-9 { 427 | left: 75%; 428 | } 429 | .col-xs-push-8 { 430 | left: 66.66666667%; 431 | } 432 | .col-xs-push-7 { 433 | left: 58.33333333%; 434 | } 435 | .col-xs-push-6 { 436 | left: 50%; 437 | } 438 | .col-xs-push-5 { 439 | left: 41.66666667%; 440 | } 441 | .col-xs-push-4 { 442 | left: 33.33333333%; 443 | } 444 | .col-xs-push-3 { 445 | left: 25%; 446 | } 447 | .col-xs-push-2 { 448 | left: 16.66666667%; 449 | } 450 | .col-xs-push-1 { 451 | left: 8.33333333%; 452 | } 453 | .col-xs-push-0 { 454 | left: auto; 455 | } 456 | .col-xs-offset-12 { 457 | margin-left: 100%; 458 | } 459 | .col-xs-offset-11 { 460 | margin-left: 91.66666667%; 461 | } 462 | .col-xs-offset-10 { 463 | margin-left: 83.33333333%; 464 | } 465 | .col-xs-offset-9 { 466 | margin-left: 75%; 467 | } 468 | .col-xs-offset-8 { 469 | margin-left: 66.66666667%; 470 | } 471 | .col-xs-offset-7 { 472 | margin-left: 58.33333333%; 473 | } 474 | .col-xs-offset-6 { 475 | margin-left: 50%; 476 | } 477 | .col-xs-offset-5 { 478 | margin-left: 41.66666667%; 479 | } 480 | .col-xs-offset-4 { 481 | margin-left: 33.33333333%; 482 | } 483 | .col-xs-offset-3 { 484 | margin-left: 25%; 485 | } 486 | .col-xs-offset-2 { 487 | margin-left: 16.66666667%; 488 | } 489 | .col-xs-offset-1 { 490 | margin-left: 8.33333333%; 491 | } 492 | .col-xs-offset-0 { 493 | margin-left: 0%; 494 | } 495 | @media (min-width: 768px) { 496 | .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { 497 | float: left; 498 | } 499 | .col-sm-12 { 500 | width: 100%; 501 | } 502 | .col-sm-11 { 503 | width: 91.66666667%; 504 | } 505 | .col-sm-10 { 506 | width: 83.33333333%; 507 | } 508 | .col-sm-9 { 509 | width: 75%; 510 | } 511 | .col-sm-8 { 512 | width: 66.66666667%; 513 | } 514 | .col-sm-7 { 515 | width: 58.33333333%; 516 | } 517 | .col-sm-6 { 518 | width: 50%; 519 | } 520 | .col-sm-5 { 521 | width: 41.66666667%; 522 | } 523 | .col-sm-4 { 524 | width: 33.33333333%; 525 | } 526 | .col-sm-3 { 527 | width: 25%; 528 | } 529 | .col-sm-2 { 530 | width: 16.66666667%; 531 | } 532 | .col-sm-1 { 533 | width: 8.33333333%; 534 | } 535 | .col-sm-pull-12 { 536 | right: 100%; 537 | } 538 | .col-sm-pull-11 { 539 | right: 91.66666667%; 540 | } 541 | .col-sm-pull-10 { 542 | right: 83.33333333%; 543 | } 544 | .col-sm-pull-9 { 545 | right: 75%; 546 | } 547 | .col-sm-pull-8 { 548 | right: 66.66666667%; 549 | } 550 | .col-sm-pull-7 { 551 | right: 58.33333333%; 552 | } 553 | .col-sm-pull-6 { 554 | right: 50%; 555 | } 556 | .col-sm-pull-5 { 557 | right: 41.66666667%; 558 | } 559 | .col-sm-pull-4 { 560 | right: 33.33333333%; 561 | } 562 | .col-sm-pull-3 { 563 | right: 25%; 564 | } 565 | .col-sm-pull-2 { 566 | right: 16.66666667%; 567 | } 568 | .col-sm-pull-1 { 569 | right: 8.33333333%; 570 | } 571 | .col-sm-pull-0 { 572 | right: auto; 573 | } 574 | .col-sm-push-12 { 575 | left: 100%; 576 | } 577 | .col-sm-push-11 { 578 | left: 91.66666667%; 579 | } 580 | .col-sm-push-10 { 581 | left: 83.33333333%; 582 | } 583 | .col-sm-push-9 { 584 | left: 75%; 585 | } 586 | .col-sm-push-8 { 587 | left: 66.66666667%; 588 | } 589 | .col-sm-push-7 { 590 | left: 58.33333333%; 591 | } 592 | .col-sm-push-6 { 593 | left: 50%; 594 | } 595 | .col-sm-push-5 { 596 | left: 41.66666667%; 597 | } 598 | .col-sm-push-4 { 599 | left: 33.33333333%; 600 | } 601 | .col-sm-push-3 { 602 | left: 25%; 603 | } 604 | .col-sm-push-2 { 605 | left: 16.66666667%; 606 | } 607 | .col-sm-push-1 { 608 | left: 8.33333333%; 609 | } 610 | .col-sm-push-0 { 611 | left: auto; 612 | } 613 | .col-sm-offset-12 { 614 | margin-left: 100%; 615 | } 616 | .col-sm-offset-11 { 617 | margin-left: 91.66666667%; 618 | } 619 | .col-sm-offset-10 { 620 | margin-left: 83.33333333%; 621 | } 622 | .col-sm-offset-9 { 623 | margin-left: 75%; 624 | } 625 | .col-sm-offset-8 { 626 | margin-left: 66.66666667%; 627 | } 628 | .col-sm-offset-7 { 629 | margin-left: 58.33333333%; 630 | } 631 | .col-sm-offset-6 { 632 | margin-left: 50%; 633 | } 634 | .col-sm-offset-5 { 635 | margin-left: 41.66666667%; 636 | } 637 | .col-sm-offset-4 { 638 | margin-left: 33.33333333%; 639 | } 640 | .col-sm-offset-3 { 641 | margin-left: 25%; 642 | } 643 | .col-sm-offset-2 { 644 | margin-left: 16.66666667%; 645 | } 646 | .col-sm-offset-1 { 647 | margin-left: 8.33333333%; 648 | } 649 | .col-sm-offset-0 { 650 | margin-left: 0%; 651 | } 652 | } 653 | @media (min-width: 992px) { 654 | .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { 655 | float: left; 656 | } 657 | .col-md-12 { 658 | width: 100%; 659 | } 660 | .col-md-11 { 661 | width: 91.66666667%; 662 | } 663 | .col-md-10 { 664 | width: 83.33333333%; 665 | } 666 | .col-md-9 { 667 | width: 75%; 668 | } 669 | .col-md-8 { 670 | width: 66.66666667%; 671 | } 672 | .col-md-7 { 673 | width: 58.33333333%; 674 | } 675 | .col-md-6 { 676 | width: 50%; 677 | } 678 | .col-md-5 { 679 | width: 41.66666667%; 680 | } 681 | .col-md-4 { 682 | width: 33.33333333%; 683 | } 684 | .col-md-3 { 685 | width: 25%; 686 | } 687 | .col-md-2 { 688 | width: 16.66666667%; 689 | } 690 | .col-md-1 { 691 | width: 8.33333333%; 692 | } 693 | .col-md-pull-12 { 694 | right: 100%; 695 | } 696 | .col-md-pull-11 { 697 | right: 91.66666667%; 698 | } 699 | .col-md-pull-10 { 700 | right: 83.33333333%; 701 | } 702 | .col-md-pull-9 { 703 | right: 75%; 704 | } 705 | .col-md-pull-8 { 706 | right: 66.66666667%; 707 | } 708 | .col-md-pull-7 { 709 | right: 58.33333333%; 710 | } 711 | .col-md-pull-6 { 712 | right: 50%; 713 | } 714 | .col-md-pull-5 { 715 | right: 41.66666667%; 716 | } 717 | .col-md-pull-4 { 718 | right: 33.33333333%; 719 | } 720 | .col-md-pull-3 { 721 | right: 25%; 722 | } 723 | .col-md-pull-2 { 724 | right: 16.66666667%; 725 | } 726 | .col-md-pull-1 { 727 | right: 8.33333333%; 728 | } 729 | .col-md-pull-0 { 730 | right: auto; 731 | } 732 | .col-md-push-12 { 733 | left: 100%; 734 | } 735 | .col-md-push-11 { 736 | left: 91.66666667%; 737 | } 738 | .col-md-push-10 { 739 | left: 83.33333333%; 740 | } 741 | .col-md-push-9 { 742 | left: 75%; 743 | } 744 | .col-md-push-8 { 745 | left: 66.66666667%; 746 | } 747 | .col-md-push-7 { 748 | left: 58.33333333%; 749 | } 750 | .col-md-push-6 { 751 | left: 50%; 752 | } 753 | .col-md-push-5 { 754 | left: 41.66666667%; 755 | } 756 | .col-md-push-4 { 757 | left: 33.33333333%; 758 | } 759 | .col-md-push-3 { 760 | left: 25%; 761 | } 762 | .col-md-push-2 { 763 | left: 16.66666667%; 764 | } 765 | .col-md-push-1 { 766 | left: 8.33333333%; 767 | } 768 | .col-md-push-0 { 769 | left: auto; 770 | } 771 | .col-md-offset-12 { 772 | margin-left: 100%; 773 | } 774 | .col-md-offset-11 { 775 | margin-left: 91.66666667%; 776 | } 777 | .col-md-offset-10 { 778 | margin-left: 83.33333333%; 779 | } 780 | .col-md-offset-9 { 781 | margin-left: 75%; 782 | } 783 | .col-md-offset-8 { 784 | margin-left: 66.66666667%; 785 | } 786 | .col-md-offset-7 { 787 | margin-left: 58.33333333%; 788 | } 789 | .col-md-offset-6 { 790 | margin-left: 50%; 791 | } 792 | .col-md-offset-5 { 793 | margin-left: 41.66666667%; 794 | } 795 | .col-md-offset-4 { 796 | margin-left: 33.33333333%; 797 | } 798 | .col-md-offset-3 { 799 | margin-left: 25%; 800 | } 801 | .col-md-offset-2 { 802 | margin-left: 16.66666667%; 803 | } 804 | .col-md-offset-1 { 805 | margin-left: 8.33333333%; 806 | } 807 | .col-md-offset-0 { 808 | margin-left: 0%; 809 | } 810 | } 811 | @media (min-width: 1200px) { 812 | .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { 813 | float: left; 814 | } 815 | .col-lg-12 { 816 | width: 100%; 817 | } 818 | .col-lg-11 { 819 | width: 91.66666667%; 820 | } 821 | .col-lg-10 { 822 | width: 83.33333333%; 823 | } 824 | .col-lg-9 { 825 | width: 75%; 826 | } 827 | .col-lg-8 { 828 | width: 66.66666667%; 829 | } 830 | .col-lg-7 { 831 | width: 58.33333333%; 832 | } 833 | .col-lg-6 { 834 | width: 50%; 835 | } 836 | .col-lg-5 { 837 | width: 41.66666667%; 838 | } 839 | .col-lg-4 { 840 | width: 33.33333333%; 841 | } 842 | .col-lg-3 { 843 | width: 25%; 844 | } 845 | .col-lg-2 { 846 | width: 16.66666667%; 847 | } 848 | .col-lg-1 { 849 | width: 8.33333333%; 850 | } 851 | .col-lg-pull-12 { 852 | right: 100%; 853 | } 854 | .col-lg-pull-11 { 855 | right: 91.66666667%; 856 | } 857 | .col-lg-pull-10 { 858 | right: 83.33333333%; 859 | } 860 | .col-lg-pull-9 { 861 | right: 75%; 862 | } 863 | .col-lg-pull-8 { 864 | right: 66.66666667%; 865 | } 866 | .col-lg-pull-7 { 867 | right: 58.33333333%; 868 | } 869 | .col-lg-pull-6 { 870 | right: 50%; 871 | } 872 | .col-lg-pull-5 { 873 | right: 41.66666667%; 874 | } 875 | .col-lg-pull-4 { 876 | right: 33.33333333%; 877 | } 878 | .col-lg-pull-3 { 879 | right: 25%; 880 | } 881 | .col-lg-pull-2 { 882 | right: 16.66666667%; 883 | } 884 | .col-lg-pull-1 { 885 | right: 8.33333333%; 886 | } 887 | .col-lg-pull-0 { 888 | right: auto; 889 | } 890 | .col-lg-push-12 { 891 | left: 100%; 892 | } 893 | .col-lg-push-11 { 894 | left: 91.66666667%; 895 | } 896 | .col-lg-push-10 { 897 | left: 83.33333333%; 898 | } 899 | .col-lg-push-9 { 900 | left: 75%; 901 | } 902 | .col-lg-push-8 { 903 | left: 66.66666667%; 904 | } 905 | .col-lg-push-7 { 906 | left: 58.33333333%; 907 | } 908 | .col-lg-push-6 { 909 | left: 50%; 910 | } 911 | .col-lg-push-5 { 912 | left: 41.66666667%; 913 | } 914 | .col-lg-push-4 { 915 | left: 33.33333333%; 916 | } 917 | .col-lg-push-3 { 918 | left: 25%; 919 | } 920 | .col-lg-push-2 { 921 | left: 16.66666667%; 922 | } 923 | .col-lg-push-1 { 924 | left: 8.33333333%; 925 | } 926 | .col-lg-push-0 { 927 | left: auto; 928 | } 929 | .col-lg-offset-12 { 930 | margin-left: 100%; 931 | } 932 | .col-lg-offset-11 { 933 | margin-left: 91.66666667%; 934 | } 935 | .col-lg-offset-10 { 936 | margin-left: 83.33333333%; 937 | } 938 | .col-lg-offset-9 { 939 | margin-left: 75%; 940 | } 941 | .col-lg-offset-8 { 942 | margin-left: 66.66666667%; 943 | } 944 | .col-lg-offset-7 { 945 | margin-left: 58.33333333%; 946 | } 947 | .col-lg-offset-6 { 948 | margin-left: 50%; 949 | } 950 | .col-lg-offset-5 { 951 | margin-left: 41.66666667%; 952 | } 953 | .col-lg-offset-4 { 954 | margin-left: 33.33333333%; 955 | } 956 | .col-lg-offset-3 { 957 | margin-left: 25%; 958 | } 959 | .col-lg-offset-2 { 960 | margin-left: 16.66666667%; 961 | } 962 | .col-lg-offset-1 { 963 | margin-left: 8.33333333%; 964 | } 965 | .col-lg-offset-0 { 966 | margin-left: 0%; 967 | } 968 | } 969 | .clearfix:before, 970 | .clearfix:after, 971 | .container:before, 972 | .container:after, 973 | .container-fluid:before, 974 | .container-fluid:after, 975 | .row:before, 976 | .row:after { 977 | content: " "; 978 | display: table; 979 | } 980 | .clearfix:after, 981 | .container:after, 982 | .container-fluid:after, 983 | .row:after { 984 | clear: both; 985 | } 986 | .center-block { 987 | display: block; 988 | margin-left: auto; 989 | margin-right: auto; 990 | } 991 | .pull-right { 992 | float: right !important; 993 | } 994 | .pull-left { 995 | float: left !important; 996 | } 997 | .hide { 998 | display: none !important; 999 | } 1000 | .show { 1001 | display: block !important; 1002 | } 1003 | .invisible { 1004 | visibility: hidden; 1005 | } 1006 | .text-hide { 1007 | font: 0/0 a; 1008 | color: transparent; 1009 | text-shadow: none; 1010 | background-color: transparent; 1011 | border: 0; 1012 | } 1013 | .hidden { 1014 | display: none !important; 1015 | } 1016 | .affix { 1017 | position: fixed; 1018 | } 1019 | -------------------------------------------------------------------------------- /server/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Paint Online 8 | 9 | 12 | 13 | 14 | 15 | 16 |
17 |

实时「你画我猜」

18 |
19 |
20 |
21 |
22 | 23 | Sorry, Your Browser don't support canvas of Html5. 24 | 25 |
26 |
27 | 颜色 28 |
29 |
30 | 线宽 31 | 32 | 1 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 |
69 |
70 |

排行榜

71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | 87 |
88 |
89 |

消息框

90 |
91 |
92 | 93 |
94 |
95 |
96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /server/static/io.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Yc on 2016/5/22. 3 | */ 4 | var socket = io.connect(); 5 | socket.on('server msg',function (data) { 6 | var ele = document.createElement('p'); 7 | ele.innerHTML = data; 8 | msg.appendChild(ele); 9 | msg.scrollTop = msg.scrollHeight; 10 | }) 11 | socket.on('login',function () { 12 | if(prompt) 13 | socket.emit('login',prompt('输入你的姓名')); 14 | else 15 | socket.emit('login','手机用户'); 16 | btnIn.outAct(); 17 | canvas.isMe = false; 18 | btnAutoin.disalbed = false; 19 | }); 20 | socket.on('paint paths',function (paths) { 21 | paths = JSON.parse(paths); 22 | ctx.clearRect(0,0,canvas.width,canvas.height); 23 | for(var k in paths) { 24 | if(paths[k].tag==='pts') 25 | Ctl.drawPts(ctx, paths[k]); 26 | else{ 27 | new Rect(paths[k].x,paths[k].y,paths[k].w,paths[k].h).clearOn(ctx); 28 | } 29 | } 30 | }); 31 | socket.on('paint pts',function (pts) { 32 | //canvas.paths = paths; 33 | pts = JSON.parse(pts) 34 | if(!pts) return; 35 | Ctl.drawPts(ctx, pts); 36 | }); 37 | socket.on('cmd',function (data) { 38 | console.log(JSON.parse(data)); 39 | }); 40 | socket.on('reset in users',function (data) { 41 | data = JSON.parse(data); 42 | /* 43 | [ 44 | {name: '', in:true} 45 | ] 46 | */ 47 | users.innerHTML = ''; 48 | data.forEach(x=>{ 49 | users.appendChild(utils.makeUserP(x)); 50 | }); 51 | }) 52 | socket.on('erase',function (x,y,w,h) { 53 | new Rect(x,y,w,h).clearOn(ctx); 54 | }) 55 | socket.on('new in user',function (data) { 56 | users.appendChild(utils.makeUserP(JSON.parse(data))); 57 | }); 58 | socket.on('out user',function (id) { 59 | var x = users.querySelector('#p'+id); 60 | if(x) x.outerHTML=''; 61 | }) 62 | socket.on('in',function (data) { 63 | users.appendChild(utils.makeUserP(JSON.parse(data))); 64 | users.scrollTop = users.scrollHeight; 65 | btnIn.inAct(); 66 | }); 67 | socket.on('out',function (id) { 68 | var x = users.querySelector('#p'+id); 69 | if(x){ 70 | x.outerHTML=''; 71 | btnIn.outAct(); 72 | } 73 | }); 74 | 75 | socket.on('mytime',function (data) { 76 | data = JSON.parse(data);// name,word:,time 77 | btnIn.disabled = true; 78 | info.player.innerText = data.name + '(自己)'; 79 | info.time.innerText = data.time +'s'; 80 | info.word.innerText = data.word; 81 | canvas.isMe = true; 82 | }); 83 | socket.on('othertime',function (data) { 84 | data = JSON.parse(data);// name,word:,time 85 | info.player.innerText = data.name; 86 | info.time.innerText = data.time +'s'; 87 | canvas.isMe = false; 88 | }); 89 | socket.on('update time',function (data) { 90 | data = JSON.parse(data); 91 | info.player.innerText = data.name; 92 | info.time.innerText = data.time +'s'; 93 | info.word.innerText = data.word; 94 | }); 95 | socket.on('update my time',function (data) { 96 | data = JSON.parse(data); 97 | info.time.innerText = data.time +'s'; 98 | }); 99 | socket.on('mytimeout',function (id) { 100 | var t = users.querySelector('#p'+id); 101 | if(t) t.outerHTML=''; 102 | info.time.innerText = '时间到了!'; 103 | canvas.isMe = false; 104 | btnIn.outAct(); 105 | }); 106 | socket.on('timeout',function (d) { 107 | d = JSON.parse(d); 108 | var t = users.querySelector('#p'+d.id); 109 | if(t) t.outerHTML=''; 110 | info.time.innerText = '时间到了!'; 111 | info.word.innerText = '正确答案为:'+d.word; 112 | }); 113 | socket.on('clear paint',function () { 114 | ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 115 | }); 116 | socket.on('tops',function (d) { 117 | d = JSON.parse(d); 118 | tops.innerHTML = ''; 119 | var temp = tops.template; 120 | d.forEach((x,i)=>{ 121 | temp.id = x.id; 122 | temp.children[0].firstElementChild.innerText = 'No'+(i+1); 123 | temp.children[1].firstElementChild.innerText = x.name; 124 | temp.children[2].firstElementChild.innerText = x.v+'次'; 125 | 126 | var node = tops.template.cloneNode(true); 127 | node.removeAttribute('role'); 128 | tops.appendChild(node); 129 | }); 130 | }) 131 | utils = { 132 | makeUserP : function (x) { 133 | var p = document.createElement('p'); p.id = 'p'+x.id; 134 | p.innerText = x.name; 135 | return p; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /server/static/js.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Yc on 2016/5/17. 3 | */ 4 | 5 | var canvas = document.getElementsByTagName('canvas')[0], 6 | ctx = canvas.getContext('2d'), 7 | msg = document.getElementById('msg'), 8 | ranger = document.getElementById('ranger'), 9 | colors = document.getElementById('colors'); 10 | 11 | var input = document.getElementById('input-msg'), 12 | users = document.getElementById('div-users'), 13 | btnIn = document.getElementById('btn-in'), 14 | btnAutoin = document.getElementById('btn-autoin'), 15 | info = document.getElementById('info'), 16 | tops = document.getElementById('tops'); 17 | btnIn.inAct = function () { 18 | this.innerText='下场'; 19 | this.in=true; 20 | }; 21 | btnIn.outAct = function () { 22 | this.innerText='上场!'; 23 | this.in=false; 24 | this.disabled = false; 25 | }; 26 | tops.template = tops.querySelector('[role=template]').cloneNode(true); 27 | 28 | info.time = info.querySelector('#time') 29 | info.player = info.querySelector('#player') 30 | info.word = info.querySelector('#word') 31 | btnAutoin.addEventListener('click',function (e) { 32 | var btnin = btnIn; 33 | if(btnin.autoIn == null){ 34 | // btnin.outAct(); 35 | if(!btnin.in) socket.emit('in'); 36 | btnin.autoIn = setInterval(function () { 37 | if(canvas.isMe) return; 38 | if(!btnin.in) socket.emit('in'); 39 | },5000); 40 | }else{ 41 | clearInterval(btnin.autoIn); 42 | delete btnin.autoIn; 43 | } 44 | this.classList.toggle('on'); 45 | }); 46 | btnIn.addEventListener('click',function () { 47 | var t = this.in; 48 | if(this.t) clearTimeout(this.t); 49 | this.t = setTimeout(function () { 50 | socket.emit(!t?'in':'out'); 51 | },400); 52 | }) 53 | 54 | window.onload = function () { 55 | Ctl.init(); 56 | function resize() { 57 | canvas.width = canvas.parentElement.clientWidth; 58 | canvas.paths = canvas.pts = []; 59 | socket.emit('repaint'); 60 | } 61 | this.addEventListener('resize',resize); 62 | resize(); 63 | input.onkeydown = function (e) { 64 | if(e.keyCode === 13 && this.value!=''){ 65 | if(canvas.isMe){ 66 | alert('绘图者不能够发送消息!'); 67 | return; 68 | } 69 | socket.emit('client msg',this.value); 70 | this.value = ''; 71 | } 72 | } 73 | document.querySelector('#btns').addEventListener('click',function (e) { 74 | if(e.target.classList.contains('btn-active-able')){ 75 | if(this.prevBtn){ 76 | this.prevBtn.classList.remove('active') 77 | } 78 | e.target.classList.add('active') 79 | this.prevBtn = e.target; 80 | } 81 | },true); 82 | } 83 | 84 | canvas.addEventListener('mousemove',function (e) { 85 | var w=20,h=20; 86 | if(canvas.isMe){ 87 | var x = e.offsetX, y = e.offsetY; 88 | if(e.buttons === 1) { 89 | if(!this.erase){ 90 | Ctl.addPos(x,y); 91 | Ctl.drawPts(ctx, this.pts); 92 | socket.emit('paint',JSON.stringify({data:new Path(this.pts),status:'ing'})) 93 | }else{ 94 | var rect = new Rect(x-(w>>>1),y-(h>>>1),w,h); 95 | rect.clearOn(ctx); 96 | socket.emit('erase',rect.x,rect.y,rect.w,rect.h); 97 | } 98 | } 99 | } 100 | }); 101 | 102 | canvas.addEventListener('mouseup',function (e) { 103 | if(!canvas.isMe || this.erase) return; 104 | var x = e.offsetX,y = e.offsetY; 105 | Ctl.addPos(x,y); 106 | Ctl.addPath(this.pts); 107 | socket.emit('paint',JSON.stringify({data:new Path(this.pts),status:'end'})); 108 | Ctl.clearPos(); 109 | 110 | }) 111 | 112 | canvas.addEventListener('mousedown',function (e) { 113 | if(!this.isMe) return; 114 | if(this.erase){ 115 | var w=20,h=20; 116 | var rect = new Rect(x-(w>>>1),y-(h>>>1),w,h); 117 | rect.clearOn(ctx); 118 | socket.emit('erase',rect.x,rect.y,rect.w,rect.h); 119 | return; 120 | } 121 | var x = e.offsetX,y = e.offsetY; 122 | Ctl.clearPos(); 123 | Ctl.addPos(x,y); 124 | }); 125 | colors.addEventListener('click',function (e) { 126 | var t = e.target; 127 | if(t.classList.contains('rect')){ 128 | Array.prototype.slice.call(this.getElementsByClassName('active')) 129 | .forEach(v=>v.classList.remove('active')); 130 | t.classList.add('active'); 131 | Ctl.setColor(t.style.backgroundColor); 132 | } 133 | }); 134 | ranger.addEventListener('change',function (e) { 135 | this.nextElementSibling.innerText = this.value; 136 | Ctl.setLw(this.value); 137 | }); 138 | 139 | // Controller 140 | Ctl = { 141 | drawPts: function (ctx,pts) { 142 | if(pts instanceof Path || pts.pts){ 143 | var color = pts.color,lw = pts.lw; 144 | pts = pts.pts; 145 | } 146 | var p1 = pts[0]; 147 | ctx.save(); 148 | ctx.beginPath(); 149 | ctx.moveTo(p1.x, p1.y); 150 | pts.slice(1).forEach(v=>{ 151 | ctx.lineTo(v.x,v.y); 152 | }); 153 | ctx.lineWidth = lw || canvas.lw 154 | ctx.strokeStyle = color || canvas.color; 155 | ctx.stroke(); 156 | ctx.restore(); 157 | }, 158 | init : function () { 159 | canvas.paths=[]; 160 | canvas.pts=[]; 161 | canvas.color = 'black'; 162 | canvas.lw = 1; 163 | for(var i=0;i<20;i++) 164 | this.addColor(); 165 | }, 166 | setLw(lw){ 167 | canvas.lw = lw; 168 | }, 169 | setColor(c){ 170 | canvas.color = c; 171 | }, 172 | addPath : function (pts) { 173 | canvas.paths.push(new Path(pts,canvas.lw,canvas.color)); 174 | }, 175 | addPos : function (x,y) { 176 | canvas.pts.push(new Pos(x,y)); 177 | }, 178 | clearPos : function () { 179 | canvas.pts = [] 180 | }, 181 | addColor : function (active) { 182 | var rect = document.createElement('div'),r = this.random; 183 | rect.className = 'rect'; 184 | if(active) 185 | rect.className+=' active'; 186 | rect.style.backgroundColor = 'rgb('+[r(256),r(256),r(256)].join(',')+')'; 187 | colors.appendChild(rect); 188 | }, 189 | random : function (b) { 190 | return Math.floor(Math.random()*b); 191 | } 192 | }; 193 | 194 | // webSocket 195 | /* 196 | var ws = WS({ 197 | path:'ws', 198 | onOpen:function (e) { 199 | alert('OK'); 200 | }, 201 | onError:function (e) { 202 | // alert(e.message) 203 | alert('Error'); 204 | }, 205 | onReceive:function (data,t) { 206 | 207 | }, 208 | onClose:function (e) { 209 | alert('Close'); 210 | } 211 | });*/ 212 | 213 | 214 | 215 | // model 216 | 217 | function Pos(x,y) { 218 | this.x=x;this.y=y; 219 | } 220 | 221 | function Path(pts,lw,color) { 222 | this.pts = pts; 223 | this.lw = lw || canvas.lw; 224 | this.color = color || canvas.color; 225 | } 226 | 227 | function Rect(x,y,w,h) { 228 | this.x=x;this.y=y;this.w=w;this.h=h; 229 | } 230 | 231 | 232 | Rect.prototype.clearOn = function (ctx) { 233 | ctx.clearRect(this.x,this.y,this.w,this.h); 234 | } 235 | -------------------------------------------------------------------------------- /server/static/style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0; 3 | padding: 0; 4 | font-family: 微软雅黑Arial, Arial, sans-serif; 5 | box-sizing: border-box; 6 | } 7 | body{ 8 | touch-action: none; 9 | } 10 | canvas{ 11 | cursor: crosshair; 12 | } 13 | h1,h2,h3{ 14 | text-align: center; 15 | margin: 10px 4px 20px; 16 | } 17 | h4,h5,h6{ 18 | text-align: center; 19 | padding: 8px 0 8px; 20 | border-bottom: 1px solid #eee; 21 | } 22 | .container{ 23 | margin-right: auto; 24 | margin-left: auto; 25 | padding-left: 15px; 26 | padding-right: 15px; 27 | } 28 | .margin-none{ 29 | margin: 0; 30 | } 31 | .col-6{ 32 | width: 60%; 33 | } 34 | .col-7{ 35 | width: 70%; 36 | } 37 | .col-3{ 38 | width: 30%; 39 | } 40 | .col-1{ 41 | width: 10%; 42 | } 43 | .col-2{ 44 | width: 20%; 45 | } 46 | .col-3{ 47 | width: 30%; 48 | } 49 | .col-4{ 50 | width: 40%; 51 | } 52 | .col-9{ 53 | width: 90%; 54 | } 55 | .col-8{ 56 | width: 80%; 57 | } 58 | .row{ 59 | margin-right: -15px; 60 | margin-left: -15px; 61 | } 62 | .row:before, 63 | .row:after { 64 | content: " "; 65 | display: table; 66 | } 67 | .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9{ 68 | padding-left: 15px; 69 | padding-right: 15px; 70 | float: left; 71 | } 72 | .row:after { 73 | clear: both; 74 | } 75 | .text-blue { 76 | color: cornflowerblue; 77 | } 78 | .fl{ 79 | float: left; 80 | } 81 | .fr{ 82 | float: right; 83 | } 84 | .mid{ 85 | vertical-align: middle; 86 | } 87 | .active{ 88 | border: 3px solid fuchsia !important; 89 | } 90 | .btn{ 91 | display: inline-block; 92 | border: none; 93 | cursor: pointer; 94 | padding: 5px; 95 | margin: 4px; 96 | border-radius: 3px; 97 | } 98 | .btn:hover{ 99 | box-shadow: 0px 0px 3px 3px #bbb; 100 | } 101 | .btn-blue{ 102 | background-color: cornflowerblue; 103 | color: azure; 104 | } 105 | 106 | .on{ 107 | border: solid 2px hotpink; 108 | opacity: .6; 109 | } 110 | a{ 111 | text-decoration: none; 112 | font-size: 14px; 113 | } 114 | .rect{ 115 | display: inline-block; 116 | width: 20px; 117 | height: 20px; 118 | border: 3px solid black; 119 | text-align: center; 120 | margin:0 2px 0; 121 | cursor: pointer; 122 | } 123 | .ctl-row{ 124 | border: 1px solid darkgreen; 125 | background-color: beige; 126 | padding-top:5px; 127 | padding-bottom: 5px; 128 | border-radius: 6px; 129 | margin: 2px 0 2px; 130 | } 131 | 132 | .box-sh{ 133 | box-shadow: 0px 0px 8px 3px #bbb; 134 | } 135 | 136 | .text-center{ 137 | text-align: center; 138 | } 139 | 140 | #msg{ 141 | overflow-y: scroll; 142 | padding: 0 10px 0; 143 | /*width: 100%;*/ 144 | min-height: 400px; 145 | max-height: 600px; 146 | } 147 | #msg p{ 148 | white-space:nowrap; 149 | } 150 | #info p{ 151 | line-height: 30px; 152 | } 153 | #div-users p{ 154 | margin-left: 2em; 155 | } 156 | input[type=range]{cursor: pointer;} 157 | input[type=text]{ 158 | height: 20px; 159 | font-size: 16px; 160 | margin: 5px; 161 | width: 90%; 162 | } 163 | button[disabled]{ 164 | opacity: .6; 165 | cursor: not-allowed; 166 | } 167 | table{ 168 | margin-top: 10px; 169 | width: 100%; 170 | border-collapse:collapse; 171 | } 172 | 173 | table tr:nth-child(2n){ 174 | background-color: gainsboro; 175 | } 176 | .table-responsive{ 177 | overflow-x: auto; 178 | overflow-y: scroll; 179 | max-height: 150px; 180 | } 181 | td{ 182 | padding: 4px 8px 4px; 183 | white-space: nowrap; 184 | } 185 | *[role=template]{ 186 | display: none; 187 | } -------------------------------------------------------------------------------- /server/words.txt: -------------------------------------------------------------------------------- 1 | 白鸽,动物 2 | 布娃娃,玩具 3 | 餐巾,生活用品 4 | CD,娱乐用品 5 | 瓷器,易碎 6 | 长江三峡,伟大的工程 7 | 长颈漏斗,化学器材 8 | 赤壁,一个地方 9 | 除草剂,喷剂 10 | 大头鱼,yyf 11 | 刀,很危险的东西 12 | 豆沙包,甜的吃的 13 | 耳机,电子用品 14 | 飞碟,很难看到 15 | 荷花,朱自清 16 | 虎,女人 17 | 蝴蝶,庞龙 18 | 护膝,运动保护 19 | 花朵,形容小朋友 20 | 环保,可持续发展 21 | 欢乐谷,小朋友的天堂 22 | 击剑,运动 23 | 教师,令人尊敬 24 | KTV,释放压力 25 | 老爷车 26 | 刘翔 27 | 落地灯 28 | 棉花 29 | 母亲 30 | NBA 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 | 钻戒 --------------------------------------------------------------------------------