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/base/d3.html"> | 10 <link rel="import" href="/tracing/ui/base/d3.html"> |
10 <link rel="import" href="/tracing/ui/base/ui.html"> | 11 <link rel="import" href="/tracing/ui/base/ui.html"> |
11 | 12 |
| 13 <dom-module id="tr-ui-b-chart-legend-key"> |
| 14 <template> |
| 15 <style> |
| 16 #checkbox { |
| 17 margin: 0; |
| 18 visibility: hidden; |
| 19 vertical-align: text-top; |
| 20 } |
| 21 #label, #link { |
| 22 white-space: nowrap; |
| 23 text-overflow: ellipsis; |
| 24 overflow: hidden; |
| 25 display: inline-block; |
| 26 } |
| 27 </style> |
| 28 |
| 29 <input type=checkbox id="checkbox" checked> |
| 30 <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link> |
| 31 <label id="label"></label> |
| 32 </template> |
| 33 </dom-module> |
| 34 <script> |
| 35 'use strict'; |
| 36 Polymer({ |
| 37 is: 'tr-ui-b-chart-legend-key', |
| 38 |
| 39 ready: function() { |
| 40 this.$.checkbox.addEventListener( |
| 41 'change', this.onCheckboxChange_.bind(this)); |
| 42 }, |
| 43 |
| 44 /** |
| 45 * Dispatch an event when the checkbox is toggled. |
| 46 * The checkbox is visible when optional is set to true. |
| 47 */ |
| 48 onCheckboxChange_: function() { |
| 49 tr.b.dispatchSimpleEvent(this, tr.ui.b.DataSeriesEnableChangeEventType, |
| 50 true, false, |
| 51 {key: Polymer.dom(this).textContent, enabled: this.enabled}); |
| 52 }, |
| 53 |
| 54 set textContent(t) { |
| 55 Polymer.dom(this.$.label).textContent = t; |
| 56 Polymer.dom(this.$.link).textContent = t; |
| 57 this.updateContents_(); |
| 58 }, |
| 59 |
| 60 set width(w) { |
| 61 w -= 20; // reserve 20px for the checkbox |
| 62 this.$.link.style.width = w + 'px'; |
| 63 this.$.label.style.width = w + 'px'; |
| 64 }, |
| 65 |
| 66 get textContent() { |
| 67 return Polymer.dom(this.$.label).textContent; |
| 68 }, |
| 69 |
| 70 /** |
| 71 * When a legend-key is "optional", then its checkbox is visible to allow |
| 72 * the user to enable/disable the data series for the key. |
| 73 * See ChartBase.customizeOptionalSeries(). |
| 74 * |
| 75 * @param {boolean} optional |
| 76 */ |
| 77 set optional(optional) { |
| 78 this.$.checkbox.style.visibility = optional ? 'visible' : 'hidden'; |
| 79 }, |
| 80 |
| 81 get optional() { |
| 82 return this.$.checkbox.style.visibility === 'visible'; |
| 83 }, |
| 84 |
| 85 set enabled(enabled) { |
| 86 this.$.checkbox.checked = enabled ? 'checked' : ''; |
| 87 }, |
| 88 |
| 89 get enabled() { |
| 90 return this.$.checkbox.checked; |
| 91 }, |
| 92 |
| 93 set color(c) { |
| 94 this.$.label.style.color = c; |
| 95 this.$.link.color = c; |
| 96 }, |
| 97 |
| 98 /** |
| 99 * When target is defined, label is hidden and link is shown. |
| 100 * When the link is clicked, then a RequestSelectionChangeEvent is |
| 101 * dispatched containing the target. |
| 102 * When target is undefined, label is shown and link is hidden, so that the |
| 103 * link is not clickable. |
| 104 * See ChartBase.customizeLegendTargets(). |
| 105 */ |
| 106 set target(target) { |
| 107 this.$.link.setSelectionAndContent( |
| 108 target, Polymer.dom(this.$.label).textContent); |
| 109 this.updateContents_(); |
| 110 }, |
| 111 |
| 112 get target() { |
| 113 return this.$.link.selection; |
| 114 }, |
| 115 |
| 116 updateContents_: function() { |
| 117 this.$.link.style.display = this.target ? '' : 'none'; |
| 118 this.$.label.style.display = this.target ? 'none' : ''; |
| 119 this.$.label.htmlFor = this.optional ? 'checkbox' : ''; |
| 120 } |
| 121 }); |
| 122 </script> |
| 123 |
12 <style> | 124 <style> |
13 * /deep/ .chart-base #title { | 125 * /deep/ .chart-base #title { |
14 font-size: 16pt; | 126 font-size: 16pt; |
15 } | 127 } |
16 | 128 |
17 * /deep/ .chart-base { | 129 * /deep/ .chart-base { |
18 font-size: 12pt; | |
19 -webkit-user-select: none; | 130 -webkit-user-select: none; |
20 cursor: default; | 131 cursor: default; |
21 } | 132 } |
22 | 133 |
23 * /deep/ .chart-base .axis path, | 134 * /deep/ .chart-base .axis path, |
24 * /deep/ .chart-base .axis line { | 135 * /deep/ .chart-base .axis line { |
25 fill: none; | 136 fill: none; |
26 shape-rendering: crispEdges; | 137 shape-rendering: crispEdges; |
27 stroke: #000; | 138 stroke: #000; |
28 } | 139 } |
| 140 |
| 141 * /deep/ .chart-base .legend body { |
| 142 margin: 0; |
| 143 } |
29 </style> | 144 </style> |
30 | 145 |
31 <template id="chart-base-template"> | 146 <template id="chart-base-template"> |
32 <svg> <!-- svg tag is dropped by ChartBase.decorate. --> | 147 <svg> <!-- svg tag is dropped by ChartBase.decorate. --> |
33 <g xmlns="http://www.w3.org/2000/svg" id="chart-area"> | 148 <g xmlns="http://www.w3.org/2000/svg" id="chart-area"> |
34 <g class="x axis"></g> | 149 <g class="x axis"></g> |
35 <g class="y axis"></g> | 150 <g class="y axis"></g> |
36 <text id="title"></text> | 151 <text id="title"></text> |
37 </g> | 152 </g> |
38 </svg> | 153 </svg> |
39 </template> | 154 </template> |
40 | 155 |
41 <script> | 156 <script> |
42 'use strict'; | 157 'use strict'; |
43 | 158 |
44 tr.exportTo('tr.ui.b', function() { | 159 tr.exportTo('tr.ui.b', function() { |
| 160 var DataSeriesEnableChangeEventType = 'data-series-enabled-change'; |
| 161 |
45 var THIS_DOC = document.currentScript.ownerDocument; | 162 var THIS_DOC = document.currentScript.ownerDocument; |
46 | 163 |
47 var svgNS = 'http://www.w3.org/2000/svg'; | 164 var svgNS = 'http://www.w3.org/2000/svg'; |
48 var ColorScheme = tr.b.ColorScheme; | 165 var ColorScheme = tr.b.ColorScheme; |
49 | 166 |
50 function getColorOfKey(key, selected) { | 167 function getColorOfKey(key, selected) { |
51 var id = ColorScheme.getColorIdForGeneralPurposeString(key); | 168 var id = ColorScheme.getColorIdForGeneralPurposeString(key); |
52 if (selected) | 169 if (selected) |
53 id += ColorScheme.properties.brightenedOffsets[0]; | 170 id += ColorScheme.properties.brightenedOffsets[0]; |
54 return ColorScheme.colorsAsStrings[id]; | 171 return ColorScheme.colorsAsStrings[id]; |
55 } | 172 } |
56 | 173 |
| 174 function DataSeries(key) { |
| 175 this.key_ = key; |
| 176 this.target_ = undefined; |
| 177 this.optional_ = false; |
| 178 this.enabled_ = true; |
| 179 } |
| 180 |
| 181 DataSeries.prototype = { |
| 182 get key() { |
| 183 return this.key_; |
| 184 }, |
| 185 |
| 186 get optional() { |
| 187 return this.optional_; |
| 188 }, |
| 189 |
| 190 set optional(optional) { |
| 191 this.optional_ = optional; |
| 192 }, |
| 193 |
| 194 get enabled() { |
| 195 return this.enabled_; |
| 196 }, |
| 197 |
| 198 set enabled(enabled) { |
| 199 // If the caller is disabling a data series, but it wasn't optional, then |
| 200 // force it to be optional. |
| 201 if (!this.optional && !enabled) |
| 202 this.optional = true; |
| 203 this.enabled_ = enabled; |
| 204 }, |
| 205 |
| 206 get target() { |
| 207 return this.target_; |
| 208 }, |
| 209 |
| 210 set target(t) { |
| 211 this.target_ = t; |
| 212 } |
| 213 }; |
| 214 |
57 /** | 215 /** |
58 * A virtual base class for basic charts that provides X and Y axes, if | 216 * A virtual base class for basic charts that provides X and Y axes, if |
59 * needed, a title, and legend. | 217 * needed, a title, and legend. |
60 * | 218 * |
61 * @constructor | 219 * @constructor |
62 */ | 220 */ |
63 var ChartBase = tr.ui.b.define('svg', undefined, svgNS); | 221 var ChartBase = tr.ui.b.define('svg', undefined, svgNS); |
64 | 222 |
65 ChartBase.prototype = { | 223 ChartBase.prototype = { |
66 __proto__: HTMLDivElement.prototype, | 224 __proto__: HTMLUnknownElement.prototype, |
| 225 |
| 226 getDataSeries: function(key) { |
| 227 if (!this.seriesByKey_.has(key)) |
| 228 this.seriesByKey_.set(key, new DataSeries(key)); |
| 229 return this.seriesByKey_.get(key); |
| 230 }, |
67 | 231 |
68 decorate: function() { | 232 decorate: function() { |
69 Polymer.dom(this).classList.add('chart-base'); | 233 Polymer.dom(this).classList.add('chart-base'); |
70 this.chartTitle_ = undefined; | 234 this.chartTitle_ = undefined; |
71 this.seriesKeys_ = undefined; | 235 this.seriesByKey_ = new Map(); |
72 this.width_ = 400; | 236 this.width_ = 400; |
73 this.height_ = 300; | 237 this.height_ = 300; |
| 238 this.margin = {top: 20, right: 72, bottom: 30, left: 50}; |
| 239 this.hideLegend_ = false; |
74 | 240 |
75 // This should use tr.ui.b.instantiateTemplate. However, creating | 241 // This should use tr.ui.b.instantiateTemplate. However, creating |
76 // svg-namespaced elements inside a template isn't possible. Thus, this | 242 // svg-namespaced elements inside a template isn't possible. Thus, this |
77 // hack. | 243 // hack. |
78 var template = Polymer.dom(THIS_DOC) | 244 var template = |
79 .querySelector('#chart-base-template'); | 245 Polymer.dom(THIS_DOC).querySelector('#chart-base-template'); |
80 var svgEl = Polymer.dom(template.content).querySelector('svg'); | 246 var svgEl = Polymer.dom(template.content).querySelector('svg'); |
81 for (var i = 0; i < svgEl.children.length; i++) | 247 for (var i = 0; i < Polymer.dom(svgEl).children.length; i++) |
82 Polymer.dom(this).appendChild(svgEl.children[i].cloneNode(true)); | 248 Polymer.dom(this).appendChild( |
| 249 Polymer.dom(svgEl.children[i]).cloneNode(true)); |
83 | 250 |
84 // svg likes to take over width & height properties for some reason. This | 251 // svg likes to take over width & height properties for some reason. This |
85 // works around it. | 252 // works around it. |
86 Object.defineProperty( | 253 Object.defineProperty( |
87 this, 'width', { | 254 this, 'width', { |
88 get: function() { | 255 get: function() { |
89 return this.width_; | 256 return this.width_; |
90 }, | 257 }, |
91 set: function(width) { | 258 set: function(width) { |
92 this.width_ = width; | 259 this.width_ = width; |
93 this.updateContents_(); | 260 this.updateContents_(); |
94 } | 261 } |
95 }); | 262 }); |
96 Object.defineProperty( | 263 Object.defineProperty( |
97 this, 'height', { | 264 this, 'height', { |
98 get: function() { | 265 get: function() { |
99 return this.height_; | 266 return this.height_; |
100 }, | 267 }, |
101 set: function(height) { | 268 set: function(height) { |
102 this.height_ = height; | 269 this.height_ = height; |
103 this.updateContents_(); | 270 this.updateContents_(); |
104 } | 271 } |
105 }); | 272 }); |
| 273 this.addEventListener(DataSeriesEnableChangeEventType, |
| 274 this.onDataSeriesEnableChange_.bind(this)); |
| 275 }, |
| 276 |
| 277 get hideLegend() { |
| 278 return this.hideLegend_; |
| 279 }, |
| 280 |
| 281 set hideLegend(h) { |
| 282 this.hideLegend_ = h; |
| 283 this.updateContents_(); |
| 284 }, |
| 285 |
| 286 isSeriesEnabled: function(key) { |
| 287 return this.getDataSeries(key).enabled; |
| 288 }, |
| 289 |
| 290 onDataSeriesEnableChange_: function(event) { |
| 291 this.getDataSeries(event.key).enabled = event.enabled; |
| 292 this.updateContents_(); |
106 }, | 293 }, |
107 | 294 |
108 get chartTitle() { | 295 get chartTitle() { |
109 return this.chartTitle_; | 296 return this.chartTitle_; |
110 }, | 297 }, |
111 | 298 |
112 set chartTitle(chartTitle) { | 299 set chartTitle(chartTitle) { |
| 300 if (chartTitle && !this.chartTitle_) |
| 301 this.margin.top += this.titleMarginPx; |
| 302 else if (this.chartTitle_ && !chartTitle) |
| 303 this.margin.top -= this.titleMarginPx; |
| 304 |
113 this.chartTitle_ = chartTitle; | 305 this.chartTitle_ = chartTitle; |
114 this.updateContents_(); | 306 this.updateContents_(); |
115 }, | 307 }, |
116 | 308 |
| 309 get titleMarginPx() { |
| 310 return 20; |
| 311 }, |
| 312 |
117 get chartAreaElement() { | 313 get chartAreaElement() { |
118 return Polymer.dom(this).querySelector('#chart-area'); | 314 return Polymer.dom(this).querySelector('#chart-area'); |
119 }, | 315 }, |
120 | 316 |
121 setSize: function(size) { | 317 setSize: function(size) { |
122 this.width_ = size.width; | 318 this.width_ = size.width; |
123 this.height_ = size.height; | 319 this.height_ = size.height; |
124 this.updateContents_(); | 320 this.updateContents_(); |
125 }, | 321 }, |
126 | 322 |
127 getMargin_: function() { | |
128 var margin = {top: 20, right: 20, bottom: 30, left: 50}; | |
129 if (this.chartTitle_) | |
130 margin.top += 20; | |
131 return margin; | |
132 }, | |
133 | |
134 get margin() { | |
135 return this.getMargin_(); | |
136 }, | |
137 | |
138 get chartAreaSize() { | 323 get chartAreaSize() { |
139 var margin = this.margin; | |
140 return { | 324 return { |
141 width: this.width_ - margin.left - margin.right, | 325 width: this.width_ - this.margin.left - this.margin.right, |
142 height: this.height_ - margin.top - margin.bottom | 326 height: this.height_ - this.margin.top - this.margin.bottom |
143 }; | 327 }; |
144 }, | 328 }, |
145 | 329 |
146 getLegendKeys_: function() { | 330 /** |
147 throw new Error('Not implemented'); | 331 * Legend keys can be clickable links instead of plain text. |
| 332 * When a legend key link is clicked, a RequestSelectionChangeEvent is |
| 333 * dispatched containing arbitrary data. ChartBase calls that arbitrary data |
| 334 * the "target" of the legend key link. |
| 335 * In order to turn the legend key for the 'foo' data series into a |
| 336 * clickable link, call customizeLegendTargets({foo: target}). When the user |
| 337 * clicks on the legend key link for 'foo', then a |
| 338 * RequestSelectionChangeEvent will be dispatched, and its |selection| field |
| 339 * will be the |target| value for the 'foo' key in |delta|. |
| 340 * |
| 341 * @param {!Object} delta |
| 342 */ |
| 343 customizeLegendTargets: function(delta) { |
| 344 tr.b.iterItems(delta, function(key, value) { |
| 345 this.getDataSeries(key).target = value; |
| 346 }, this); |
| 347 }, |
| 348 |
| 349 /** |
| 350 * Optional data series can be enabled and disabled using checkboxes. |
| 351 * In order to allow the user to enable/disabled the 'foo' data series, |
| 352 * call customizeOptionalSeries({foo: true}). This will show a checkbox |
| 353 * next to the 'foo' legend key. When the user toggles the checkbox, then a |
| 354 * DataSeriesEnableChangeEvent will be dispatched with its |key| = 'foo'. |
| 355 * ChartBase listens for that event and updates |isSeriesEnabled('foo')| to |
| 356 * reflect the state of that checkbox, and calls updateContents_(). |
| 357 * Subclasses are responsible for implementing updateContents_() in order to |
| 358 * hiding disabled data series -- see BarChart. |
| 359 * |
| 360 * @param {!Object} delta |
| 361 */ |
| 362 customizeOptionalSeries: function(delta) { |
| 363 tr.b.iterItems(delta, function(key, value) { |
| 364 this.getDataSeries(key).optional = value; |
| 365 }, this); |
| 366 }, |
| 367 |
| 368 /** |
| 369 * Data series can be enabled and disabled. |
| 370 * See customizeOptionalSeries() in order to allow the user to |
| 371 * enable/disable data series manually. Callers may call |
| 372 * customizeEnabledSeries({foo: false}) in order to automatically |
| 373 * disable the 'foo' data series, for example. |
| 374 * |
| 375 * @param {!Object} delta |
| 376 */ |
| 377 customizeEnabledSeries: function(delta) { |
| 378 tr.b.iterItems(delta, function(key, value) { |
| 379 this.getDataSeries(key).enabled = value; |
| 380 }, this); |
148 }, | 381 }, |
149 | 382 |
150 updateScales_: function() { | 383 updateScales_: function() { |
151 throw new Error('Not implemented'); | 384 throw new Error('Not implemented'); |
152 }, | 385 }, |
153 | 386 |
154 updateContents_: function() { | 387 updateContents_: function() { |
155 var margin = this.margin; | |
156 | |
157 var thisSel = d3.select(this); | 388 var thisSel = d3.select(this); |
158 thisSel.attr('width', this.width_); | 389 thisSel.attr('width', this.width_); |
159 thisSel.attr('height', this.height_); | 390 thisSel.attr('height', this.height_); |
160 | 391 |
161 var chartAreaSel = d3.select(this.chartAreaElement); | 392 var chartAreaSel = d3.select(this.chartAreaElement); |
162 chartAreaSel.attr('transform', | 393 chartAreaSel.attr('transform', |
163 'translate(' + margin.left + ',' + margin.top + ')'); | 394 'translate(' + this.margin.left + ',' + this.margin.top + ')'); |
164 | 395 |
165 this.updateScales_(); | 396 this.updateScales_(); |
166 this.updateTitle_(chartAreaSel); | 397 this.updateTitle_(chartAreaSel); |
167 this.updateLegend_(); | 398 this.updateLegend_(); |
168 }, | 399 }, |
169 | 400 |
170 updateTitle_: function(chartAreaSel) { | 401 updateTitle_: function(chartAreaSel) { |
171 var titleSel = chartAreaSel.select('#title'); | 402 var titleSel = chartAreaSel.select('#title'); |
172 if (!this.chartTitle_) { | 403 if (!this.chartTitle_) { |
173 titleSel.style('display', 'none'); | 404 titleSel.style('display', 'none'); |
174 return; | 405 return; |
175 } | 406 } |
176 var width = this.chartAreaSize.width; | 407 var width = this.chartAreaSize.width; |
177 titleSel.attr('transform', 'translate(' + width * 0.5 + ',-5)') | 408 titleSel.attr('transform', 'translate(' + width * 0.5 + ',-5)') |
178 .style('display', undefined) | 409 .style('display', undefined) |
179 .style('text-anchor', 'middle') | 410 .style('text-anchor', 'middle') |
180 .attr('class', 'title') | 411 .attr('class', 'title') |
181 .attr('width', width) | 412 .attr('width', width) |
182 .text(this.chartTitle_); | 413 .text(this.chartTitle_); |
183 }, | 414 }, |
184 | 415 |
185 // TODO(charliea): We should change updateLegend_ so that it ellipsizes the | |
186 // series names after a certain point. Otherwise, the series names start | |
187 // dipping below the x-axis and continue on outside of the viewport. | |
188 updateLegend_: function() { | 416 updateLegend_: function() { |
189 var keys = this.getLegendKeys_(); | 417 var chartAreaSel = d3.select(this.chartAreaElement); |
190 if (keys === undefined) | 418 chartAreaSel.selectAll('.legend').remove(); |
| 419 if (this.hideLegend) |
191 return; | 420 return; |
192 | 421 |
193 var chartAreaSel = d3.select(this.chartAreaElement); | 422 var series = [...this.seriesByKey_.values()].reverse(); |
194 var chartAreaSize = this.chartAreaSize; | 423 var legendEntriesSel = chartAreaSel.selectAll('.legend').data(series); |
195 | 424 |
196 var legendEntriesSel = chartAreaSel.selectAll('.legend') | 425 var width = this.margin.right - 2; |
197 .data(keys.slice().reverse()); | |
198 | |
199 legendEntriesSel.enter() | 426 legendEntriesSel.enter() |
200 .append('g') | 427 .append('foreignObject') |
201 .attr('class', 'legend') | 428 .attr('class', 'legend') |
202 .attr('transform', function(d, i) { | 429 .attr('x', this.chartAreaSize.width + 2) |
203 return 'translate(0,' + i * 20 + ')'; | 430 .attr('width', width) |
| 431 .attr('height', 18) |
| 432 .attr('transform', function(series, i) { |
| 433 return 'translate(0,' + i * 18 + ')'; |
204 }) | 434 }) |
205 .append('text').text(function(key) { | 435 .append('xhtml:body') |
206 return key; | 436 .append('tr-ui-b-chart-legend-key') |
207 }); | 437 .property('color', function(series) { |
| 438 var selected = this.currentHighlightedLegendKey === series.key; |
| 439 return getColorOfKey(series.key, selected); |
| 440 }.bind(this)) |
| 441 .property('width', width) |
| 442 .property('target', function(series) { return series.target; }) |
| 443 .property('optional', function(series) { return series.optional; }) |
| 444 .property('enabled', function(series) { return series.enabled; }) |
| 445 .text(function(series) { return series.key; }); |
208 legendEntriesSel.exit().remove(); | 446 legendEntriesSel.exit().remove(); |
209 | |
210 legendEntriesSel.attr('x', chartAreaSize.width - 18) | |
211 .attr('width', 18) | |
212 .attr('height', 18) | |
213 .style('fill', function(key) { | |
214 var selected = this.currentHighlightedLegendKey === key; | |
215 return getColorOfKey(key, selected); | |
216 }.bind(this)); | |
217 | |
218 legendEntriesSel.selectAll('text') | |
219 .attr('x', chartAreaSize.width - 24) | |
220 .attr('y', 9) | |
221 .attr('dy', '.35em') | |
222 .style('text-anchor', 'end') | |
223 .text(function(d) { return d; }); | |
224 }, | 447 }, |
225 | 448 |
226 get highlightedLegendKey() { | 449 get highlightedLegendKey() { |
227 return this.highlightedLegendKey_; | 450 return this.highlightedLegendKey_; |
228 }, | 451 }, |
229 | 452 |
230 set highlightedLegendKey(highlightedLegendKey) { | 453 set highlightedLegendKey(highlightedLegendKey) { |
231 this.highlightedLegendKey_ = highlightedLegendKey; | 454 this.highlightedLegendKey_ = highlightedLegendKey; |
232 this.updateHighlight_(); | 455 this.updateHighlight_(); |
233 }, | 456 }, |
(...skipping 30 matching lines...) Expand all Loading... |
264 this.style.fill = color; | 487 this.style.fill = color; |
265 if (highlighted) | 488 if (highlighted) |
266 this.style.fontWeight = 'bold'; | 489 this.style.fontWeight = 'bold'; |
267 else | 490 else |
268 this.style.fontWeight = ''; | 491 this.style.fontWeight = ''; |
269 }); | 492 }); |
270 } | 493 } |
271 }; | 494 }; |
272 | 495 |
273 return { | 496 return { |
| 497 DataSeriesEnableChangeEventType: DataSeriesEnableChangeEventType, |
274 getColorOfKey: getColorOfKey, | 498 getColorOfKey: getColorOfKey, |
275 ChartBase: ChartBase | 499 ChartBase: ChartBase |
276 }; | 500 }; |
277 }); | 501 }); |
278 </script> | 502 </script> |
OLD | NEW |