1 <!DOCTYPE html> 2 <!-- 3 Copyright (c) 2014 The Chromium Authors. All rights reserved. 4 Use of this source code is governed by a BSD-style license that can be 5 found in the LICENSE file. 6 --> 7 8 <link rel="import" href="/base/range.html"> 9 10 <script> 11 'use strict'; 12 13 tr.exportTo('tr.ui', function() { 14 /** 15 * @constructor 16 */ 17 function SnapIndicator(y, height) { 18 this.y = y; 19 this.height = height; 20 } 21 22 /** 23 * The interesting part of the world. 24 * 25 * @constructor 26 */ 27 function TimelineInterestRange(vp) { 28 this.viewport_ = vp; 29 30 this.range_ = new tr.b.Range(); 31 32 this.leftSelected_ = false; 33 this.rightSelected_ = false; 34 35 this.leftSnapIndicator_ = undefined; 36 this.rightSnapIndicator_ = undefined; 37 } 38 39 TimelineInterestRange.prototype = { 40 get isEmpty() { 41 return this.range_.isEmpty; 42 }, 43 44 reset: function() { 45 this.range_.reset(); 46 this.leftSelected_ = false; 47 this.rightSelected_ = false; 48 this.leftSnapIndicator_ = undefined; 49 this.rightSnapIndicator_ = undefined; 50 this.viewport_.dispatchChangeEvent(); 51 }, 52 53 get min() { 54 return this.range_.min; 55 }, 56 57 set min(min) { 58 this.range_.min = min; 59 this.viewport_.dispatchChangeEvent(); 60 }, 61 62 get max() { 63 return this.range_.max; 64 }, 65 66 set max(max) { 67 this.range_.max = max; 68 this.viewport_.dispatchChangeEvent(); 69 }, 70 71 set: function(range) { 72 this.range_.reset(); 73 this.range_.addRange(range); 74 this.viewport_.dispatchChangeEvent(); 75 }, 76 77 setMinAndMax: function(min, max) { 78 this.range_.min = min; 79 this.range_.max = max; 80 this.viewport_.dispatchChangeEvent(); 81 }, 82 83 get range() { 84 return this.range_.range; 85 }, 86 87 asRangeObject: function() { 88 var range = new tr.b.Range(); 89 range.addRange(this.range_); 90 return range; 91 }, 92 93 get leftSelected() { 94 return this.leftSelected_; 95 }, 96 97 set leftSelected(leftSelected) { 98 if (this.leftSelected_ == leftSelected) 99 return; 100 this.leftSelected_ = leftSelected; 101 this.viewport_.dispatchChangeEvent(); 102 }, 103 104 get rightSelected() { 105 return this.rightSelected_; 106 }, 107 108 set rightSelected(rightSelected) { 109 if (this.rightSelected_ == rightSelected) 110 return; 111 this.rightSelected_ = rightSelected; 112 this.viewport_.dispatchChangeEvent(); 113 }, 114 115 get leftSnapIndicator() { 116 return this.leftSnapIndicator_; 117 }, 118 119 set leftSnapIndicator(leftSnapIndicator) { 120 this.leftSnapIndicator_ = leftSnapIndicator; 121 this.viewport_.dispatchChangeEvent(); 122 }, 123 124 get rightSnapIndicator() { 125 return this.rightSnapIndicator_; 126 }, 127 128 set rightSnapIndicator(rightSnapIndicator) { 129 this.rightSnapIndicator_ = rightSnapIndicator; 130 this.viewport_.dispatchChangeEvent(); 131 }, 132 133 draw: function(ctx, viewLWorld, viewRWorld) { 134 if (this.range_.isEmpty) 135 return; 136 var dt = this.viewport_.currentDisplayTransform; 137 138 var markerLWorld = this.min; 139 var markerRWorld = this.max; 140 141 var markerLView = Math.round(dt.xWorldToView(markerLWorld)); 142 var markerRView = Math.round(dt.xWorldToView(markerRWorld)); 143 144 ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; 145 if (markerLWorld > viewLWorld) { 146 ctx.fillRect(dt.xWorldToView(viewLWorld), 0, 147 markerLView, ctx.canvas.height); 148 } 149 150 if (markerRWorld < viewRWorld) { 151 ctx.fillRect(markerRView, 0, 152 dt.xWorldToView(viewRWorld), ctx.canvas.height); 153 } 154 155 var pixelRatio = window.devicePixelRatio || 1; 156 ctx.lineWidth = Math.round(pixelRatio); 157 if (this.range_.range > 0) { 158 this.drawLine_(ctx, viewLWorld, viewRWorld, 159 ctx.canvas.height, this.min, this.leftSelected_); 160 this.drawLine_(ctx, viewLWorld, viewRWorld, 161 ctx.canvas.height, this.max, this.rightSelected_); 162 } else { 163 this.drawLine_(ctx, viewLWorld, viewRWorld, 164 ctx.canvas.height, this.min, 165 this.leftSelected_ || this.rightSelected_); 166 } 167 ctx.lineWidth = 1; 168 }, 169 170 drawLine_: function(ctx, viewLWorld, viewRWorld, height, ts, selected) { 171 if (ts < viewLWorld || ts >= viewRWorld) 172 return; 173 174 var dt = this.viewport_.currentDisplayTransform; 175 var viewX = Math.round(dt.xWorldToView(ts)); 176 177 // Apply subpixel translate to get crisp lines. 178 // http://www.mobtowers.com/html5-canvas-crisp-lines-every-time/ 179 ctx.save(); 180 ctx.translate((Math.round(ctx.lineWidth) % 2) / 2, 0); 181 182 ctx.beginPath(); 183 tr.ui.b.drawLine(ctx, viewX, 0, viewX, height); 184 if (selected) 185 ctx.strokeStyle = 'rgb(255, 0, 0)'; 186 else 187 ctx.strokeStyle = 'rgb(0, 0, 0)'; 188 ctx.stroke(); 189 190 ctx.restore(); 191 }, 192 193 drawIndicators: function(ctx, viewLWorld, viewRWorld) { 194 if (this.leftSnapIndicator_) { 195 this.drawIndicator_(ctx, viewLWorld, viewRWorld, 196 this.range_.min, 197 this.leftSnapIndicator_, 198 this.leftSelected_); 199 } 200 if (this.rightSnapIndicator_) { 201 this.drawIndicator_(ctx, viewLWorld, viewRWorld, 202 this.range_.max, 203 this.rightSnapIndicator_, 204 this.rightSelected_); 205 } 206 }, 207 208 drawIndicator_: function(ctx, viewLWorld, viewRWorld, 209 xWorld, si, selected) { 210 var dt = this.viewport_.currentDisplayTransform; 211 212 var viewX = Math.round(dt.xWorldToView(xWorld)); 213 214 // Apply subpixel translate to get crisp lines. 215 // http://www.mobtowers.com/html5-canvas-crisp-lines-every-time/ 216 ctx.save(); 217 ctx.translate((Math.round(ctx.lineWidth) % 2) / 2, 0); 218 219 var pixelRatio = window.devicePixelRatio || 1; 220 var viewY = si.y * devicePixelRatio; 221 var viewHeight = si.height * devicePixelRatio; 222 var arrowSize = 4 * pixelRatio; 223 224 if (selected) 225 ctx.fillStyle = 'rgb(255, 0, 0)'; 226 else 227 ctx.fillStyle = 'rgb(0, 0, 0)'; 228 tr.ui.b.drawTriangle(ctx, 229 viewX - arrowSize * 0.75, viewY, 230 viewX + arrowSize * 0.75, viewY, 231 viewX, viewY + arrowSize); 232 ctx.fill(); 233 tr.ui.b.drawTriangle(ctx, 234 viewX - arrowSize * 0.75, viewY + viewHeight, 235 viewX + arrowSize * 0.75, viewY + viewHeight, 236 viewX, viewY + viewHeight - arrowSize); 237 ctx.fill(); 238 239 ctx.restore(); 240 } 241 }; 242 243 return { 244 SnapIndicator: SnapIndicator, 245 TimelineInterestRange: TimelineInterestRange 246 }; 247 }); 248 </script> 249