OpenShot Video Editor  2.0.0
ruler.js
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Ruler directives (dragging playhead functionality, progress bars, tick marks, etc...)
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  * @author Cody Parker <cody@yourcodepro.com>
6  *
7  * @section LICENSE
8  *
9  * Copyright (c) 2008-2014 OpenShot Studios, LLC
10  * <http://www.openshotstudios.com/>. This file is part of
11  * OpenShot Video Editor, an open-source project dedicated to
12  * delivering high quality video editing and animation solutions to the
13  * world. For more information visit <http://www.openshot.org/>.
14  *
15  * OpenShot Video Editor is free software: you can redistribute it
16  * and/or modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation, either version 3 of the
18  * License, or (at your option) any later version.
19  *
20  * OpenShot Video Editor is distributed in the hope that it will be
21  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
27  */
28 
29 
30 // Variables for panning by middle click
31 var is_scrolling = false;
32 var starting_scrollbar = { x: 0, y: 0 };
33 var starting_mouse_position = { x: 0, y: 0 };
34 
35 // Variables for scrolling control
37 
38 
39 // This container allows for tracks to be scrolled (with synced ruler)
40 // and allows for panning of the timeline with the middle mouse button
41 App.directive('tlScrollableTracks', function () {
42  return {
43  restrict: 'A',
44 
45  link: function (scope, element, attrs) {
46 
47  // Sync ruler to track scrolling
48  element.on('scroll', function () {
49  //set amount scrolled
50  scroll_left_pixels = element.scrollLeft();
51 
52  $('#track_controls').scrollTop(element.scrollTop());
53  $('#scrolling_ruler').scrollLeft(element.scrollLeft());
54  $('#progress_container').scrollLeft(element.scrollLeft());
55  });
56 
57  // Initialize panning when middle mouse is clicked
58  element.on('mousedown', function(e) {
59  if (e.which == 2) { // middle button
60  e.preventDefault();
61  is_scrolling = true;
62  starting_scrollbar = { x: element.scrollLeft(), y: element.scrollTop() };
63  starting_mouse_position = { x: e.pageX, y: e.pageY };
64  element.addClass('drag_cursor');
65  }
66  });
67 
68  // Pans the timeline (on middle mouse clip and drag)
69  element.on('mousemove', function(e){
70  if (is_scrolling) {
71  // Calculate difference from last position
72  difference = { x: starting_mouse_position.x-e.pageX, y: starting_mouse_position.y-e.pageY};
73 
74  // Scroll the tracks div
75  element.scrollLeft(starting_scrollbar.x + difference.x);
76  element.scrollTop(starting_scrollbar.y + difference.y);
77  }
78  });
79 
80  // Remove move cursor (i.e. dragging has stopped)
81  element.on('mouseup', function(e) {
82  element.removeClass('drag_cursor');
83  });
84 
85 
86  }
87  };
88 });
89 
90 // Track scrolling mode on body tag... allows for capture of released middle mouse button
91 App.directive('tlBody', function () {
92  return {
93  link: function (scope, element, attrs){
94 
95  element.on('mouseup', function(e){
96  if (e.which == 2) // middle button
97  is_scrolling = false;
98  });
99 
100 
101  }
102  };
103 });
104 
105 
106 // The HTML5 canvas ruler
107 App.directive('tlRuler', function ($timeout) {
108  return {
109  restrict: 'A',
110  link: function (scope, element, attrs) {
111  //on click of the ruler canvas, jump playhead to the clicked spot
112  element.on('mousedown', function(e){
113  // Get playhead position
114  var playhead_left = e.pageX - element.offset().left;
115  var playhead_seconds = playhead_left / scope.pixelsPerSecond;
116 
117  // Immediately preview frame (don't wait for animated playhead)
118  scope.PreviewFrame(playhead_seconds);
119 
120  // Animate to new position (and then update scope)
121  scope.playhead_animating = true;
122  $(".playhead-line").animate({left: playhead_left + scope.playheadOffset }, 200);
123  $(".playhead-top").animate({left: playhead_left + scope.playheadOffset }, 200, function() {
124  // Update playhead
125  scope.MovePlayhead(playhead_seconds);
126 
127  // Animation complete.
128  scope.$apply(function(){
129  scope.playhead_animating = false;
130  });
131  });
132 
133  });
134 
135  // Move playhead to new position (if it's not currently being animated)
136  element.on('mousemove', function(e){
137  if (e.which == 1 && !scope.playhead_animating) { // left button
138  var playhead_seconds = (e.pageX - element.offset().left) / scope.pixelsPerSecond;
139  // Update playhead
140  scope.MovePlayhead(playhead_seconds);
141  scope.PreviewFrame(playhead_seconds);
142  }
143  });
144 
145  //watch the scale value so it will be able to draw the ruler after changes,
146  //otherwise the canvas is just reset to blank
147  scope.$watch('project.scale + markers.length + project.duration', function (val) {
148  if (val){
149 
150  $timeout(function(){
151  //get all scope variables we need for the ruler
152  var scale = scope.project.scale;
153  var tick_pixels = scope.project.tick_pixels;
154  var each_tick = tick_pixels / 2;
155  var pixel_length = scope.GetTimelineWidth(1024);
156 
157  //draw the ruler
158  var ctx = element[0].getContext('2d');
159  //clear the canvas first
160  ctx.clearRect(0, 0, element.width(), element.height());
161  //set number of ticks based 2 for each pixel_length
162  num_ticks = pixel_length / 50;
163 
164  ctx.lineWidth = 1;
165  ctx.strokeStyle = "#c8c8c8";
166  ctx.lineCap = "round";
167 
168  //loop em and draw em
169  for (x=0;x<num_ticks+1;x++){
170  ctx.beginPath();
171 
172  //if it's even, make the line longer
173  if (x%2 == 0){
174  line_top = 18;
175  //if it's not the first line, set the time text
176  if (x != 0){
177  //get time for this tick
178  time = (scale * x) /2;
179  time_text = secondsToTime(time, scope.project.fps.num, scope.project.fps.den);
180 
181  //write time on the canvas, centered above long tick
182  ctx.fillStyle = "#c8c8c8";
183  ctx.font = "0.9em";
184  ctx.fillText(time_text["hour"] +":"+ time_text["min"] +":"+ time_text["sec"], x*each_tick-22, 11);
185  }
186  } else {
187  //shorter line
188  line_top = 28;
189  }
190 
191  ctx.moveTo(x*each_tick, 39);
192  ctx.lineTo(x*each_tick, line_top);
193  ctx.stroke();
194  }
195  }, 0);
196 
197  }
198  });
199 
200  }
201 
202  };
203 });
204 
205 
206 // The HTML5 canvas ruler
207 App.directive('tlRulertime', function () {
208  return {
209  restrict: 'A',
210  link: function (scope, element, attrs) {
211  //on click of the ruler canvas, jump playhead to the clicked spot
212  element.on('mousedown', function(e){
213  var playhead_seconds = 0.0;
214  // Update playhead
215  scope.MovePlayhead(playhead_seconds);
216  scope.PreviewFrame(playhead_seconds);
217 
218  });
219 
220  // Move playhead to new position (if it's not currently being animated)
221  element.on('mousemove', function(e){
222  if (e.which == 1 && !scope.playhead_animating) { // left button
223  var playhead_seconds = 0.0;
224  // Update playhead
225  scope.MovePlayhead(playhead_seconds);
226  scope.PreviewFrame(playhead_seconds);
227  }
228  });
229 
230 
231  }
232  };
233 });
234 
235 
236 
237 // Handles the HTML5 canvas progress bar
238 App.directive('tlProgress', function($timeout){
239  return {
240  link: function(scope, element, attrs){
241  scope.$watch('progress + project.scale', function (val) {
242  if (val) {
243  $timeout(function(){
244  var progress = scope.project.progress;
245  for(p=0;p<progress.length;p++){
246 
247  //get the progress item details
248  var start_second = progress[p][0];
249  var stop_second = progress[p][1];
250  var status = progress[p][2];
251 
252  //figure out the actual pixel position
253  var start_pixel = start_second * scope.pixelsPerSecond;
254  var stop_pixel = stop_second * scope.pixelsPerSecond;
255  var rect_length = stop_pixel - start_pixel;
256 
257  //get the element and draw the rects
258  var ctx = element[0].getContext('2d');
259  ctx.beginPath();
260  ctx.rect(start_pixel, 0, rect_length, 5);
261  //change style based on status
262  if (status == 'complete'){
263  ctx.fillStyle = 'green';
264  }else{
265  ctx.fillStyle = 'yellow';
266  }
267  ctx.fill();
268  }
269  }, 0);
270 
271  }
272  });
273 
274 
275  }
276  };
277 });
278 
279 
280 
281 
282 
var starting_scrollbar
Definition: ruler.js:32
var is_scrolling
Definition: ruler.js:31
var App
Definition: app.js:31
var a[b] e
Tween propHooks scrollTop
Definition: jquery.js:9274
var scroll_left_pixels
Definition: ruler.js:36
function secondsToTime(secs, fps_num, fps_den)
Definition: functions.js:120
var starting_mouse_position
Definition: ruler.js:33