Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: chrome/browser/resources/tracing/timeline.js

Issue 8359025: Tons of timeline tweaks (Closed)
Patch Set: Fixen Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview Interactive visualizaiton of TimelineModel objects 6 * @fileoverview Interactive visualizaiton of TimelineModel objects
7 * based loosely on gantt charts. Each thread in the TimelineModel is given a 7 * based loosely on gantt charts. Each thread in the TimelineModel is given a
8 * set of TimelineTracks, one per subrow in the thread. The Timeline class 8 * set of TimelineTracks, one per subrow in the thread. The Timeline class
9 * acts as a controller, creating the individual tracks, while TimelineTracks 9 * acts as a controller, creating the individual tracks, while TimelineTracks
10 * do actual drawing. 10 * do actual drawing.
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 160
161 this.invalidatePending_ = false; 161 this.invalidatePending_ = false;
162 162
163 this.tracks_ = this.ownerDocument.createElement('div'); 163 this.tracks_ = this.ownerDocument.createElement('div');
164 this.tracks_.invalidate = this.invalidate.bind(this); 164 this.tracks_.invalidate = this.invalidate.bind(this);
165 this.appendChild(this.tracks_); 165 this.appendChild(this.tracks_);
166 166
167 this.dragBox_ = this.ownerDocument.createElement('div'); 167 this.dragBox_ = this.ownerDocument.createElement('div');
168 this.dragBox_.className = 'timeline-drag-box'; 168 this.dragBox_.className = 'timeline-drag-box';
169 this.appendChild(this.dragBox_); 169 this.appendChild(this.dragBox_);
170 this.hideDragBox_();
170 171
171 // The following code uses a setInterval to monitor the timeline control 172 // The following code uses a setInterval to monitor the timeline control
172 // for size changes. This is so that we can keep the canvas' bitmap size 173 // for size changes. This is so that we can keep the canvas' bitmap size
173 // correctly synchronized with its presentation size. 174 // correctly synchronized with its presentation size.
174 // TODO(nduca): detect this in a more efficient way, e.g. iframe hack. 175 // TODO(nduca): detect this in a more efficient way, e.g. iframe hack.
175 this.lastSize_ = this.clientWidth + 'x' + this.clientHeight; 176 this.lastSize_ = this.clientWidth + 'x' + this.clientHeight;
176 this.ownerDocument.defaultView.setInterval(function() { 177 this.checkForResizeInterval_ =
178 this.ownerDocument.defaultView.setInterval(function() {
179 if (!this.isAttachedToDocument_)
180 return;
177 var curSize = this.clientWidth + 'x' + this.clientHeight; 181 var curSize = this.clientWidth + 'x' + this.clientHeight;
178 if (this.clientWidth && curSize != this.lastSize_) { 182 if (this.clientWidth && curSize != this.lastSize_) {
179 this.lastSize_ = curSize; 183 this.lastSize_ = curSize;
180 this.onResize(); 184 this.onResize();
181 } 185 }
182 }.bind(this), 250); 186 }.bind(this), 250);
183 187
184 document.addEventListener('keypress', this.onKeypress_.bind(this)); 188 this.bindEventListener_(document, 'keypress', this.onKeypress_, this);
185 document.addEventListener('keydown', this.onKeydown_.bind(this)); 189 this.bindEventListener_(document, 'keydown', this.onKeydown_, this);
186 document.addEventListener('mousedown', this.onMouseDown_.bind(this)); 190 this.bindEventListener_(document, 'mousedown', this.onMouseDown_, this);
187 document.addEventListener('mousemove', this.onMouseMove_.bind(this)); 191 this.bindEventListener_(document, 'mousemove', this.onMouseMove_, this);
188 document.addEventListener('mouseup', this.onMouseUp_.bind(this)); 192 this.bindEventListener_(document, 'mouseup', this.onMouseUp_, this);
189 document.addEventListener('dblclick', this.onDblClick_.bind(this)); 193 this.bindEventListener_(document, 'dblclick', this.onDblClick_, this);
190 194
191 this.lastMouseViewPos_ = {x: 0, y: 0}; 195 this.lastMouseViewPos_ = {x: 0, y: 0};
192 196
193 this.selection_ = []; 197 this.selection_ = [];
194 }, 198 },
195 199
200 /**
201 * Wraps the stanard addEventListener but automatically binds the provided
James Hawkins 2011/11/10 01:06:13 s/stanard/standard/
nduca 2011/11/10 02:24:35 Done.
202 * func to the provided target, tracking the resulting closure. When detach
203 * is called, these listeners will be automatically removed.
204 */
205 bindEventListener_: function(object, event, func, target) {
206 if (!this.boundListeners_)
207 this.boundListeners_ = [];
208 var boundFunc = func.bind(target);
209 this.boundListeners_.push({object: object,
210 event: event,
211 boundFunc: boundFunc});
212 object.addEventListener(event, boundFunc);
213 },
214
215 detach: function() {
216 for (var i = 0; i < this.boundListeners_.length; ++i) {
217 var binding = this.boundListeners_[i];
218 binding.object.removeEventListener(binding.event, binding.boundFunc);
219 }
220 this.boundListeners_ = undefined;
221 window.clearInterval(this.checkForResizeInterval_);
222 this.checkForResizeInterval_ = undefined;
223 },
224
196 get model() { 225 get model() {
197 return this.model_; 226 return this.model_;
198 }, 227 },
199 228
200 set model(model) { 229 set model(model) {
201 if (!model) 230 if (!model)
202 throw Error('Model cannot be null'); 231 throw Error('Model cannot be null');
203 if (this.model) { 232 if (this.model) {
204 throw Error('Cannot set model twice.'); 233 throw Error('Cannot set model twice.');
205 } 234 }
206 this.model_ = model; 235 this.model_ = model;
207 236
208 // Create tracks. 237 // Create tracks and measure their heading size.
209 this.tracks_.textContent = '';
210 var threads = model.getAllThreads(); 238 var threads = model.getAllThreads();
211 threads.sort(tracing.TimelineThread.compare); 239 var maxHeadingWidth = 0;
240 var tracks = [];
241 var measuringStick = new tracing.MeasuringStick();
242 var headingEl = document.createElement('div');
243 headingEl.style.position = 'fixed';
244 headingEl.className = 'timeline-slice-track-title';
212 for (var tI = 0; tI < threads.length; tI++) { 245 for (var tI = 0; tI < threads.length; tI++) {
213 var thread = threads[tI]; 246 var thread = threads[tI];
214 var track = new TimelineThreadTrack(); 247 var track = new TimelineThreadTrack();
215 track.thread = thread; 248 track.thread = thread;
216 track.viewport = this.viewport_; 249 track.viewport = this.viewport_;
250 tracks.push(track);
251 headingEl.textContent = track.heading;
252 var w = measuringStick.measure(headingEl).width;
253 // Limit heading width to 300px.
254 if (w > 300)
255 w = 300;
256 if (w > maxHeadingWidth)
257 maxHeadingWidth = w;
258 }
259 maxHeadingWidth += maxHeadingWidth + 4;
James Hawkins 2011/11/10 01:06:13 What is the 4 about?
nduca 2011/11/10 02:24:35 Its some extra padding to make things look less cr
260
261 // Attach tracks and set width.
262 this.tracks_.textContent = '';
263 threads.sort(tracing.TimelineThread.compare);
264 for (var tI = 0; tI < tracks.length; tI++) {
265 var track = tracks[tI];
266 track.headingWidth = maxHeadingWidthWithUnit + 'px';
217 this.tracks_.appendChild(track); 267 this.tracks_.appendChild(track);
218
219 } 268 }
220 269
221 this.needsViewportReset_ = true; 270 if (this.isAttachedToDocument_) {
James Hawkins 2011/11/10 01:06:13 nit: No braces for single-line blocks.
nduca 2011/11/10 02:24:35 Done.
271 this.onResize();
272 } else {
273 this.needsViewportReset_ = true;
274 }
222 }, 275 },
223 276
224 viewportChange_: function() { 277 viewportChange_: function() {
225 this.invalidate(); 278 this.invalidate();
226 }, 279 },
227 280
228 invalidate: function() { 281 invalidate: function() {
229 if (this.invalidatePending_) 282 if (this.invalidatePending_)
230 return; 283 return;
231 this.invalidatePending_ = true; 284 this.invalidatePending_ = true;
232 window.setTimeout(function() { 285 if (this.isAttachedToDocument_)
233 this.invalidatePending_ = false; 286 window.setTimeout(function() {
234 this.redrawAllTracks_(); 287 this.invalidatePending_ = false;
235 }.bind(this), 0); 288 this.redrawAllTracks_();
289 }.bind(this), 0);
290 },
291
292 /**
293 * @return {boolean} Whether the current timeline is attached to the
294 * document.
295 */
296 get isAttachedToDocument_() {
297 var cur = this;
298 while (cur.parentNode)
299 cur = cur.parentNode;
300 return cur == this.ownerDocument;
236 }, 301 },
237 302
238 onResize: function() { 303 onResize: function() {
304 if (!this.isAttachedToDocument_)
305 throw 'Not attached to document!';
239 for (var i = 0; i < this.tracks_.children.length; ++i) { 306 for (var i = 0; i < this.tracks_.children.length; ++i) {
240 var track = this.tracks_.children[i]; 307 var track = this.tracks_.children[i];
241 track.onResize(); 308 track.onResize();
242 } 309 }
310 if (this.invalidatePending_) {
311 this.invalidatePending_ = false;
312 this.redrawAllTracks_();
313 }
243 }, 314 },
244 315
245 redrawAllTracks_: function() { 316 redrawAllTracks_: function() {
246 if (this.needsViewportReset_ && this.clientWidth != 0) { 317 if (this.needsViewportReset_ && this.clientWidth != 0) {
318 if (!this.isAttachedToDocument_)
319 throw 'Not attached to document!';
247 this.needsViewportReset_ = false; 320 this.needsViewportReset_ = false;
248 /* update viewport */ 321 /* update viewport */
249 var rangeTimestamp = this.model_.maxTimestamp - 322 var rangeTimestamp = this.model_.maxTimestamp -
250 this.model_.minTimestamp; 323 this.model_.minTimestamp;
251 var w = this.firstCanvas.width; 324 var w = this.firstCanvas.width;
252 console.log('viewport was reset with w=', w);
253 var scaleX = w / rangeTimestamp; 325 var scaleX = w / rangeTimestamp;
254 var panX = -this.model_.minTimestamp; 326 var panX = -this.model_.minTimestamp;
255 this.viewport_.setPanAndScale(panX, scaleX); 327 this.viewport_.setPanAndScale(panX, scaleX);
256 } 328 }
257 for (var i = 0; i < this.tracks_.children.length; ++i) { 329 for (var i = 0; i < this.tracks_.children.length; ++i) {
258 this.tracks_.children[i].redraw(); 330 this.tracks_.children[i].redraw();
259 } 331 }
260 }, 332 },
261 333
262 updateChildViewports_: function() { 334 updateChildViewports_: function() {
263 for (var cI = 0; cI < this.tracks_.children.length; ++cI) { 335 for (var cI = 0; cI < this.tracks_.children.length; ++cI) {
264 var child = this.tracks_.children[cI]; 336 var child = this.tracks_.children[cI];
265 child.setViewport(this.panX, this.scaleX); 337 child.setViewport(this.panX, this.scaleX);
266 } 338 }
267 }, 339 },
268 340
341 get listenToKeys_() {
342 if (this.parentElement.parentElement.tabIndex >= 0)
343 return document.activeElement == this.parentElement.parentElement;
344 return true;
345 },
346
269 onKeypress_: function(e) { 347 onKeypress_: function(e) {
270 var vp = this.viewport_; 348 var vp = this.viewport_;
271 if (!this.firstCanvas) 349 if (!this.firstCanvas)
272 return; 350 return;
351 if (!this.listenToKeys_)
352 return;
273 var viewWidth = this.firstCanvas.clientWidth; 353 var viewWidth = this.firstCanvas.clientWidth;
274 var curMouseV, curCenterW; 354 var curMouseV, curCenterW;
275 switch (e.keyCode) { 355 switch (e.keyCode) {
276 case 101: // e 356 case 101: // e
277 var vX = this.lastMouseViewPos_.x; 357 var vX = this.lastMouseViewPos_.x;
278 var wX = vp.xViewToWorld(this.lastMouseViewPos_.x); 358 var wX = vp.xViewToWorld(this.lastMouseViewPos_.x);
279 var distFromCenter = vX - (viewWidth / 2); 359 var distFromCenter = vX - (viewWidth / 2);
280 var percFromCenter = distFromCenter / viewWidth; 360 var percFromCenter = distFromCenter / viewWidth;
281 var percFromCenterSq = percFromCenter * percFromCenter; 361 var percFromCenterSq = percFromCenter * percFromCenter;
282 vp.xPanWorldPosToViewPos(wX, 'center', viewWidth); 362 vp.xPanWorldPosToViewPos(wX, 'center', viewWidth);
(...skipping 26 matching lines...) Expand all
309 vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5); 389 vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5);
310 break; 390 break;
311 case 68: // D 391 case 68: // D
312 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5); 392 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5);
313 break; 393 break;
314 } 394 }
315 }, 395 },
316 396
317 // Not all keys send a keypress. 397 // Not all keys send a keypress.
318 onKeydown_: function(e) { 398 onKeydown_: function(e) {
399 if (!this.listenToKeys_)
400 return;
319 switch (e.keyCode) { 401 switch (e.keyCode) {
320 case 37: // left arrow 402 case 37: // left arrow
321 this.selectPrevious_(e); 403 this.selectPrevious_(e);
322 e.preventDefault(); 404 e.preventDefault();
323 break; 405 break;
324 case 39: // right arrow 406 case 39: // right arrow
325 this.selectNext_(e); 407 this.selectNext_(e);
326 e.preventDefault(); 408 e.preventDefault();
327 break; 409 break;
328 case 9: // TAB 410 case 9: // TAB
329 if (e.shiftKey) 411 if (this.parentElement.parentElement.tabIndex == -1) {
330 this.selectPrevious_(e); 412 if (e.shiftKey)
331 else 413 this.selectPrevious_(e);
332 this.selectNext_(e); 414 else
333 e.preventDefault(); 415 this.selectNext_(e);
416 e.preventDefault();
417 }
334 break; 418 break;
335 } 419 }
336 }, 420 },
337 421
338 /** 422 /**
339 * Zoom in or out on the timeline by the given scale factor. 423 * Zoom in or out on the timeline by the given scale factor.
340 * @param {integer} scale The scale factor to apply. If <1, zooms out. 424 * @param {integer} scale The scale factor to apply. If <1, zooms out.
341 */ 425 */
342 zoomBy_: function(scale) { 426 zoomBy_: function(scale) {
343 if (!this.firstCanvas) 427 if (!this.firstCanvas)
(...skipping 22 matching lines...) Expand all
366 * @param {boolean} forwardp If true, select one forward (next). 450 * @param {boolean} forwardp If true, select one forward (next).
367 * Else, select previous. 451 * Else, select previous.
368 */ 452 */
369 selectAdjoining_: function(e, forwardp) { 453 selectAdjoining_: function(e, forwardp) {
370 var i, track, slice, adjoining; 454 var i, track, slice, adjoining;
371 var selection = []; 455 var selection = [];
372 // Clear old selection; try and select next. 456 // Clear old selection; try and select next.
373 for (i = 0; i < this.selection_.length; ++i) { 457 for (i = 0; i < this.selection_.length; ++i) {
374 adjoining = undefined; 458 adjoining = undefined;
375 this.selection_[i].slice.selected = false; 459 this.selection_[i].slice.selected = false;
376 var track = this.selection_[i].track; 460 track = this.selection_[i].track;
377 var slice = this.selection_[i].slice; 461 slice = this.selection_[i].slice;
378 if (slice) { 462 if (slice) {
379 if (forwardp) 463 if (forwardp)
380 adjoining = track.pickNext(slice); 464 adjoining = track.pickNext(slice);
381 else 465 else
382 adjoining = track.pickPrevious(slice); 466 adjoining = track.pickPrevious(slice);
383 } 467 }
384 if (adjoining != undefined) 468 if (adjoining != undefined)
385 selection.push({track: track, slice: adjoining}); 469 selection.push({track: track, slice: adjoining});
386 } 470 }
387 // Activate the new selection. 471 // Activate the new selection.
388 this.selection_ = selection; 472 this.selection_ = selection;
389 for (i = 0; i < this.selection_.length; ++i) 473 for (i = 0; i < this.selection_.length; ++i)
390 this.selection_[i].slice.selected = true; 474 this.selection_[i].slice.selected = true;
391 cr.dispatchSimpleEvent(this, 'selectionChange'); 475 cr.dispatchSimpleEvent(this, 'selectionChange');
392 this.invalidate(); // Cause tracks to redraw. 476 this.invalidate(); // Cause tracks to redraw.
393 e.preventDefault(); 477 e.preventDefault();
394 }, 478 },
395 479
396 get keyHelp() { 480 get keyHelp() {
397 return 'Keyboard shortcuts:\n' + 481 var help = 'Keyboard shortcuts:\n' +
398 ' w/s : Zoom in/out (with shift: go faster)\n' + 482 ' w/s : Zoom in/out (with shift: go faster)\n' +
399 ' a/d : Pan left/right\n' + 483 ' a/d : Pan left/right\n' +
400 ' e : Center on mouse\n' + 484 ' e : Center on mouse\n' +
401 ' g/G : Shows grid at the start/end of the selected task\n' + 485 ' g/G : Shows grid at the start/end of the selected task\n';
402 ' <-,^TAB : Select previous event on current timeline\n' +
403 ' ->, TAB : Select next event on current timeline\n' +
404 '\n' +
405 'Dbl-click to zoom in; Shift dbl-click to zoom out\n';
406 486
487 if (this.parentElement.parentElement.tabIndex)
James Hawkins 2011/11/10 01:06:13 nit: Multi-line blocks must have braces.
nduca 2011/11/10 02:24:35 Done.
488 help += ' <- : Select previous event on current timeline\n' +
489 ' -> : Select next event on current timeline\n';
490 else
491 help += ' <-,^TAB : Select previous event on current timeline\n' +
492 ' ->, TAB : Select next event on current timeline\n';
407 493
494 help +=
495 '\n' +
496 'Dbl-click to zoom in; Shift dbl-click to zoom out\n';
497 return help;
408 }, 498 },
409 499
410 get selection() { 500 get selection() {
411 return this.selection_; 501 return this.selection_;
412 }, 502 },
413 503
504 set selection(var sel) {
505 // Clear old selection.
506 for (i = 0; i < this.selection_.length; ++i) {
James Hawkins 2011/11/10 01:06:13 nit: No braces for single-line blocks.
nduca 2011/11/10 02:24:35 Done.
507 this.selection_[i].slice.selected = false;
508 }
509
510 this.selection_ = sel;
511
512 this.selection_ = selection;
513 cr.dispatchSimpleEvent(this, 'selectionChange');
514 for (i = 0; i < this.selection_.length; ++i) {
James Hawkins 2011/11/10 01:06:13 nit: No braces for single-line blocks.
nduca 2011/11/10 02:24:35 Done.
515 this.selection_[i].slice.selected = true;
516 }
517 this.invalidate(); // Cause tracks to redraw.
518 }
519
414 get firstCanvas() { 520 get firstCanvas() {
415 return this.tracks_.firstChild ? 521 return this.tracks_.firstChild ?
416 this.tracks_.firstChild.firstCanvas : undefined; 522 this.tracks_.firstChild.firstCanvas : undefined;
417 }, 523 },
418 524
419 showDragBox_: function() {
420 this.dragBox_.hidden = false;
421 },
422
423 hideDragBox_: function() { 525 hideDragBox_: function() {
424 this.dragBox_.style.left = '-1000px'; 526 this.dragBox_.style.left = '-1000px';
425 this.dragBox_.style.top = '-1000px'; 527 this.dragBox_.style.top = '-1000px';
426 this.dragBox_.style.width = 0; 528 this.dragBox_.style.width = 0;
427 this.dragBox_.style.height = 0; 529 this.dragBox_.style.height = 0;
428 this.dragBox_.hidden = true;
429 },
430
431 get dragBoxVisible_() {
432 return this.dragBox_.hidden == false;
433 }, 530 },
434 531
435 setDragBoxPosition_: function(eDown, eCur) { 532 setDragBoxPosition_: function(eDown, eCur) {
436 var loX = Math.min(eDown.clientX, eCur.clientX); 533 var loX = Math.min(eDown.clientX, eCur.clientX);
437 var hiX = Math.max(eDown.clientX, eCur.clientX); 534 var hiX = Math.max(eDown.clientX, eCur.clientX);
438 var loY = Math.min(eDown.clientY, eCur.clientY); 535 var loY = Math.min(eDown.clientY, eCur.clientY);
439 var hiY = Math.max(eDown.clientY, eCur.clientY); 536 var hiY = Math.max(eDown.clientY, eCur.clientY);
440 537
441 this.dragBox_.style.left = loX + 'px'; 538 this.dragBox_.style.left = loX + 'px';
442 this.dragBox_.style.top = loY + 'px'; 539 this.dragBox_.style.top = loY + 'px';
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 var canv = this.firstCanvas; 580 var canv = this.firstCanvas;
484 var pos = { 581 var pos = {
485 x: e.clientX - canv.offsetLeft, 582 x: e.clientX - canv.offsetLeft,
486 y: e.clientY - canv.offsetTop 583 y: e.clientY - canv.offsetTop
487 }; 584 };
488 585
489 var wX = this.viewport_.xViewToWorld(pos.x); 586 var wX = this.viewport_.xViewToWorld(pos.x);
490 587
491 this.dragBeginEvent_ = e; 588 this.dragBeginEvent_ = e;
492 e.preventDefault(); 589 e.preventDefault();
590 if (this.parentElement.parentElement.tabIndex)
591 this.parentElement.parentElement.focus();
493 }, 592 },
494 593
495 onMouseMove_: function(e) { 594 onMouseMove_: function(e) {
496 if (!this.firstCanvas) 595 if (!this.firstCanvas)
497 return; 596 return;
498 var canv = this.firstCanvas; 597 var canv = this.firstCanvas;
499 var pos = { 598 var pos = {
500 x: e.clientX - canv.offsetLeft, 599 x: e.clientX - canv.offsetLeft,
501 y: e.clientY - canv.offsetTop 600 y: e.clientY - canv.offsetTop
502 }; 601 };
503 602
504 // Remember position. Used during keyboard zooming. 603 // Remember position. Used during keyboard zooming.
505 this.lastMouseViewPos_ = pos; 604 this.lastMouseViewPos_ = pos;
506 605
507 // Initiate the drag box if needed.
508 if (this.dragBeginEvent_ && !this.dragBoxVisible_) {
509 this.showDragBox_();
510 this.setDragBoxPosition_(e, e);
511 }
512
513 // Update the drag box 606 // Update the drag box
514 if (this.dragBeginEvent_) { 607 if (this.dragBeginEvent_) {
515 this.setDragBoxPosition_(this.dragBeginEvent_, e); 608 this.setDragBoxPosition_(this.dragBeginEvent_, e);
516 } 609 }
517 }, 610 },
518 611
519 onMouseUp_: function(e) { 612 onMouseUp_: function(e) {
520 var i; 613 var i;
521 if (this.dragBeginEvent_) { 614 if (this.dragBeginEvent_) {
522 // Stop the dragging. 615 // Stop the dragging.
523 this.hideDragBox_(); 616 this.hideDragBox_();
524 var eDown = this.dragBeginEvent_; 617 var eDown = this.dragBeginEvent_;
525 this.dragBeginEvent_ = null; 618 this.dragBeginEvent_ = null;
526 619
527 // Figure out extents of the drag. 620 // Figure out extents of the drag.
528 var loX = Math.min(eDown.clientX, e.clientX); 621 var loX = Math.min(eDown.clientX, e.clientX);
529 var hiX = Math.max(eDown.clientX, e.clientX); 622 var hiX = Math.max(eDown.clientX, e.clientX);
530 var loY = Math.min(eDown.clientY, e.clientY); 623 var loY = Math.min(eDown.clientY, e.clientY);
531 var hiY = Math.max(eDown.clientY, e.clientY); 624 var hiY = Math.max(eDown.clientY, e.clientY);
532 625
533 // Convert to worldspace. 626 // Convert to worldspace.
534 var canv = this.firstCanvas; 627 var canv = this.firstCanvas;
535 var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft); 628 var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft);
536 var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft); 629 var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft);
537 630
538 // Clear old selection.
539 for (i = 0; i < this.selection_.length; ++i) {
540 this.selection_[i].slice.selected = false;
541 }
542
543 // Figure out what has been hit. 631 // Figure out what has been hit.
544 var selection = []; 632 var selection = [];
545 function addHit(type, track, slice) { 633 function addHit(type, track, slice) {
546 selection.push({track: track, slice: slice}); 634 selection.push({track: track, slice: slice});
547 } 635 }
548 for (i = 0; i < this.tracks_.children.length; ++i) { 636 for (i = 0; i < this.tracks_.children.length; ++i) {
549 var track = this.tracks_.children[i]; 637 var track = this.tracks_.children[i];
550 638
551 // Only check tracks that insersect the rect. 639 // Only check tracks that insersect the rect.
552 var trackClientRect = track.getBoundingClientRect(); 640 var trackClientRect = track.getBoundingClientRect();
553 var a = Math.max(loY, trackClientRect.top); 641 var a = Math.max(loY, trackClientRect.top);
554 var b = Math.min(hiY, trackClientRect.bottom); 642 var b = Math.min(hiY, trackClientRect.bottom);
555 if (a <= b) { 643 if (a <= b) {
556 track.pickRange(loWX, hiWX, loY, hiY, addHit); 644 track.pickRange(loWX, hiWX, loY, hiY, addHit);
557 } 645 }
558 } 646 }
559 // Activate the new selection. 647 // Activate the new selection.
560 this.selection_ = selection; 648 this.selection = selection;
561 cr.dispatchSimpleEvent(this, 'selectionChange');
562 for (i = 0; i < this.selection_.length; ++i) {
563 this.selection_[i].slice.selected = true;
564 }
565 this.invalidate(); // Cause tracks to redraw.
566 } 649 }
567 }, 650 },
568 651
569 onDblClick_: function(e) { 652 onDblClick_: function(e) {
570 var scale = 4; 653 var scale = 4;
571 if (e.shiftKey) 654 if (e.shiftKey)
572 scale = 1 / scale; 655 scale = 1 / scale;
573 this.zoomBy_(scale); 656 this.zoomBy_(scale);
574 e.preventDefault(); 657 e.preventDefault();
575 }, 658 },
576 }; 659 };
577 660
578 /** 661 /**
579 * The TimelineModel being viewed by the timeline 662 * The TimelineModel being viewed by the timeline
580 * @type {TimelineModel} 663 * @type {TimelineModel}
581 */ 664 */
582 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS); 665 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS);
583 666
584 return { 667 return {
585 Timeline: Timeline 668 Timeline: Timeline
586 }; 669 };
587 }); 670 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698