OpenShot Video Editor  2.0.0
functions.js
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Misc Functions used by the OpenShot Timeline
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 // Find a JSON element / object with a particular value in the json data
31 function findElement(arr, propName, propValue) {
32 
33  // Loop through array looking for a matching element
34  for (var i=0; i < arr.length; i++)
35  if (arr[i][propName] == propValue)
36  return arr[i];
37 
38 }
39 
40 // Get the height of the track container (minus bottom margin of last track)
42 
43  var track_margin = 0;
44  if ($(".track").length)
45  if ($(".track").css("margin-bottom"))
46  track_margin = parseInt($(".track").css("margin-bottom").replace("px",""));
47 
48  return $("#track-container").height() - track_margin;
49 }
50 
51 // Draw the audio wave on a clip
52 function drawAudio(scope, clip_id){
53  //get the clip in the scope
54  clip = findElement(scope.project.clips, "id", clip_id);
55 
56  if (clip.show_audio){
57  element = $("#clip_"+clip_id);
58 
59  // Determine start and stop samples
60  var samples_per_second = 20;
61  var start_sample = clip.start * samples_per_second;
62  var end_sample = clip.end * samples_per_second;
63 
64  // Determine divisor for zoom scale
65  var sample_divisor = samples_per_second / scope.pixelsPerSecond;
66 
67  //show audio container
68  element.find(".audio-container").show();
69 
70  // Get audio canvas context
71  var audio_canvas = element.find(".audio");
72  var ctx = audio_canvas[0].getContext('2d');
73 
74  // Clear canvas
75  ctx.canvas.width = ctx.canvas.width;
76 
77  // Offset the coordinates for thinner lines
78  ctx.translate(0.5, 0.5);
79  ctx.beginPath();
80 
81  // Find the midpoint
82  var mid_point = audio_canvas.height() - 8;
83  var line_spot = 0;
84 
85  // Draw the mid-point line
86  ctx.lineWidth = 1;
87  ctx.moveTo(0, mid_point);
88  ctx.lineTo(audio_canvas.width(), mid_point);
89  ctx.strokeStyle = "#2a82da";
90  ctx.stroke();
91 
92  //for each point of audio data, draw a line
93  var sample_index = 0;
94  for (var i = 1; i < audio_canvas.width(); i+=1) {
95  //increase the 'x' axis draw point
96  ctx.beginPath();
97  line_spot += 1;
98  ctx.moveTo(line_spot, mid_point);
99  sample_index = Math.round(start_sample + (sample_divisor * i));
100  var audio_point = clip.audio_data[sample_index];
101  //set the point to draw to
102  var draw_to = (audio_point * mid_point);
103  //handle the 'draw to' point based on positive or negative audio point
104  if (audio_point >= 0.0) draw_to = mid_point - draw_to;
105  if (audio_point < 0.0) draw_to = mid_point + (draw_to * -1.0);
106  //draw it
107  ctx.lineTo(line_spot, draw_to);
108  ctx.stroke();
109  }
110  }
111 
112 }
113 
114 function padNumber(value, pad_length)
115 {
116  return ("10000"+value).slice(-1* pad_length);
117 }
118 
119 // Convert seconds into formatted time stamp
120 function secondsToTime(secs, fps_num, fps_den)
121 {
122  // calculate time of playhead
123  var milliseconds = secs * 1000;
124  var sec = Math.floor(milliseconds/1000);
125  var milli = milliseconds % 1000;
126  var min = Math.floor(sec/60);
127  var sec = sec % 60;
128  var hour = Math.floor(min/60);
129  var min = min % 60;
130  var day = Math.floor(hour/24);
131  var hour = hour % 24;
132  var week = Math.floor(day/7);
133  var day = day % 7;
134 
135  var frame = Math.round((milli / 1000.0) * (fps_num / fps_den)) + 1;
136  return { "week":padNumber(week,2), "day":padNumber(day,2), "hour":padNumber(hour,2), "min":padNumber(min,2), "sec":padNumber(sec,2), "milli":padNumber(milli,2), "frame":padNumber(frame,2) };
137 }
138 
139 // Find the closest track number (based on a Y coordinate)
140 function findTrackAtLocation(scope, top){
141 
142  // Loop through each layer (looking for the closest track based on Y coordinate)
143  var track_position = 0;
144  var track_number = 0;
145  for (var layer_index = scope.project.layers.length - 1; layer_index >= 0 ; layer_index--) {
146  var layer = scope.project.layers[layer_index];
147 
148  // Compare position of track to Y param (of unlocked tracks)
149  if (!layer.lock)
150  if ((top < layer.y && top > track_position) || track_position==0) {
151  // return first matching layer
152  track_position = layer.y;
153  track_number = layer.number;
154  }
155  }
156 
157  return track_number;
158 }
159 
160 // Find the closest track number (based on a Y coordinate)
161 function hasLockedTrack(scope, top, bottom){
162 
163  // Loop through each layer (looking for the closest track based on Y coordinate)
164  var track_position = 0;
165  var track_number = 0;
166  for (var layer_index = scope.project.layers.length - 1; layer_index >= 0 ; layer_index--) {
167  var layer = scope.project.layers[layer_index];
168 
169  // Compare position of track to Y param
170  if (layer.lock && layer.y >= top && layer.y <= bottom) {
171  // Yes, found a locked track inside these coordinates
172  return true;
173  }
174  }
175 
176  return false;
177 }
178 
179 var bounding_box = Object();
180 
181 // Build bounding box (since multiple items can be selected)
182 function setBoundingBox(item){
183  var vert_scroll_offset = $("#scrolling_tracks").scrollTop();
184  var horz_scroll_offset = $("#scrolling_tracks").scrollLeft();
185 
186  var item_bottom = item.position().top + item.height() + vert_scroll_offset;
187  var item_top = item.position().top + vert_scroll_offset;
188  var item_left = item.position().left + horz_scroll_offset;
189  var item_right = item.position().left + horz_scroll_offset + item.width();
190 
191  if(jQuery.isEmptyObject(bounding_box)){
192  bounding_box.left = item_left;
193  bounding_box.top = item_top;
194  bounding_box.bottom = item_bottom;
195  bounding_box.right = item_right;
196  bounding_box.height = item.height();
197  bounding_box.width = item.width();
198  }else{
199  //compare and change if item is a better fit for bounding box edges
200  if (item_top < bounding_box.top) bounding_box.top = item_top;
201  if (item_left < bounding_box.left) bounding_box.left = item_left;
202  if (item_bottom > bounding_box.bottom) bounding_box.bottom = item_bottom;
203  if (item_right > bounding_box.right) bounding_box.right = item_right;
204 
205  // compare height and width of bounding box (take the largest number)
206  var height = bounding_box.bottom - bounding_box.top;
207  var width = bounding_box.right - bounding_box.left;
208  if (height > bounding_box.height) bounding_box.height = height;
209  if (width > bounding_box.width) bounding_box.width = width;
210  }
211 }
212 
213 // Move bounding box (apply snapping and constraints)
214 function moveBoundingBox(scope, previous_x, previous_y, x_offset, y_offset, left, top) {
215  // Store result of snapping logic (left, top)
216  var snapping_result = Object();
217  snapping_result.left = left;
218  snapping_result.top = top;
219 
220  // Check for shift key
221  if (scope.shift_pressed) {
222  // freeze X movement
223  x_offset = 0;
224  snapping_result.left = previous_x;
225  }
226 
227  // Update bounding box
228  bounding_box.left += x_offset;
229  bounding_box.right += x_offset;
230  bounding_box.top += y_offset;
231  bounding_box.bottom += y_offset;
232 
233  // Check overall timeline constraints (i.e don't let clips be dragged outside the timeline)
234  if (bounding_box.left < 0) {
235  // Left border
236  x_offset -= bounding_box.left;
237  bounding_box.left = 0;
238  bounding_box.right = bounding_box.width;
239  snapping_result.left = previous_x + x_offset;
240  }
241  if (bounding_box.top < 0) {
242  // Top border
243  y_offset -= bounding_box.top;
244  bounding_box.top = 0;
245  bounding_box.bottom = bounding_box.height;
246  snapping_result.top = previous_y + y_offset;
247  }
248  if (bounding_box.bottom > track_container_height) {
249  // Bottom border
250  y_offset -= (bounding_box.bottom - track_container_height);
252  bounding_box.top = bounding_box.bottom - bounding_box.height;
253  snapping_result.top = previous_y + y_offset;
254  }
255 
256  // Get list of current selected ids (so we can ignore their snapping x coordinates)
257  selected_ids = {};
258  $(".ui-selected").each(function() {
259  var item_id = $(this).attr('id');
260  selected_ids[item_id.substr(item_id.indexOf("_") + 1)] = true;
261  });
262 
263  // Find closest nearby object, if any (for snapping)
264  var bounding_box_padding = 3; // not sure why this is needed, but it helps line everything up
265  var results = scope.GetNearbyPosition([bounding_box.left, bounding_box.right + bounding_box_padding], 1.0, selected_ids);
266  var nearby_offset = results[0] * scope.pixelsPerSecond;
267  var snapline_position = results[1];
268 
269  if (snapline_position) {
270  // Show snapping line
271  scope.ShowSnapline(snapline_position);
272 
273  if (scope.enable_snapping) {
274  snapped = true;
275 
276  // Snap bounding box to this position
277  x_offset -= nearby_offset;
278  bounding_box.left -= nearby_offset;
279  bounding_box.right -= nearby_offset;
280  snapping_result.left -= nearby_offset;
281  }
282 
283  } else {
284  // Hide snapline
285  scope.HideSnapline();
286  }
287 
288  return { 'position': snapping_result, 'x_offset' : x_offset, 'y_offset' : y_offset };
289 }
290 
jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem, computed){if(computed){return jQuery.swap(elem,{"display":"inline-block"}, curCSS, [elem,"marginRight"]);}}};}if(!jQuery.support.pixelPosition &&jQuery.fn.position){jQuery.each(["top","left"], function(i, prop){jQuery.cssHooks[prop]={get:function(elem, computed){if(computed){computed=curCSS(elem, prop);return rnumnonpx.test(computed)?jQuery(elem).position()[prop]+"px":computed;}}};});}})
function getTrackContainerHeight()
Definition: functions.js:41
function findElement(arr, propName, propValue)
Definition: functions.js:31
var bounding_box
Definition: functions.js:179
Definition: clip.py:1
function moveBoundingBox(scope, previous_x, previous_y, x_offset, y_offset, left, top)
Definition: functions.js:214
function setBoundingBox(item)
Definition: functions.js:182
function padNumber(value, pad_length)
Definition: functions.js:114
Tween propHooks scrollTop
Definition: jquery.js:9274
function drawAudio(scope, clip_id)
Definition: functions.js:52
jQuery each(["height","width"], function(i, name){jQuery.cssHooks[name]={get:function(elem, computed, extra){if(computed){return elem.offsetWidth===0 &&rdisplayswap.test(jQuery.css(elem,"display"))?jQuery.swap(elem, cssShow, function(){return getWidthOrHeight(elem, name, extra);}):getWidthOrHeight(elem, name, extra);}}, set:function(elem, value, extra){var styles=extra &&getStyles(elem);return setPositiveNumber(elem, value, extra?augmentWidthOrHeight(elem, name, extra, jQuery.support.boxSizing &&jQuery.css(elem,"boxSizing", false, styles)==="border-box", styles):0);}};})
function hasLockedTrack(scope, top, bottom)
Definition: functions.js:161
function findTrackAtLocation(scope, top)
Definition: functions.js:140
function secondsToTime(secs, fps_num, fps_den)
Definition: functions.js:120
var track_container_height
Definition: clip.js:37