1 /** 2 * Constructs a new dot mark with default properties. Dots 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 dot; a dot is simply a sized glyph centered at a given 7 * point that can also be stroked and filled. The <tt>size</tt> property is 8 * proportional to the area of the rendered glyph to encourage meaningful visual 9 * encodings. Dots can visually encode up to eight dimensions of data, though 10 * this may be unwise due to integrality. See {@link pv.Mark} for details on the 11 * prioritization of redundant positioning properties. 12 * 13 * <p>See also the <a href="../../api/Dot.html">Dot guide</a>. 14 * 15 * @extends pv.Mark 16 */ 17 pv.Dot = function() { 18 pv.Mark.call(this); 19 }; 20 21 pv.Dot.prototype = pv.extend(pv.Mark) 22 .property("size", Number) 23 .property("radius", Number) 24 .property("shape", String) 25 .property("angle", Number) 26 .property("lineWidth", Number) 27 .property("strokeStyle", pv.color) 28 .property("fillStyle", pv.color); 29 30 pv.Dot.prototype.type = "dot"; 31 32 /** 33 * The size of the dot, in square pixels. Square pixels are used such that the 34 * area of the dot is linearly proportional to the value of the size property, 35 * facilitating representative encodings. 36 * 37 * @see #radius 38 * @type number 39 * @name pv.Dot.prototype.size 40 */ 41 42 /** 43 * The radius of the dot, in pixels. This is an alternative to using 44 * {@link #size}. 45 * 46 * @see #size 47 * @type number 48 * @name pv.Dot.prototype.radius 49 */ 50 51 /** 52 * The shape name. Several shapes are supported:<ul> 53 * 54 * <li>cross 55 * <li>triangle 56 * <li>diamond 57 * <li>square 58 * <li>circle 59 * <li>tick 60 * <li>bar 61 * 62 * </ul>These shapes can be further changed using the {@link #angle} property; 63 * for instance, a cross can be turned into a plus by rotating. Similarly, the 64 * tick, which is vertical by default, can be rotated horizontally. Note that 65 * some shapes (cross and tick) do not have interior areas, and thus do not 66 * support fill style meaningfully. 67 * 68 * <p>Note: it may be more natural to use the {@link pv.Rule} mark for 69 * horizontal and vertical ticks. The tick shape is only necessary if angled 70 * ticks are needed. 71 * 72 * @type string 73 * @name pv.Dot.prototype.shape 74 */ 75 76 /** 77 * The rotation angle, in radians. Used to rotate shapes, such as to turn a 78 * cross into a plus. 79 * 80 * @type number 81 * @name pv.Dot.prototype.angle 82 */ 83 84 /** 85 * The width of stroked lines, in pixels; used in conjunction with 86 * <tt>strokeStyle</tt> to stroke the dot's shape. 87 * 88 * @type number 89 * @name pv.Dot.prototype.lineWidth 90 */ 91 92 /** 93 * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to 94 * stroke the dot's shape. The default value of this property is a categorical 95 * color. 96 * 97 * @type string 98 * @name pv.Dot.prototype.strokeStyle 99 * @see pv.color 100 */ 101 102 /** 103 * The fill style; if non-null, the interior of the dot is filled with the 104 * specified color. The default value of this property is null, meaning dots are 105 * not filled by default. 106 * 107 * @type string 108 * @name pv.Dot.prototype.fillStyle 109 * @see pv.color 110 */ 111 112 /** 113 * Default properties for dots. By default, there is no fill and the stroke 114 * style is a categorical color. The default shape is "circle" with size 20. 115 * 116 * @type pv.Dot 117 */ 118 pv.Dot.prototype.defaults = new pv.Dot() 119 .extend(pv.Mark.prototype.defaults) 120 .size(20) 121 .shape("circle") 122 .lineWidth(1.5) 123 .strokeStyle(pv.Colors.category10().by(pv.parent)); 124 125 /** 126 * Constructs a new dot anchor with default properties. Dots support five 127 * different anchors:<ul> 128 * 129 * <li>top 130 * <li>left 131 * <li>center 132 * <li>bottom 133 * <li>right 134 * 135 * </ul>In addition to positioning properties (left, right, top bottom), the 136 * anchors support text rendering properties (text-align, text-baseline). Text is 137 * rendered to appear outside the dot. Note that this behavior is different from 138 * other mark anchors, which default to rendering text <i>inside</i> the mark. 139 * 140 * <p>For consistency with the other mark types, the anchor positions are 141 * defined in terms of their opposite edge. For example, the top anchor defines 142 * the bottom property, such that a bar added to the top anchor grows upward. 143 * 144 * @param {string} name the anchor name; either a string or a property function. 145 * @returns {pv.Anchor} 146 */ 147 pv.Dot.prototype.anchor = function(name) { 148 var scene; 149 return pv.Mark.prototype.anchor.call(this, name) 150 .def("$wedge.anchor", function() { 151 scene = this.scene.target; 152 }) 153 .left(function() { 154 var s = scene[this.index]; 155 switch (this.name()) { 156 case "bottom": 157 case "top": 158 case "center": return s.left; 159 case "left": return null; 160 } 161 return s.left + s.radius; 162 }) 163 .right(function() { 164 var s = scene[this.index]; 165 return this.name() == "left" ? s.right + s.radius : null; 166 }) 167 .top(function() { 168 var s = scene[this.index]; 169 switch (this.name()) { 170 case "left": 171 case "right": 172 case "center": return s.top; 173 case "top": return null; 174 } 175 return s.top + s.radius; 176 }) 177 .bottom(function() { 178 var s = scene[this.index]; 179 return this.name() == "top" ? s.bottom + s.radius : null; 180 }) 181 .textAlign(function() { 182 switch (this.name()) { 183 case "left": return "right"; 184 case "bottom": 185 case "top": 186 case "center": return "center"; 187 } 188 return "left"; 189 }) 190 .textBaseline(function() { 191 switch (this.name()) { 192 case "right": 193 case "left": 194 case "center": return "middle"; 195 case "bottom": return "top"; 196 } 197 return "bottom"; 198 }); 199 }; 200 201 /** @private Sets radius based on size or vice versa. */ 202 pv.Dot.prototype.buildImplied = function(s) { 203 if (s.radius == null) s.radius = Math.sqrt(s.size); 204 else if (s.size == null) s.size = s.radius * s.radius; 205 pv.Mark.prototype.buildImplied.call(this, s); 206 }; 207