1 /**
  2  * Constructs a new bar mark with default properties. Bars are not typically
  3  * constructed directly, but by adding to a panel or an existing mark via
  4  * {@link pv.Mark#add}.
  5  *
  6  * @class Represents a bar: an axis-aligned rectangle that can be stroked and
  7  * filled. Bars are used for many chart types, including bar charts, histograms
  8  * and Gantt charts. Bars can also be used as decorations, for example to draw a
  9  * frame border around a panel; in fact, a panel is a special type (a subclass)
 10  * of bar.
 11  *
 12  * <p>Bars can be positioned in several ways. Most commonly, one of the four
 13  * corners is fixed using two margins, and then the width and height properties
 14  * determine the extent of the bar relative to this fixed location. For example,
 15  * using the bottom and left properties fixes the bottom-left corner; the width
 16  * then extends to the right, while the height extends to the top. As an
 17  * alternative to the four corners, a bar can be positioned exclusively using
 18  * margins; this is convenient as an inset from the containing panel, for
 19  * example. See {@link pv.Mark} for details on the prioritization of redundant
 20  * positioning properties.
 21  *
 22  * <p>See also the <a href="../../api/Bar.html">Bar guide</a>.
 23  *
 24  * @extends pv.Mark
 25  */
 26 pv.Bar = function() {
 27   pv.Mark.call(this);
 28 };
 29 
 30 pv.Bar.prototype = pv.extend(pv.Mark)
 31     .property("width")
 32     .property("height")
 33     .property("lineWidth")
 34     .property("strokeStyle")
 35     .property("fillStyle");
 36 
 37 pv.Bar.prototype.type = "bar";
 38 
 39 /**
 40  * The width of the bar, in pixels. If the left position is specified, the bar
 41  * extends rightward from the left edge; if the right position is specified, the
 42  * bar extends leftward from the right edge.
 43  *
 44  * @type number
 45  * @name pv.Bar.prototype.width
 46  */
 47 
 48 /**
 49  * The height of the bar, in pixels. If the bottom position is specified, the
 50  * bar extends upward from the bottom edge; if the top position is specified,
 51  * the bar extends downward from the top edge.
 52  *
 53  * @type number
 54  * @name pv.Bar.prototype.height
 55  */
 56 
 57 /**
 58  * The width of stroked lines, in pixels; used in conjunction with
 59  * <tt>strokeStyle</tt> to stroke the bar's border.
 60  *
 61  * @type number
 62  * @name pv.Bar.prototype.lineWidth
 63  */
 64 
 65 /**
 66  * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to
 67  * stroke the bar's border. The default value of this property is null, meaning
 68  * bars are not stroked by default.
 69  *
 70  * @type string
 71  * @name pv.Bar.prototype.strokeStyle
 72  * @see pv.color
 73  */
 74 
 75 /**
 76  * The bar fill style; if non-null, the interior of the bar is filled with the
 77  * specified color. The default value of this property is a categorical color.
 78  *
 79  * @type string
 80  * @name pv.Bar.prototype.fillStyle
 81  * @see pv.color
 82  */
 83 
 84 /**
 85  * Default properties for bars. By default, there is no stroke and the fill
 86  * style is a categorical color.
 87  *
 88  * @type pv.Bar
 89  */
 90 pv.Bar.prototype.defaults = new pv.Bar()
 91     .extend(pv.Mark.prototype.defaults)
 92     .lineWidth(1.5)
 93     .fillStyle(defaultFillStyle);
 94 
 95 /**
 96  * Constructs a new bar anchor with default properties. Bars support five
 97  * different anchors:<ul>
 98  *
 99  * <li>top
100  * <li>left
101  * <li>center
102  * <li>bottom
103  * <li>right
104  *
105  * </ul>In addition to positioning properties (left, right, top bottom), the
106  * anchors support text rendering properties (text-align, text-baseline). Text
107  * is rendered to appear inside the bar.
108  *
109  * <p>To facilitate stacking of bars, the anchors are defined in terms of their
110  * opposite edge. For example, the top anchor defines the bottom property, such
111  * that the bar grows upwards; the bottom anchor instead defines the top
112  * property, such that the bar grows downwards. Of course, in general it is more
113  * robust to use panels and the cousin accessor to define stacked bars; see
114  * {@link pv.Mark#scene} for an example.
115  *
116  * <p>Bar anchors also "smartly" specify position properties based on whether
117  * the derived mark type supports the width and height properties. If the
118  * derived mark type does not support these properties (e.g., dots), the
119  * position will be centered on the corresponding edge. Otherwise (e.g., bars),
120  * the position will be in the opposite side.
121  *
122  * @param {string} name the anchor name; either a string or a property function.
123  * @returns {pv.Anchor}
124  */
125 pv.Bar.prototype.anchor = function(name) {
126   var bar = this;
127   return pv.Mark.prototype.anchor.call(this, name)
128     .left(function() {
129         switch (this.name()) {
130           case "bottom":
131           case "top":
132           case "center": return bar.left() + (this.properties.width ? 0 : (bar.width() / 2));
133           case "right": return bar.left() + bar.width();
134         }
135         return null;
136       })
137     .right(function() {
138         switch (this.name()) {
139           case "bottom":
140           case "top":
141           case "center": return bar.right() + (this.properties.width ? 0 : (bar.width() / 2));
142           case "left": return bar.right() + bar.width();
143         }
144         return null;
145       })
146     .top(function() {
147         switch (this.name()) {
148           case "left":
149           case "right":
150           case "center": return bar.top() + (this.properties.height ? 0 : (bar.height() / 2));
151           case "bottom": return bar.top() + bar.height();
152         }
153         return null;
154       })
155     .bottom(function() {
156         switch (this.name()) {
157           case "left":
158           case "right":
159           case "center": return bar.bottom() + (this.properties.height ? 0 : (bar.height() / 2));
160           case "top": return bar.bottom() + bar.height();
161         }
162         return null;
163       })
164     .textAlign(function() {
165         switch (this.name()) {
166           case "bottom":
167           case "top":
168           case "center": return "center";
169           case "right": return "right";
170         }
171         return "left";
172       })
173     .textBaseline(function() {
174         switch (this.name()) {
175           case "right":
176           case "left":
177           case "center": return "middle";
178           case "top": return "top";
179         }
180         return "bottom";
181       });
182 };
183