| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="stylesheet" href="/core/tracks/drawing_container.css"> |
| |
| <link rel="import" href="/core/tracks/track.html"> |
| <link rel="import" href="/base/raf.html"> |
| <link rel="import" href="/base/ui.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tv.exportTo('tv.c.tracks', function() { |
| var DrawType = { |
| GENERAL_EVENT: 1, |
| INSTANT_EVENT: 2, |
| BACKGROUND: 3, |
| GRID: 4, |
| FLOW_ARROWS: 5, |
| MARKERS: 6, |
| HIGHLIGHTS: 7, |
| ANNOTATIONS: 8 |
| }; |
| |
| var DrawingContainer = tv.b.ui.define('drawing-container', |
| tv.c.tracks.Track); |
| |
| DrawingContainer.prototype = { |
| __proto__: tv.c.tracks.Track.prototype, |
| |
| decorate: function(viewport) { |
| tv.c.tracks.Track.prototype.decorate.call(this, viewport); |
| this.classList.add('drawing-container'); |
| |
| this.canvas_ = document.createElement('canvas'); |
| this.canvas_.className = 'drawing-container-canvas'; |
| this.canvas_.style.left = tv.c.constants.HEADING_WIDTH + 'px'; |
| this.appendChild(this.canvas_); |
| |
| this.ctx_ = this.canvas_.getContext('2d'); |
| |
| this.viewportChange_ = this.viewportChange_.bind(this); |
| this.viewport.addEventListener('change', this.viewportChange_); |
| }, |
| |
| // Needed to support the calls in TimelineTrackView. |
| get canvas() { |
| return this.canvas_; |
| }, |
| |
| context: function() { |
| return this.ctx_; |
| }, |
| |
| viewportChange_: function() { |
| this.invalidate(); |
| }, |
| |
| invalidate: function() { |
| if (this.rafPending_) |
| return; |
| this.rafPending_ = true; |
| |
| tv.b.requestPreAnimationFrame(this.preDraw_, this); |
| }, |
| |
| preDraw_: function() { |
| this.rafPending_ = false; |
| this.updateCanvasSizeIfNeeded_(); |
| |
| tv.b.requestAnimationFrameInThisFrameIfPossible(this.draw_, this); |
| }, |
| |
| draw_: function() { |
| this.ctx_.clearRect(0, 0, this.canvas_.width, this.canvas_.height); |
| |
| var typesToDraw = [ |
| DrawType.BACKGROUND, |
| DrawType.HIGHLIGHTS, |
| DrawType.GRID, |
| DrawType.INSTANT_EVENT, |
| DrawType.GENERAL_EVENT, |
| DrawType.MARKERS, |
| DrawType.ANNOTATIONS |
| ]; |
| |
| if (this.viewport.showFlowEvents) |
| typesToDraw.push(DrawType.FLOW_ARROWS); |
| |
| for (var idx in typesToDraw) { |
| for (var i = 0; i < this.children.length; ++i) { |
| if (!(this.children[i] instanceof tv.c.tracks.Track)) |
| continue; |
| this.children[i].drawTrack(typesToDraw[idx]); |
| } |
| } |
| |
| var pixelRatio = window.devicePixelRatio || 1; |
| var bounds = this.canvas_.getBoundingClientRect(); |
| var dt = this.viewport.currentDisplayTransform; |
| var viewLWorld = dt.xViewToWorld(0); |
| var viewRWorld = dt.xViewToWorld( |
| bounds.width * pixelRatio); |
| |
| this.viewport.drawGridLines(this.ctx_, viewLWorld, viewRWorld); |
| }, |
| |
| updateCanvasSizeIfNeeded_: function() { |
| var visibleChildTracks = |
| tv.b.asArray(this.children).filter(this.visibleFilter_); |
| |
| var thisBounds = this.getBoundingClientRect(); |
| |
| var firstChildTrackBounds = visibleChildTracks[0].getBoundingClientRect(); |
| var lastChildTrackBounds = |
| visibleChildTracks[visibleChildTracks.length - 1]. |
| getBoundingClientRect(); |
| |
| var innerWidth = firstChildTrackBounds.width - |
| tv.c.constants.HEADING_WIDTH; |
| var innerHeight = lastChildTrackBounds.bottom - firstChildTrackBounds.top; |
| |
| var pixelRatio = window.devicePixelRatio || 1; |
| if (this.canvas_.width != innerWidth * pixelRatio) { |
| this.canvas_.width = innerWidth * pixelRatio; |
| this.canvas_.style.width = innerWidth + 'px'; |
| } |
| |
| if (this.canvas_.height != innerHeight * pixelRatio) { |
| this.canvas_.height = innerHeight * pixelRatio; |
| this.canvas_.style.height = innerHeight + 'px'; |
| } |
| }, |
| |
| visibleFilter_: function(element) { |
| if (!(element instanceof tv.c.tracks.Track)) |
| return false; |
| return window.getComputedStyle(element).display !== 'none'; |
| }, |
| |
| addClosestEventToSelection: function( |
| worldX, worldMaxDist, loY, hiY, selection) { |
| for (var i = 0; i < this.children.length; ++i) { |
| if (!(this.children[i] instanceof tv.c.tracks.Track)) |
| continue; |
| var trackClientRect = this.children[i].getBoundingClientRect(); |
| var a = Math.max(loY, trackClientRect.top); |
| var b = Math.min(hiY, trackClientRect.bottom); |
| if (a <= b) { |
| this.children[i].addClosestEventToSelection( |
| worldX, worldMaxDist, loY, hiY, selection); |
| } |
| } |
| |
| tv.c.tracks.Track.prototype.addClosestEventToSelection. |
| apply(this, arguments); |
| }, |
| |
| addEventsToTrackMap: function(eventToTrackMap) { |
| for (var i = 0; i < this.children.length; ++i) { |
| if (!(this.children[i] instanceof tv.c.tracks.Track)) |
| continue; |
| this.children[i].addEventsToTrackMap(eventToTrackMap); |
| } |
| }, |
| |
| addContainersToTrackMap: function(containerToTrackMap) { |
| for (var i = 0; i < this.children.length; ++i) { |
| if (!(this.children[i] instanceof tv.c.tracks.Track)) |
| continue; |
| this.children[i].addContainersToTrackMap(containerToTrackMap); |
| } |
| } |
| }; |
| |
| return { |
| DrawingContainer: DrawingContainer, |
| DrawType: DrawType |
| }; |
| }); |
| </script> |