PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/views/index.html

https://bitbucket.org/mpuckett/iostudio-whiteboard
HTML | 339 lines | 282 code | 45 blank | 12 comment | 0 complexity | dd795700fdc696557d6680ca5a489502 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, MIT
  1. <!DOCTYPE html>
  2. <!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
  3. <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
  4. <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
  5. <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
  6. <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
  7. <head>
  8. <meta charset="utf-8" />
  9. <!-- Set the viewport width to device width for mobile -->
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Welcome to Foundation</title>
  12. <!-- Included CSS Files -->
  13. <link rel="stylesheet" href="/stylesheets/app.css">
  14. <script src="/scripts/foundation/modernizr.foundation.js"></script>
  15. <!-- IE Fix for HTML5 Tags -->
  16. <!--[if lt IE 9]>
  17. <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  18. <![endif]-->
  19. </head>
  20. <body>
  21. <nav class="top-bar fixed">
  22. <ul>
  23. <ul>
  24. <li class="name"><h1><a href="#">whiteboard!</a></h1></li>
  25. <li class="toggle-topbar"><a href="#"></a></li>
  26. </ul>
  27. </ul>
  28. </nav>
  29. <div class="row">
  30. <div class="twelve columns">
  31. <div class="row">
  32. <div class="three columns">
  33. <div class="row">
  34. <div class="twelve columns">
  35. <h2>Users</h2>
  36. <ul id="users-list"></ul>
  37. <h2>Files</h2>
  38. <ul id="files-list"></ul>
  39. </div>
  40. </div>
  41. </div>
  42. <div class="nine columns">
  43. <video class="th" autoplay="true" id="webcam">
  44. </video>
  45. <canvas id="webcam-feed"></canvas>
  46. <form id="chat">
  47. <h2>Chat <a id="request-chat-notifications-permission" class="hide" href="#">(Click for Growl-like Notifications!)</a></h2>
  48. <ul id="chat-messages-list"></ul>
  49. <div class="chat-box">
  50. <input type="text" placeholder="Message Here...">
  51. </div>
  52. </form>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. <!--<script src="http://d3js.org/d3.v2.js"></script>
  58. <svg id="main" draggable="true"></svg>-->
  59. <script id="template-file" type="text/handlebars">
  60. <li id="file-{{id}}" data-id="{{id}}">
  61. <a href="/files/{{name}}" download="{{name}}">
  62. <div>
  63. {{name}} ({{user}} at {{timestamp}})
  64. </div>
  65. </a>
  66. </li>
  67. </script>
  68. <script id="template-user" type="text/handlebars">
  69. <li id="user-{{id}}" data-id="{{id}}" class="user {{#self}}self{{/self}}">
  70. <div class="{{#self}}callout{{/self}}">
  71. {{#image}}
  72. <a class="th">
  73. <img src="{{image.data}}">
  74. </a>
  75. {{/image}}
  76. <span class="name">{{name}}</span></div>
  77. </li>
  78. </script>
  79. <script id="template-chat-message" type="text/handlebars">
  80. <li id="message-{{id}}" data-id="{{id}}" class="{{#user.self}}self{{/user.self}}"><img src="{{user.image.data}}"></img><span class="user">{{#user.self}}You{{/user.self}}{{^user.self}}{{user.name}}{{/user.self}}</span> {{#file}}<audio controls="controls"><source src="{{file}}" type="audio/mpeg"></source></audio>{{/file}} <p>{{message}}</p></li>
  81. </script>
  82. <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
  83. <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
  84. <script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
  85. <script src="//cdnjs.cloudflare.com/ajax/libs/mustache.js/0.5.0-dev/mustache.min.js"></script>
  86. <script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0.beta6/handlebars.min.js"></script>
  87. <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.10/socket.io.min.js"></script>
  88. <script>
  89. $(document).tooltips();
  90. </script>
  91. <script>
  92. Backbone.Controller = Backbone.View;
  93. Backbone.Collection.prototype.update = function (model, params) {
  94. var t = this;
  95. this.where({id:model.id})[0].edit(model, params);
  96. };
  97. Backbone.Model.prototype.update = function(model, params){
  98. var t = this;
  99. // update or add all new values
  100. _.each(model, function (value, attribute) {
  101. t.set(attribute, value);
  102. });
  103. if (!params || (params && !params.soft) ) {
  104. // if new value is missing, delete old value
  105. _.each(this.attributes, function (value, attribute) {
  106. if (!model[attribute]) {
  107. t.unset(attribute);
  108. }
  109. });
  110. }
  111. this.trigger('update', model);
  112. };
  113. var MediaCaptureView = Backbone.View.extend({
  114. el: '#webcam',
  115. elements: {
  116. feed: $('#webcam-feed').get(0)
  117. },
  118. events: {
  119. 'click': function (e) {
  120. e.preventDefault();
  121. this.trigger('_mediaCaptured', this.takePhoto() );
  122. }
  123. },
  124. takePhoto: function () {
  125. var canvas = this.elements.feed.getContext('2d');
  126. var videoWidth = this.$el.get(0).videoWidth;
  127. var videoHeight = this.$el.get(0).videoHeight;
  128. $(this.elements.feed).width( videoWidth );
  129. $(this.elements.feed).height( videoWidth );
  130. this.elements.feed.setAttribute( 'width', videoWidth );
  131. this.elements.feed.setAttribute( 'height', videoWidth );
  132. canvas.drawImage( this.$el.get(0), 0, 0 );
  133. return this.elements.feed.toDataURL();
  134. },
  135. requestCapturePermission: function (callback) {
  136. var t = this;
  137. navigator.webkitGetUserMedia({video:true,audio:true}, function (stream) {
  138. t.startStream(stream);
  139. });
  140. },
  141. startStream: function (stream) {
  142. this.$el.get(0).src = window.webkitURL.createObjectURL(stream);
  143. this.show();
  144. },
  145. stopStream: function (stream) {
  146. this.$el.get(0).src = window.webkitURL.createObjectURL(null);
  147. },
  148. show: function () {
  149. this.$el.addClass('open');
  150. },
  151. hide: function () {
  152. var t = this;
  153. this.$el.removeClass('open');
  154. navigator.webkitGetUserMedia({video:true,audio:true}, function (stream) {
  155. t.stopStream(stream);
  156. });
  157. }
  158. });
  159. var MediaController = Backbone.Controller.extend({
  160. initialize: function () {
  161. var t = this;
  162. var mediaCaptureView = this.mediaCaptureView = new MediaCaptureView();
  163. mediaCaptureView.on('_mediaCaptured', function (media) {
  164. t.trigger('_mediaCaptured', { data: media });
  165. mediaCaptureView.hide();
  166. });
  167. },
  168. capture: function () {
  169. this.mediaCaptureView.requestCapturePermission();
  170. }
  171. });
  172. </script>
  173. <script>//drawing backbone models/controller/view
  174. (function ($) {
  175. var LineModel = Backbone.Model.extend({
  176. defaults: {
  177. // socketID: 'meep',
  178. // //lineId: lineCollection.length-1,
  179. coordinates: [{'x':null,'y':null}]
  180. },
  181. initialize: function(){
  182. if (this.get('id')) {
  183. }
  184. }
  185. });
  186. var LineCollection = Backbone.Collection.extend({
  187. model: LineModel
  188. });
  189. var LineView = Backbone.View.extend({
  190. offset: $('#main').offset(),
  191. el: "#main",
  192. events :{
  193. 'dragstart': function(e){
  194. var posX = e.pageX - this.offset.left,
  195. posY = e.pageY - this.offset.top - 100,
  196. lineModel = new LineModel({coordinates:[{'x':posX,'y':posY}]});
  197. lineCollection.add(lineModel);
  198. console.log('new line model!', lineModel);
  199. console.log('line collection!', lineCollection.length, lineCollection);
  200. },
  201. 'drag': function(e){
  202. // var parentOffset = $(e.target).offset();
  203. var coordinate = {
  204. x : e.pageX - this.offset.left,
  205. y : e.pageY - this.offset.top - 100
  206. }
  207. this.trigger('_newPointsAdded', coordinate);
  208. }
  209. },
  210. renderCollection : function(){
  211. var svg = d3.select("#main");
  212. //console.log('beep!', lineCollection);
  213. _.each(lineCollection.models, function(obj){
  214. var d3line2 = d3.svg.line()
  215. .x(function(d){return d.x;})
  216. .y(function(d){return d.y;})
  217. .interpolate("cardinal");
  218. svg.append("svg:path")
  219. .attr("d", d3line2(obj.attributes.coordinates))
  220. .attr("fill", "transparent")
  221. .attr("stroke", "#aaa")
  222. .attr("stroke-width", 7);
  223. });
  224. },
  225. renderModel : function(model){
  226. var svg = d3.select("#main");
  227. var d3line2 = d3.svg.line()
  228. .x(function(d){return d.x;})
  229. .y(function(d){return d.y;})
  230. .interpolate("cardinal");
  231. svg.append("svg:path")
  232. .attr("d", d3line2(model.attributes.coordinates))
  233. .attr("fill", "transparent")
  234. .attr("stroke", "#aaa")
  235. .attr("stroke-width", 7);
  236. }
  237. });
  238. var LineController = Backbone.View.extend({
  239. initialize : function(){
  240. var lineView = new LineView();
  241. var that = this;
  242. lineView.on('_newPointsAdded', function(newCoordinate){
  243. console.log('line collection', lineCollection);
  244. var currentLineId = lineCollection.length - 1,
  245. currentLine = lineCollection.at(currentLineId),
  246. coordinates = currentLine.get('coordinates'),
  247. lastCoordinate = _.last(coordinates);
  248. if (!that.isWithinThreshold(newCoordinate, lastCoordinate)){
  249. coordinates.push({
  250. 'x': newCoordinate.x,
  251. 'y' : newCoordinate.y
  252. });
  253. currentLine.set('coordinates', coordinates);
  254. socket.emit('modelUpdate', currentLine, currentLineId);
  255. currentLine.trigger('change:coordinates', currentLine);
  256. //console.log('current line', currentLine);
  257. }
  258. });
  259. lineCollection.on('change:coordinates', function(model){
  260. lineView.renderModel(model);
  261. });
  262. lineCollection.on('add', function (model) {
  263. //socket.emit('newLine', model.toJSON() );
  264. //lineView.render();
  265. });
  266. /*lineCollection.on('change:coordinates', function(model){
  267. console.log('change', model.toJSON());
  268. socket.emit('newLineCoordinate', model.toJSON());
  269. //lineView.render();
  270. });*/
  271. },
  272. isWithinThreshold : function(newCoordinate, lastCoordinate){
  273. var threshold = 2;
  274. if ((newCoordinate.x < lastCoordinate.x+threshold && newCoordinate.x > lastCoordinate.x-threshold) || (newCoordinate.y < lastCoordinate.y+threshold && newCoordinate.y > lastCoordinate.y-threshold))
  275. {
  276. return true;
  277. }
  278. else{
  279. return false;
  280. }
  281. }
  282. });
  283. //offset = $('#main').offset();
  284. lineCollection = new LineCollection();
  285. var lineController = new LineController();
  286. })(jQuery);
  287. </script>
  288. <script src="/scripts/drag.js"></script>
  289. <script src="/scripts/chat.js"></script>
  290. <script src="/scripts/files.js"></script>
  291. <script src="/scripts/users.js"></script>
  292. <script src="/scripts/app.js"></script>
  293. </body>
  294. </html>