Tadpole.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. var Tadpole = function() {
  2. var tadpole = this;
  3. this.x = Math.random() * 300 - 150;
  4. this.y = Math.random() * 300 - 150;
  5. this.size = 4;
  6. this.name = '';
  7. this.age = 0;
  8. this.hover = false;
  9. this.momentum = 0;
  10. this.maxMomentum = 3;
  11. this.angle = Math.PI * 2;
  12. this.targetX = 0;
  13. this.targetY = 0;
  14. this.targetMomentum = 0;
  15. this.messages = [];
  16. this.timeSinceLastActivity = 0;
  17. this.changed = 0;
  18. this.timeSinceLastServerUpdate = 0;
  19. this.update = function(mouse) {
  20. tadpole.timeSinceLastServerUpdate++;
  21. tadpole.x += Math.cos(tadpole.angle) * tadpole.momentum;
  22. tadpole.y += Math.sin(tadpole.angle) * tadpole.momentum;
  23. if(tadpole.targetX != 0 || tadpole.targetY != 0) {
  24. tadpole.x += (tadpole.targetX - tadpole.x) / 20;
  25. tadpole.y += (tadpole.targetY - tadpole.y) / 20;
  26. }
  27. // Update messages
  28. for (var i = tadpole.messages.length - 1; i >= 0; i--) {
  29. var msg = tadpole.messages[i];
  30. msg.update();
  31. if(msg.age == msg.maxAge) {
  32. tadpole.messages.splice(i,1);
  33. }
  34. }
  35. // Update tadpole hover/mouse state
  36. if(Math.sqrt(Math.pow(tadpole.x - mouse.worldx,2) + Math.pow(tadpole.y - mouse.worldy,2)) < tadpole.size+2) {
  37. tadpole.hover = true;
  38. mouse.tadpole = tadpole;
  39. }
  40. else {
  41. if(mouse.tadpole && mouse.tadpole.id == tadpole.id) {
  42. //mouse.tadpole = null;
  43. }
  44. tadpole.hover = false;
  45. }
  46. tadpole.tail.update();
  47. };
  48. this.onclick = function(e) {
  49. if(e.ctrlKey && e.which == 1) {
  50. if(isAuthorized() && tadpole.hover) {
  51. window.open("http://twitter.com/" + tadpole.name.substring(1));
  52. return true;
  53. }
  54. }
  55. else if(e.which == 2) {
  56. //todo:open menu
  57. e.preventDefault();
  58. return true;
  59. }
  60. return false;
  61. };
  62. this.userUpdate = function(tadpoles, angleTargetX, angleTargetY) {
  63. this.age++;
  64. var prevState = {
  65. angle: tadpole.angle,
  66. momentum: tadpole.momentum,
  67. }
  68. // Angle to targetx and targety (mouse position)
  69. var anglediff = ((Math.atan2(angleTargetY - tadpole.y, angleTargetX - tadpole.x)) - tadpole.angle);
  70. while(anglediff < -Math.PI) {
  71. anglediff += Math.PI * 2;
  72. }
  73. while(anglediff > Math.PI) {
  74. anglediff -= Math.PI * 2;
  75. }
  76. tadpole.angle += anglediff / 5;
  77. // Momentum to targetmomentum
  78. if(tadpole.targetMomentum != tadpole.momentum) {
  79. tadpole.momentum += (tadpole.targetMomentum - tadpole.momentum) / 20;
  80. }
  81. if(tadpole.momentum < 0) {
  82. tadpole.momentum = 0;
  83. }
  84. tadpole.changed += Math.abs((prevState.angle - tadpole.angle)*3) + tadpole.momentum;
  85. if(tadpole.changed > 1) {
  86. this.timeSinceLastServerUpdate = 0;
  87. }
  88. };
  89. this.draw = function(context) {
  90. var opacity = Math.max(Math.min(20 / Math.max(tadpole.timeSinceLastServerUpdate-300,1),1),.2).toFixed(3);
  91. if(tadpole.hover && isAuthorized()) {
  92. context.fillStyle = 'rgba(192, 253, 247,'+opacity+')';
  93. // context.shadowColor = 'rgba(249, 136, 119, '+opacity*0.7+')';
  94. }
  95. else {
  96. context.fillStyle = 'rgba(226,219,226,'+opacity+')';
  97. }
  98. context.shadowOffsetX = 0;
  99. context.shadowOffsetY = 0;
  100. context.shadowBlur = 6;
  101. context.shadowColor = 'rgba(255, 255, 255, '+opacity*0.7+')';
  102. // Draw circle
  103. context.beginPath();
  104. context.arc(tadpole.x, tadpole.y, tadpole.size, tadpole.angle + Math.PI * 2.7, tadpole.angle + Math.PI * 1.3, true);
  105. tadpole.tail.draw(context);
  106. context.closePath();
  107. context.fill();
  108. context.shadowBlur = 0;
  109. context.shadowColor = '';
  110. drawName(context);
  111. drawMessages(context);
  112. };
  113. var isAuthorized = function() {
  114. return tadpole.name.charAt('0') == "@";
  115. };
  116. var drawName = function(context) {
  117. var opacity = Math.max(Math.min(20 / Math.max(tadpole.timeSinceLastServerUpdate-300,1),1),.2).toFixed(3);
  118. context.fillStyle = 'rgba(226,219,226,'+opacity+')';
  119. context.font = 7 + "px 'proxima-nova-1','proxima-nova-2', arial, sans-serif";
  120. context.textBaseline = 'hanging';
  121. var width = context.measureText(tadpole.name).width;
  122. context.fillText(tadpole.name, tadpole.x - width/2, tadpole.y + 8);
  123. }
  124. var drawMessages = function(context) {
  125. tadpole.messages.reverse();
  126. for(var i = 0, len = tadpole.messages.length; i<len; i++) {
  127. tadpole.messages[i].draw(context, tadpole.x+10, tadpole.y+5, i);
  128. }
  129. tadpole.messages.reverse();
  130. };
  131. // Constructor
  132. (function() {
  133. tadpole.tail = new TadpoleTail(tadpole);
  134. })();
  135. }