1<!DOCTYPE html>
2<!--
3Copyright (c) 2015 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/base/range.html">
9
10<script>
11'use strict';
12
13tr.exportTo('tr.ui.tracks', function() {
14
15  /**
16   * A vertical axis for a (set of) chart series which maps an arbitrary range
17   * of values [min, max] to the unit range [0, 1].
18   *
19   * @constructor
20   */
21  function ChartAxis(opt_min, opt_max) {
22    this.guid_ = tr.b.GUID.allocate();
23    this.bounds = new tr.b.Range();
24    if (opt_min !== undefined)
25      this.bounds.addValue(opt_min);
26    if (opt_max !== undefined)
27      this.bounds.addValue(opt_max);
28  };
29
30  ChartAxis.prototype = {
31    get guid() {
32      return this.guid_;
33    },
34
35    valueToUnitRange: function(value) {
36      if (this.bounds.isEmpty)
37        throw new Error('Chart axis bounds are empty');
38      var bounds = this.bounds;
39      if (bounds.range === 0)
40        return 0;
41      return (value - bounds.min) / bounds.range;
42    },
43
44    /**
45     * Automatically set the axis bounds from the range of values of all series
46     * in a list.
47     *
48     * See the description of autoSetFromRange for the optional configuration
49     * argument flags.
50     */
51    autoSetFromSeries: function(series, opt_config) {
52      var range = new tr.b.Range();
53      series.forEach(function(s) {
54        range.addRange(s.range);
55      }, this);
56      this.autoSetFromRange(range, opt_config);
57    },
58
59    /**
60     * Automatically set the axis bound from a range of values.
61     *
62     * The following four flags, which affect the behavior of this method with
63     * respect to already defined bounds, can be present in the optional
64     * configuration (a flag is assumed to be false if it is not provided or if
65     * the configuration is not provided):
66     *
67     *   - expandMin: allow decreasing the min bound (if range.min < this.min)
68     *   - shrinkMin: allow increasing the min bound (if range.min > this.min)
69     *   - expandMax: allow increasing the max bound (if range.max > this.max)
70     *   - shrinkMax: allow decreasing the max bound (if range.max < this.max)
71     *
72     * This method will ensure that the resulting bounds are defined and valid
73     * (i.e. min <= max) provided that they were valid or empty before and the
74     * value range is non-empty and valid.
75     *
76     * Note that unless expanding/shrinking a bound is explicitly enabled in
77     * the configuration, non-empty bounds will not be changed under any
78     * circumstances.
79     *
80     * Observe that if no configuration is provided (or all flags are set to
81     * false), this method will only modify the axis bounds if they are empty.
82     */
83    autoSetFromRange: function(range, opt_config) {
84      if (range.isEmpty)
85        return;
86
87      var bounds = this.bounds;
88      if (bounds.isEmpty) {
89        bounds.addRange(range);
90        return;
91      }
92
93      if (!opt_config)
94        return;
95
96      var useRangeMin = (opt_config.expandMin && range.min < bounds.min ||
97                         opt_config.shrinkMin && range.min > bounds.min);
98      var useRangeMax = (opt_config.expandMax && range.max > bounds.max ||
99                         opt_config.shrinkMax && range.max < bounds.max);
100
101      // Neither bound is modified.
102      if (!useRangeMin && !useRangeMax)
103        return;
104
105      // Both bounds are modified. Assuming the range argument is a valid
106      // range, no extra checks are necessary.
107      if (useRangeMin && useRangeMax) {
108        bounds.min = range.min;
109        bounds.max = range.max;
110        return;
111      }
112
113      // Only one bound is modified. We must ensure that it doesn't go
114      // over/under the other (unmodified) bound.
115      if (useRangeMin) {
116        bounds.min = Math.min(range.min, bounds.max);
117      } else {
118        bounds.max = Math.max(range.max, bounds.min);
119      }
120    }
121  };
122
123  return {
124    ChartAxis: ChartAxis
125  };
126});
127</script>
128