| 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/iteration_helpers.html"> | 8 <link rel="import" href="/tracing/base/iteration_helpers.html"> |
| 9 <link rel="import" href="/tracing/base/range.html"> | 9 <link rel="import" href="/tracing/base/range.html"> |
| 10 <link rel="import" href="/tracing/ui/base/chart_base.html"> | 10 <link rel="import" href="/tracing/ui/base/chart_base.html"> |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 __proto__: ChartBase.prototype, | 31 __proto__: ChartBase.prototype, |
| 32 | 32 |
| 33 decorate: function() { | 33 decorate: function() { |
| 34 ChartBase.prototype.decorate.call(this); | 34 ChartBase.prototype.decorate.call(this); |
| 35 this.classList.add('chart-base-2d'); | 35 this.classList.add('chart-base-2d'); |
| 36 this.xScale_ = d3.scale.linear(); | 36 this.xScale_ = d3.scale.linear(); |
| 37 this.yScale_ = d3.scale.linear(); | 37 this.yScale_ = d3.scale.linear(); |
| 38 this.isYLogScale_ = false; | 38 this.isYLogScale_ = false; |
| 39 this.yLogScaleMin_ = undefined; | 39 this.yLogScaleMin_ = undefined; |
| 40 this.dataRange_ = new tr.b.Range(); | 40 this.dataRange_ = new tr.b.Range(); |
| 41 | 41 this.hideXAxis_ = false; |
| 42 this.hideYAxis_ = false; |
| 42 this.data_ = []; | 43 this.data_ = []; |
| 43 this.seriesKeys_ = []; | |
| 44 this.leftMargin_ = 50; | 44 this.leftMargin_ = 50; |
| 45 | 45 |
| 46 d3.select(this.chartAreaElement) | 46 d3.select(this.chartAreaElement) |
| 47 .append('g') | 47 .append('g') |
| 48 .attr('id', 'brushes'); | 48 .attr('id', 'brushes'); |
| 49 d3.select(this.chartAreaElement) | 49 d3.select(this.chartAreaElement) |
| 50 .append('g') | 50 .append('g') |
| 51 .attr('id', 'series'); | 51 .attr('id', 'series'); |
| 52 | 52 |
| 53 this.addEventListener('mousedown', this.onMouseDown_.bind(this)); | 53 this.addEventListener('mousedown', this.onMouseDown_.bind(this)); |
| 54 }, | 54 }, |
| 55 | 55 |
| 56 get hideXAxis() { |
| 57 return this.hideXAxis_; |
| 58 }, |
| 59 |
| 60 set hideXAxis(h) { |
| 61 this.hideXAxis_ = h; |
| 62 this.updateContents_(); |
| 63 }, |
| 64 |
| 65 get hideYAxis() { |
| 66 return this.hideYAxis_; |
| 67 }, |
| 68 |
| 69 set hideYAxis(h) { |
| 70 this.hideYAxis_ = h; |
| 71 this.updateContents_(); |
| 72 }, |
| 73 |
| 56 get data() { | 74 get data() { |
| 57 return this.data_; | 75 return this.data_; |
| 58 }, | 76 }, |
| 59 | 77 |
| 60 /** | 78 /** |
| 61 * Sets the data array for the object | 79 * Sets the data array for the object |
| 62 * | 80 * |
| 63 * @param {Array} data The data. Each element must be an object, with at | 81 * @param {Array} data The data. Each element must be an object, with at |
| 64 * least an x property. All other properties become series names in the | 82 * least an x property. All other properties become series names in the |
| 65 * chart. The data can be sparse (i.e. every x value does not have to | 83 * chart. The data can be sparse (i.e. every x value does not have to |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 leftIndex = index; | 120 leftIndex = index; |
| 103 rightIndex = Math.min(index + 1, data.length - 1); | 121 rightIndex = Math.min(index + 1, data.length - 1); |
| 104 } | 122 } |
| 105 var leftWidth = this.getXForDatum_(data[index], index) - | 123 var leftWidth = this.getXForDatum_(data[index], index) - |
| 106 this.getXForDatum_(data[leftIndex], leftIndex); | 124 this.getXForDatum_(data[leftIndex], leftIndex); |
| 107 var rightWidth = this.getXForDatum_(data[rightIndex], rightIndex) - | 125 var rightWidth = this.getXForDatum_(data[rightIndex], rightIndex) - |
| 108 this.getXForDatum_(data[index], index); | 126 this.getXForDatum_(data[index], index); |
| 109 return leftWidth * 0.5 + rightWidth * 0.5; | 127 return leftWidth * 0.5 + rightWidth * 0.5; |
| 110 }, | 128 }, |
| 111 | 129 |
| 112 getLegendKeys_: function() { | |
| 113 if (this.seriesKeys_ && | |
| 114 this.seriesKeys_.length > 1) | |
| 115 return this.seriesKeys_.slice(); | |
| 116 return []; | |
| 117 }, | |
| 118 | |
| 119 updateSeriesKeys_: function() { | 130 updateSeriesKeys_: function() { |
| 120 // Accumulate the keys on each data point. | 131 // Don't clear seriesByKey_; the caller might have put state in it using |
| 121 var keySet = {}; | 132 // customizeLegendTargets, customizeOptionalSeries, or |
| 133 // customizeEnabledSeries before setting data. |
| 122 this.data_.forEach(function(datum) { | 134 this.data_.forEach(function(datum) { |
| 123 Object.keys(datum).forEach(function(key) { | 135 Object.keys(datum).forEach(function(key) { |
| 124 if (this.isDatumFieldSeries_(key)) | 136 if (this.isDatumFieldSeries_(key)) |
| 125 keySet[key] = true; | 137 this.getDataSeries(key); |
| 126 }, this); | 138 }, this); |
| 127 }, this); | 139 }, this); |
| 128 this.seriesKeys_ = Object.keys(keySet); | |
| 129 }, | 140 }, |
| 130 | 141 |
| 131 isDatumFieldSeries_: function(fieldName) { | 142 isDatumFieldSeries_: function(fieldName) { |
| 132 throw new Error('Not implemented'); | 143 throw new Error('Not implemented'); |
| 133 }, | 144 }, |
| 134 | 145 |
| 135 getXForDatum_: function(datum, index) { | 146 getXForDatum_: function(datum, index) { |
| 136 throw new Error('Not implemented'); | 147 throw new Error('Not implemented'); |
| 137 }, | 148 }, |
| 138 | 149 |
| 139 updateScales_: function() { | 150 updateScales_: function() { |
| 140 if (this.data_.length === 0) | 151 if (this.data_.length === 0) |
| 141 return; | 152 return; |
| 142 | 153 |
| 143 var width = this.chartAreaSize.width; | 154 var width = this.chartAreaSize.width; |
| 144 var height = this.chartAreaSize.height; | 155 var height = this.chartAreaSize.height; |
| 145 | 156 |
| 146 // X. | 157 // X. |
| 147 this.xScale_.range([0, width]); | 158 this.xScale_.range([0, width]); |
| 148 this.xScale_.domain(d3.extent(this.data_, this.getXForDatum_.bind(this))); | 159 this.xScale_.domain(d3.extent(this.data_, this.getXForDatum_.bind(this))); |
| 149 | 160 |
| 150 // Y. | 161 // Y. |
| 151 var yRange = new tr.b.Range(); | 162 var yRange = new tr.b.Range(); |
| 152 var keySet = new Set(this.seriesKeys_); | 163 for (var i = 0; i < this.data_.length; i++) { |
| 153 for (var i = 0; i < this.data_.length; i++) | 164 for (var key in this.data_[i]) { |
| 154 for (var key in this.data_[i]) | 165 if (!isNaN(Math.max(this.data_[i][key]))) |
| 155 if (keySet.has(key)) | |
| 156 yRange.addValue(this.data_[i][key]); | 166 yRange.addValue(this.data_[i][key]); |
| 167 } |
| 168 } |
| 157 | 169 |
| 158 this.yScale_.range([height, 0]); | 170 this.yScale_.range([height, 0]); |
| 159 this.yScale_.domain([yRange.min, yRange.max]); | 171 this.yScale_.domain([yRange.min, yRange.max]); |
| 160 }, | 172 }, |
| 161 | 173 |
| 162 updateBrushContents_: function(brushSel) { | 174 updateBrushContents_: function(brushSel) { |
| 163 brushSel.selectAll('*').remove(); | 175 brushSel.selectAll('*').remove(); |
| 164 }, | 176 }, |
| 165 | 177 |
| 166 updateXAxis_: function(xAxis) { | 178 updateXAxis_: function(xAxis) { |
| 167 xAxis.selectAll('*').remove(); | 179 xAxis.selectAll('*').remove(); |
| 168 xAxis[0][0].style.opacity = 0; | 180 xAxis[0][0].style.opacity = 0; |
| 181 if (this.hideXAxis) |
| 182 return; |
| 183 |
| 169 xAxis.attr('transform', 'translate(0,' + this.chartAreaSize.height + ')') | 184 xAxis.attr('transform', 'translate(0,' + this.chartAreaSize.height + ')') |
| 170 .call(d3.svg.axis() | 185 .call(d3.svg.axis() |
| 171 .scale(this.xScale_) | 186 .scale(this.xScale_) |
| 172 .orient('bottom')); | 187 .orient('bottom')); |
| 173 window.requestAnimationFrame(function() { | 188 window.requestAnimationFrame(function() { |
| 174 var previousRight = undefined; | 189 var previousRight = undefined; |
| 175 xAxis.selectAll('.tick')[0].forEach(function(tick) { | 190 xAxis.selectAll('.tick')[0].forEach(function(tick) { |
| 176 var currentLeft = tick.transform.baseVal[0].matrix.e; | 191 var currentLeft = tick.transform.baseVal[0].matrix.e; |
| 177 if ((previousRight === undefined) || | 192 if ((previousRight === undefined) || |
| 178 (currentLeft > (previousRight + 3))) { | 193 (currentLeft > (previousRight + 3))) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 | 226 |
| 212 var onePowerLess = Math.floor( | 227 var onePowerLess = Math.floor( |
| 213 Math.log(minValue) / Math.log(10)) - 1; | 228 Math.log(minValue) / Math.log(10)) - 1; |
| 214 this.yLogScaleMin_ = Math.pow(10, onePowerLess); | 229 this.yLogScaleMin_ = Math.pow(10, onePowerLess); |
| 215 } | 230 } |
| 216 }, | 231 }, |
| 217 | 232 |
| 218 updateYAxis_: function(yAxis) { | 233 updateYAxis_: function(yAxis) { |
| 219 yAxis.selectAll('*').remove(); | 234 yAxis.selectAll('*').remove(); |
| 220 yAxis[0][0].style.opacity = 0; | 235 yAxis[0][0].style.opacity = 0; |
| 236 if (this.hideYAxis) |
| 237 return; |
| 221 | 238 |
| 222 var axisModifier = d3.svg.axis() | 239 var axisModifier = d3.svg.axis() |
| 223 .scale(this.yScale_) | 240 .scale(this.yScale_) |
| 224 .orient('left'); | 241 .orient('left'); |
| 225 | 242 |
| 226 if (this.isYLogScale_) { | 243 if (this.isYLogScale_) { |
| 227 if (this.yLogScaleMin_ === undefined) | 244 if (this.yLogScaleMin_ === undefined) |
| 228 return; | 245 return; |
| 229 var minValue = this.dataRange_.min; | 246 var minValue = this.dataRange_.min; |
| 230 if (minValue == 0) | 247 if (minValue == 0) |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 * Returns a map of series key to the data for that series. | 306 * Returns a map of series key to the data for that series. |
| 290 * | 307 * |
| 291 * Example: | 308 * Example: |
| 292 * // returns {y: [{x: 1, y: 1}, {x: 3, y: 3}], z: [{x: 2, z: 2}]} | 309 * // returns {y: [{x: 1, y: 1}, {x: 3, y: 3}], z: [{x: 2, z: 2}]} |
| 293 * this.data_ = [{x: 1, y: 1}, {x: 2, z: 2}, {x: 3, y: 3}]; | 310 * this.data_ = [{x: 1, y: 1}, {x: 2, z: 2}, {x: 3, y: 3}]; |
| 294 * this.getDataBySeriesKey_(); | 311 * this.getDataBySeriesKey_(); |
| 295 * @return {Object} A map of series data by series key. | 312 * @return {Object} A map of series data by series key. |
| 296 */ | 313 */ |
| 297 getDataBySeriesKey_: function() { | 314 getDataBySeriesKey_: function() { |
| 298 var dataBySeriesKey = {}; | 315 var dataBySeriesKey = {}; |
| 299 this.seriesKeys_.forEach(function(seriesKey) { | 316 for (var [key, series] of this.seriesByKey_) { |
| 300 dataBySeriesKey[seriesKey] = []; | 317 dataBySeriesKey[key] = []; |
| 301 }); | 318 } |
| 302 | 319 |
| 303 this.data_.forEach(function(multiSeriesDatum, index) { | 320 this.data_.forEach(function(multiSeriesDatum, index) { |
| 304 var x = this.getXForDatum_(multiSeriesDatum, index); | 321 var x = this.getXForDatum_(multiSeriesDatum, index); |
| 305 | 322 |
| 306 d3.keys(multiSeriesDatum).forEach(function(seriesKey) { | 323 d3.keys(multiSeriesDatum).forEach(function(seriesKey) { |
| 307 // Skip 'x' - it's not a series | 324 // Skip 'x' - it's not a series |
| 308 if (seriesKey === 'x') | 325 if (seriesKey === 'x') |
| 309 return; | 326 return; |
| 310 | 327 |
| 311 if (multiSeriesDatum[seriesKey] === undefined) | 328 if (multiSeriesDatum[seriesKey] === undefined) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 this.dispatchEvent(dataEvent); | 392 this.dispatchEvent(dataEvent); |
| 376 this.classList.remove('updating-brushing-state'); | 393 this.classList.remove('updating-brushing-state'); |
| 377 } | 394 } |
| 378 }; | 395 }; |
| 379 | 396 |
| 380 return { | 397 return { |
| 381 ChartBase2D: ChartBase2D | 398 ChartBase2D: ChartBase2D |
| 382 }; | 399 }; |
| 383 }); | 400 }); |
| 384 </script> | 401 </script> |
| OLD | NEW |