| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <!-- | 2 <!-- |
| 3 Copyright (c) 2014 The Chromium Authors. All rights reserved. | 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 | 4 Use of this source code is governed by a BSD-style license that can be |
| 5 found in the LICENSE file. | 5 found in the LICENSE file. |
| 6 --> | 6 --> |
| 7 | 7 |
| 8 <link rel="import" href="/tracing/base/color_scheme.html"> | 8 <link rel="import" href="/tracing/base/color_scheme.html"> |
| 9 <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> | 9 <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> |
| 10 <link rel="import" href="/tracing/ui/base/d3.html"> | 10 <link rel="import" href="/tracing/ui/base/d3.html"> |
| 11 <link rel="import" href="/tracing/ui/base/ui.html"> | 11 <link rel="import" href="/tracing/ui/base/ui.html"> |
| 12 | 12 |
| 13 <polymer-element name="tr-ui-b-chart-legend-key"> | 13 <polymer-element name="tr-ui-b-chart-legend-key"> |
| 14 <template> | 14 <template> |
| 15 <style> | 15 <style> |
| 16 #checkbox { | 16 #checkbox { |
| 17 margin: 0; | 17 margin: 0; |
| 18 visibility: hidden; | 18 visibility: hidden; |
| 19 vertical-align: text-top; | 19 vertical-align: text-top; |
| 20 } | 20 } |
| 21 #label, #link { | 21 #label, #link { |
| 22 white-space: nowrap; | 22 white-space: nowrap; |
| 23 text-overflow: ellipsis; | 23 text-overflow: ellipsis; |
| 24 overflow: hidden; | 24 overflow: hidden; |
| 25 display: inline-block; | 25 display: inline-block; |
| 26 width: 50px; | |
| 27 } | 26 } |
| 28 </style> | 27 </style> |
| 29 | 28 |
| 30 <input type=checkbox id="checkbox" checked> | 29 <input type=checkbox id="checkbox" checked> |
| 31 <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link> | 30 <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link> |
| 32 <label id="label"></label> | 31 <label id="label"></label> |
| 33 </template> | 32 </template> |
| 34 | 33 |
| 35 <script> | 34 <script> |
| 36 'use strict'; | 35 'use strict'; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 48 tr.b.dispatchSimpleEvent(this, tr.ui.b.DataSeriesEnableChangeEventType, | 47 tr.b.dispatchSimpleEvent(this, tr.ui.b.DataSeriesEnableChangeEventType, |
| 49 true, false, {key: this.textContent, enabled: this.enabled}); | 48 true, false, {key: this.textContent, enabled: this.enabled}); |
| 50 }, | 49 }, |
| 51 | 50 |
| 52 set textContent(t) { | 51 set textContent(t) { |
| 53 this.$.label.textContent = t; | 52 this.$.label.textContent = t; |
| 54 this.$.link.textContent = t; | 53 this.$.link.textContent = t; |
| 55 this.updateContents_(); | 54 this.updateContents_(); |
| 56 }, | 55 }, |
| 57 | 56 |
| 57 set width(w) { |
| 58 w -= 20; // reserve 20px for the checkbox |
| 59 this.$.link.style.width = w + 'px'; |
| 60 this.$.label.style.width = w + 'px'; |
| 61 }, |
| 62 |
| 58 get textContent() { | 63 get textContent() { |
| 59 return this.$.label.textContent; | 64 return this.$.label.textContent; |
| 60 }, | 65 }, |
| 61 | 66 |
| 62 /** | 67 /** |
| 63 * When a legend-key is "optional", then its checkbox is visible to allow | 68 * When a legend-key is "optional", then its checkbox is visible to allow |
| 64 * the user to enable/disable the data series for the key. | 69 * the user to enable/disable the data series for the key. |
| 65 * See ChartBase.customizeOptionalSeries(). | 70 * See ChartBase.customizeOptionalSeries(). |
| 66 * | 71 * |
| 67 * @param {boolean} optional | 72 * @param {boolean} optional |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 }); | 117 }); |
| 113 </script> | 118 </script> |
| 114 </polymer-element> | 119 </polymer-element> |
| 115 | 120 |
| 116 <style> | 121 <style> |
| 117 * /deep/ .chart-base #title { | 122 * /deep/ .chart-base #title { |
| 118 font-size: 16pt; | 123 font-size: 16pt; |
| 119 } | 124 } |
| 120 | 125 |
| 121 * /deep/ .chart-base { | 126 * /deep/ .chart-base { |
| 122 font-size: 12pt; | |
| 123 -webkit-user-select: none; | 127 -webkit-user-select: none; |
| 124 cursor: default; | 128 cursor: default; |
| 125 } | 129 } |
| 126 | 130 |
| 127 * /deep/ .chart-base .axis path, | 131 * /deep/ .chart-base .axis path, |
| 128 * /deep/ .chart-base .axis line { | 132 * /deep/ .chart-base .axis line { |
| 129 fill: none; | 133 fill: none; |
| 130 shape-rendering: crispEdges; | 134 shape-rendering: crispEdges; |
| 131 stroke: #000; | 135 stroke: #000; |
| 132 } | 136 } |
| 137 |
| 138 * /deep/ .chart-base .legend body { |
| 139 margin: 0; |
| 140 } |
| 133 </style> | 141 </style> |
| 134 | 142 |
| 135 <template id="chart-base-template"> | 143 <template id="chart-base-template"> |
| 136 <svg> <!-- svg tag is dropped by ChartBase.decorate. --> | 144 <svg> <!-- svg tag is dropped by ChartBase.decorate. --> |
| 137 <g xmlns="http://www.w3.org/2000/svg" id="chart-area"> | 145 <g xmlns="http://www.w3.org/2000/svg" id="chart-area"> |
| 138 <g class="x axis"></g> | 146 <g class="x axis"></g> |
| 139 <g class="y axis"></g> | 147 <g class="y axis"></g> |
| 140 <text id="title"></text> | 148 <text id="title"></text> |
| 141 </g> | 149 </g> |
| 142 </svg> | 150 </svg> |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 this.seriesByKey_.set(key, new DataSeries(key)); | 225 this.seriesByKey_.set(key, new DataSeries(key)); |
| 218 return this.seriesByKey_.get(key); | 226 return this.seriesByKey_.get(key); |
| 219 }, | 227 }, |
| 220 | 228 |
| 221 decorate: function() { | 229 decorate: function() { |
| 222 this.classList.add('chart-base'); | 230 this.classList.add('chart-base'); |
| 223 this.chartTitle_ = undefined; | 231 this.chartTitle_ = undefined; |
| 224 this.seriesByKey_ = new Map(); | 232 this.seriesByKey_ = new Map(); |
| 225 this.width_ = 400; | 233 this.width_ = 400; |
| 226 this.height_ = 300; | 234 this.height_ = 300; |
| 235 this.margin = {top: 20, right: 72, bottom: 30, left: 50}; |
| 227 | 236 |
| 228 // This should use tr.ui.b.instantiateTemplate. However, creating | 237 // This should use tr.ui.b.instantiateTemplate. However, creating |
| 229 // svg-namespaced elements inside a template isn't possible. Thus, this | 238 // svg-namespaced elements inside a template isn't possible. Thus, this |
| 230 // hack. | 239 // hack. |
| 231 var template = THIS_DOC.querySelector('#chart-base-template'); | 240 var template = THIS_DOC.querySelector('#chart-base-template'); |
| 232 var svgEl = template.content.querySelector('svg'); | 241 var svgEl = template.content.querySelector('svg'); |
| 233 for (var i = 0; i < svgEl.children.length; i++) | 242 for (var i = 0; i < svgEl.children.length; i++) |
| 234 this.appendChild(svgEl.children[i].cloneNode(true)); | 243 this.appendChild(svgEl.children[i].cloneNode(true)); |
| 235 | 244 |
| 236 // svg likes to take over width & height properties for some reason. This | 245 // svg likes to take over width & height properties for some reason. This |
| (...skipping 29 matching lines...) Expand all Loading... |
| 266 onDataSeriesEnableChange_: function(event) { | 275 onDataSeriesEnableChange_: function(event) { |
| 267 this.getDataSeries(event.key).enabled = event.enabled; | 276 this.getDataSeries(event.key).enabled = event.enabled; |
| 268 this.updateContents_(); | 277 this.updateContents_(); |
| 269 }, | 278 }, |
| 270 | 279 |
| 271 get chartTitle() { | 280 get chartTitle() { |
| 272 return this.chartTitle_; | 281 return this.chartTitle_; |
| 273 }, | 282 }, |
| 274 | 283 |
| 275 set chartTitle(chartTitle) { | 284 set chartTitle(chartTitle) { |
| 285 if (chartTitle && !this.chartTitle_) |
| 286 this.margin.top += this.titleMarginPx; |
| 287 else if (this.chartTitle_ && !chartTitle) |
| 288 this.margin.top -= this.titleMarginPx; |
| 289 |
| 276 this.chartTitle_ = chartTitle; | 290 this.chartTitle_ = chartTitle; |
| 277 this.updateContents_(); | 291 this.updateContents_(); |
| 278 }, | 292 }, |
| 279 | 293 |
| 294 get titleMarginPx() { |
| 295 return 20; |
| 296 }, |
| 297 |
| 280 get chartAreaElement() { | 298 get chartAreaElement() { |
| 281 return this.querySelector('#chart-area'); | 299 return this.querySelector('#chart-area'); |
| 282 }, | 300 }, |
| 283 | 301 |
| 284 setSize: function(size) { | 302 setSize: function(size) { |
| 285 this.width_ = size.width; | 303 this.width_ = size.width; |
| 286 this.height_ = size.height; | 304 this.height_ = size.height; |
| 287 this.updateContents_(); | 305 this.updateContents_(); |
| 288 }, | 306 }, |
| 289 | 307 |
| 290 getMargin_: function() { | |
| 291 var margin = {top: 20, right: 72, bottom: 30, left: 50}; | |
| 292 if (this.chartTitle_) | |
| 293 margin.top += 20; | |
| 294 return margin; | |
| 295 }, | |
| 296 | |
| 297 get margin() { | |
| 298 return this.getMargin_(); | |
| 299 }, | |
| 300 | |
| 301 get chartAreaSize() { | 308 get chartAreaSize() { |
| 302 var margin = this.margin; | |
| 303 return { | 309 return { |
| 304 width: this.width_ - margin.left - margin.right, | 310 width: this.width_ - this.margin.left - this.margin.right, |
| 305 height: this.height_ - margin.top - margin.bottom | 311 height: this.height_ - this.margin.top - this.margin.bottom |
| 306 }; | 312 }; |
| 307 }, | 313 }, |
| 308 | 314 |
| 309 /** | 315 /** |
| 310 * Legend keys can be clickable links instead of plain text. | 316 * Legend keys can be clickable links instead of plain text. |
| 311 * When a legend key link is clicked, a RequestSelectionChangeEvent is | 317 * When a legend key link is clicked, a RequestSelectionChangeEvent is |
| 312 * dispatched containing arbitrary data. ChartBase calls that arbitrary data | 318 * dispatched containing arbitrary data. ChartBase calls that arbitrary data |
| 313 * the "target" of the legend key link. | 319 * the "target" of the legend key link. |
| 314 * In order to turn the legend key for the 'foo' data series into a | 320 * In order to turn the legend key for the 'foo' data series into a |
| 315 * clickable link, call customizeLegendTargets({foo: target}). When the user | 321 * clickable link, call customizeLegendTargets({foo: target}). When the user |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 tr.b.iterItems(delta, function(key, value) { | 363 tr.b.iterItems(delta, function(key, value) { |
| 358 this.getDataSeries(key).enabled = value; | 364 this.getDataSeries(key).enabled = value; |
| 359 }, this); | 365 }, this); |
| 360 }, | 366 }, |
| 361 | 367 |
| 362 updateScales_: function() { | 368 updateScales_: function() { |
| 363 throw new Error('Not implemented'); | 369 throw new Error('Not implemented'); |
| 364 }, | 370 }, |
| 365 | 371 |
| 366 updateContents_: function() { | 372 updateContents_: function() { |
| 367 var margin = this.margin; | |
| 368 | |
| 369 var thisSel = d3.select(this); | 373 var thisSel = d3.select(this); |
| 370 thisSel.attr('width', this.width_); | 374 thisSel.attr('width', this.width_); |
| 371 thisSel.attr('height', this.height_); | 375 thisSel.attr('height', this.height_); |
| 372 | 376 |
| 373 var chartAreaSel = d3.select(this.chartAreaElement); | 377 var chartAreaSel = d3.select(this.chartAreaElement); |
| 374 chartAreaSel.attr('transform', | 378 chartAreaSel.attr('transform', |
| 375 'translate(' + margin.left + ',' + margin.top + ')'); | 379 'translate(' + this.margin.left + ',' + this.margin.top + ')'); |
| 376 | 380 |
| 377 this.updateScales_(); | 381 this.updateScales_(); |
| 378 this.updateTitle_(chartAreaSel); | 382 this.updateTitle_(chartAreaSel); |
| 379 this.updateLegend_(); | 383 this.updateLegend_(); |
| 380 }, | 384 }, |
| 381 | 385 |
| 382 updateTitle_: function(chartAreaSel) { | 386 updateTitle_: function(chartAreaSel) { |
| 383 var titleSel = chartAreaSel.select('#title'); | 387 var titleSel = chartAreaSel.select('#title'); |
| 384 if (!this.chartTitle_) { | 388 if (!this.chartTitle_) { |
| 385 titleSel.style('display', 'none'); | 389 titleSel.style('display', 'none'); |
| 386 return; | 390 return; |
| 387 } | 391 } |
| 388 var width = this.chartAreaSize.width; | 392 var width = this.chartAreaSize.width; |
| 389 titleSel.attr('transform', 'translate(' + width * 0.5 + ',-5)') | 393 titleSel.attr('transform', 'translate(' + width * 0.5 + ',-5)') |
| 390 .style('display', undefined) | 394 .style('display', undefined) |
| 391 .style('text-anchor', 'middle') | 395 .style('text-anchor', 'middle') |
| 392 .attr('class', 'title') | 396 .attr('class', 'title') |
| 393 .attr('width', width) | 397 .attr('width', width) |
| 394 .text(this.chartTitle_); | 398 .text(this.chartTitle_); |
| 395 }, | 399 }, |
| 396 | 400 |
| 397 updateLegend_: function() { | 401 updateLegend_: function() { |
| 398 var chartAreaSel = d3.select(this.chartAreaElement); | 402 var chartAreaSel = d3.select(this.chartAreaElement); |
| 399 chartAreaSel.selectAll('.legend').remove(); | 403 chartAreaSel.selectAll('.legend').remove(); |
| 400 | 404 |
| 401 var series = [...this.seriesByKey_.values()].reverse(); | 405 var series = [...this.seriesByKey_.values()].reverse(); |
| 402 var legendEntriesSel = chartAreaSel.selectAll('.legend').data(series); | 406 var legendEntriesSel = chartAreaSel.selectAll('.legend').data(series); |
| 403 | 407 |
| 408 var width = this.margin.right - 2; |
| 404 legendEntriesSel.enter() | 409 legendEntriesSel.enter() |
| 405 .append('foreignObject') | 410 .append('foreignObject') |
| 406 .attr('class', 'legend') | 411 .attr('class', 'legend') |
| 407 .attr('x', this.chartAreaSize.width + 2) | 412 .attr('x', this.chartAreaSize.width + 2) |
| 408 .attr('width', 70) | 413 .attr('width', width) |
| 409 .attr('height', 18) | 414 .attr('height', 18) |
| 410 .attr('transform', function(series, i) { | 415 .attr('transform', function(series, i) { |
| 411 return 'translate(0,' + i * 18 + ')'; | 416 return 'translate(0,' + i * 18 + ')'; |
| 412 }) | 417 }) |
| 413 .append('xhtml:body') | 418 .append('xhtml:body') |
| 414 .append('tr-ui-b-chart-legend-key') | 419 .append('tr-ui-b-chart-legend-key') |
| 415 .property('color', function(series) { | 420 .property('color', function(series) { |
| 416 var selected = this.currentHighlightedLegendKey === series.key; | 421 var selected = this.currentHighlightedLegendKey === series.key; |
| 417 return getColorOfKey(series.key, selected); | 422 return getColorOfKey(series.key, selected); |
| 418 }.bind(this)) | 423 }.bind(this)) |
| 424 .property('width', width) |
| 419 .property('target', function(series) { return series.target; }) | 425 .property('target', function(series) { return series.target; }) |
| 420 .property('optional', function(series) { return series.optional; }) | 426 .property('optional', function(series) { return series.optional; }) |
| 421 .property('enabled', function(series) { return series.enabled; }) | 427 .property('enabled', function(series) { return series.enabled; }) |
| 422 .text(function(series) { return series.key; }); | 428 .text(function(series) { return series.key; }); |
| 423 legendEntriesSel.exit().remove(); | 429 legendEntriesSel.exit().remove(); |
| 424 }, | 430 }, |
| 425 | 431 |
| 426 get highlightedLegendKey() { | 432 get highlightedLegendKey() { |
| 427 return this.highlightedLegendKey_; | 433 return this.highlightedLegendKey_; |
| 428 }, | 434 }, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 } | 476 } |
| 471 }; | 477 }; |
| 472 | 478 |
| 473 return { | 479 return { |
| 474 DataSeriesEnableChangeEventType: DataSeriesEnableChangeEventType, | 480 DataSeriesEnableChangeEventType: DataSeriesEnableChangeEventType, |
| 475 getColorOfKey: getColorOfKey, | 481 getColorOfKey: getColorOfKey, |
| 476 ChartBase: ChartBase | 482 ChartBase: ChartBase |
| 477 }; | 483 }; |
| 478 }); | 484 }); |
| 479 </script> | 485 </script> |
| OLD | NEW |