rubyvis 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +13 -0
  4. data/Gemfile +8 -0
  5. data/Gemfile.lock +37 -0
  6. data/History.txt +6 -0
  7. data/LICENSE.txt +23 -0
  8. data/{README.txt → README.md} +15 -12
  9. data/Rakefile +4 -11
  10. data/lib/rubyvis.rb +1 -1
  11. data/lib/rubyvis/scale/quantitative.rb +14 -18
  12. data/lib/rubyvis/scene/svg_label.rb +1 -1
  13. data/rubyvis.gemspec +21 -0
  14. data/spec/anchor_spec.rb +2 -1
  15. data/spec/line_spec.rb +2 -2
  16. data/spec/scale_linear_datetime_spec.rb +23 -8
  17. data/spec/spec_helper.rb +2 -1
  18. metadata +31 -214
  19. data/.gemtest +0 -0
  20. data/vendor/protovis/protovis-r3.3.js +0 -287
  21. data/vendor/protovis/src/behavior/Behavior.js +0 -32
  22. data/vendor/protovis/src/behavior/Drag.js +0 -112
  23. data/vendor/protovis/src/behavior/Pan.js +0 -110
  24. data/vendor/protovis/src/behavior/Point.js +0 -157
  25. data/vendor/protovis/src/behavior/Resize.js +0 -104
  26. data/vendor/protovis/src/behavior/Select.js +0 -100
  27. data/vendor/protovis/src/behavior/Zoom.js +0 -85
  28. data/vendor/protovis/src/color/Color.js +0 -598
  29. data/vendor/protovis/src/color/Colors.js +0 -135
  30. data/vendor/protovis/src/color/Ramp.js +0 -17
  31. data/vendor/protovis/src/data/Arrays.js +0 -277
  32. data/vendor/protovis/src/data/Dom.js +0 -380
  33. data/vendor/protovis/src/data/Flatten.js +0 -146
  34. data/vendor/protovis/src/data/Histogram.js +0 -120
  35. data/vendor/protovis/src/data/LinearScale.js +0 -54
  36. data/vendor/protovis/src/data/LogScale.js +0 -142
  37. data/vendor/protovis/src/data/Nest.js +0 -257
  38. data/vendor/protovis/src/data/Numbers.js +0 -313
  39. data/vendor/protovis/src/data/Objects.js +0 -78
  40. data/vendor/protovis/src/data/OrdinalScale.js +0 -267
  41. data/vendor/protovis/src/data/QuantileScale.js +0 -180
  42. data/vendor/protovis/src/data/QuantitativeScale.js +0 -440
  43. data/vendor/protovis/src/data/RootScale.js +0 -55
  44. data/vendor/protovis/src/data/Scale.js +0 -86
  45. data/vendor/protovis/src/data/Transform.js +0 -109
  46. data/vendor/protovis/src/data/Tree.js +0 -124
  47. data/vendor/protovis/src/data/Vector.js +0 -118
  48. data/vendor/protovis/src/geo/Geo.js +0 -5
  49. data/vendor/protovis/src/geo/GeoScale.js +0 -307
  50. data/vendor/protovis/src/geo/LatLng.js +0 -23
  51. data/vendor/protovis/src/geo/Projection.js +0 -43
  52. data/vendor/protovis/src/geo/Projections.js +0 -117
  53. data/vendor/protovis/src/lang/Array.js +0 -112
  54. data/vendor/protovis/src/lang/init.js +0 -26
  55. data/vendor/protovis/src/layout/Arc.js +0 -178
  56. data/vendor/protovis/src/layout/Bullet.js +0 -164
  57. data/vendor/protovis/src/layout/Cluster.js +0 -205
  58. data/vendor/protovis/src/layout/Force.js +0 -309
  59. data/vendor/protovis/src/layout/Grid.js +0 -119
  60. data/vendor/protovis/src/layout/Hierarchy.js +0 -249
  61. data/vendor/protovis/src/layout/Horizon.js +0 -159
  62. data/vendor/protovis/src/layout/Indent.js +0 -83
  63. data/vendor/protovis/src/layout/Layout.js +0 -56
  64. data/vendor/protovis/src/layout/Matrix.js +0 -177
  65. data/vendor/protovis/src/layout/Network.js +0 -302
  66. data/vendor/protovis/src/layout/Pack.js +0 -323
  67. data/vendor/protovis/src/layout/Partition.js +0 -203
  68. data/vendor/protovis/src/layout/Rollup.js +0 -203
  69. data/vendor/protovis/src/layout/Stack.js +0 -391
  70. data/vendor/protovis/src/layout/Tree.js +0 -282
  71. data/vendor/protovis/src/layout/Treemap.js +0 -347
  72. data/vendor/protovis/src/mark/Anchor.js +0 -81
  73. data/vendor/protovis/src/mark/Area.js +0 -268
  74. data/vendor/protovis/src/mark/Bar.js +0 -93
  75. data/vendor/protovis/src/mark/Dot.js +0 -212
  76. data/vendor/protovis/src/mark/Ease.js +0 -150
  77. data/vendor/protovis/src/mark/Image.js +0 -154
  78. data/vendor/protovis/src/mark/Label.js +0 -155
  79. data/vendor/protovis/src/mark/Line.js +0 -195
  80. data/vendor/protovis/src/mark/Mark.js +0 -1237
  81. data/vendor/protovis/src/mark/Panel.js +0 -273
  82. data/vendor/protovis/src/mark/Rule.js +0 -143
  83. data/vendor/protovis/src/mark/Transient.js +0 -7
  84. data/vendor/protovis/src/mark/Transition.js +0 -195
  85. data/vendor/protovis/src/mark/Wedge.js +0 -244
  86. data/vendor/protovis/src/physics/BoundConstraint.js +0 -75
  87. data/vendor/protovis/src/physics/ChargeForce.js +0 -184
  88. data/vendor/protovis/src/physics/CollisionConstraint.js +0 -113
  89. data/vendor/protovis/src/physics/Constraint.js +0 -26
  90. data/vendor/protovis/src/physics/DragForce.js +0 -49
  91. data/vendor/protovis/src/physics/Force.js +0 -25
  92. data/vendor/protovis/src/physics/Particle.js +0 -81
  93. data/vendor/protovis/src/physics/PositionConstraint.js +0 -72
  94. data/vendor/protovis/src/physics/Quadtree.js +0 -195
  95. data/vendor/protovis/src/physics/Simulation.js +0 -159
  96. data/vendor/protovis/src/physics/SpringForce.js +0 -141
  97. data/vendor/protovis/src/pv-internals.js +0 -154
  98. data/vendor/protovis/src/pv.js +0 -95
  99. data/vendor/protovis/src/scene/SvgArea.js +0 -172
  100. data/vendor/protovis/src/scene/SvgBar.js +0 -28
  101. data/vendor/protovis/src/scene/SvgCurve.js +0 -354
  102. data/vendor/protovis/src/scene/SvgDot.js +0 -81
  103. data/vendor/protovis/src/scene/SvgImage.js +0 -45
  104. data/vendor/protovis/src/scene/SvgLabel.js +0 -46
  105. data/vendor/protovis/src/scene/SvgLine.js +0 -159
  106. data/vendor/protovis/src/scene/SvgPanel.js +0 -126
  107. data/vendor/protovis/src/scene/SvgRule.js +0 -26
  108. data/vendor/protovis/src/scene/SvgScene.js +0 -185
  109. data/vendor/protovis/src/scene/SvgWedge.js +0 -66
  110. data/vendor/protovis/src/text/DateFormat.js +0 -262
  111. data/vendor/protovis/src/text/Format.js +0 -78
  112. data/vendor/protovis/src/text/NumberFormat.js +0 -227
  113. data/vendor/protovis/src/text/TimeFormat.js +0 -115
@@ -1,157 +0,0 @@
1
- /**
2
- * Returns a new point behavior to be registered on mousemove events.
3
- *
4
- * @class Implements interactive fuzzy pointing, identifying marks that are in
5
- * close proximity to the mouse cursor. This behavior is an alternative to the
6
- * native mouseover and mouseout events, improving usability. Rather than
7
- * requiring the user to mouseover a mark exactly, the mouse simply needs to
8
- * move near the given mark and a "point" event is triggered. In addition, if
9
- * multiple marks overlap, the point behavior can be used to identify the mark
10
- * instance closest to the cursor, as opposed to the one that is rendered on
11
- * top.
12
- *
13
- * <p>The point behavior can also identify the closest mark instance for marks
14
- * that produce a continuous graphic primitive. The point behavior can thus be
15
- * used to provide details-on-demand for both discrete marks (such as dots and
16
- * bars), as well as continuous marks (such as lines and areas).
17
- *
18
- * <p>This behavior is implemented by finding the closest mark instance to the
19
- * mouse cursor on every mousemove event. If this closest mark is within the
20
- * given radius threshold, which defaults to 30 pixels, a "point" psuedo-event
21
- * is dispatched to the given mark instance. If any mark were previously
22
- * pointed, it would receive a corresponding "unpoint" event. These two
23
- * psuedo-event types correspond to the native "mouseover" and "mouseout"
24
- * events, respectively. To increase the radius at which the point behavior can
25
- * be applied, specify an appropriate threshold to the constructor, up to
26
- * <tt>Infinity</tt>.
27
- *
28
- * <p>By default, the standard Cartesian distance is computed. However, with
29
- * some visualizations it is desirable to consider only a single dimension, such
30
- * as the <i>x</i>-dimension for an independent variable. In this case, the
31
- * collapse parameter can be set to collapse the <i>y</i> dimension:
32
- *
33
- * <pre> .event("mousemove", pv.Behavior.point(Infinity).collapse("y"))</pre>
34
- *
35
- * <p>This behavior only listens to mousemove events on the assigned panel,
36
- * which is typically the root panel. The behavior will search recursively for
37
- * descendant marks to point. If the mouse leaves the assigned panel, the
38
- * behavior no longer receives mousemove events; an unpoint psuedo-event is
39
- * automatically dispatched to unpoint any pointed mark. Marks may be re-pointed
40
- * when the mouse reenters the panel.
41
- *
42
- * <p>Panels have transparent fill styles by default; this means that panels may
43
- * not receive the initial mousemove event to start pointing. To fix this
44
- * problem, either given the panel a visible fill style (such as "white"), or
45
- * set the <tt>events</tt> property to "all" such that the panel receives events
46
- * despite its transparent fill.
47
- *
48
- * <p>Note: this behavior does not currently wedge marks.
49
- *
50
- * @extends pv.Behavior
51
- *
52
- * @param {number} [r] the fuzzy radius threshold in pixels
53
- * @see <a href="http://www.tovigrossman.com/papers/chi2005bubblecursor.pdf"
54
- * >"The Bubble Cursor: Enhancing Target Acquisition by Dynamic Resizing of the
55
- * Cursor's Activation Area"</a> by T. Grossman &amp; R. Balakrishnan, CHI 2005.
56
- */
57
- pv.Behavior.point = function(r) {
58
- var unpoint, // the current pointer target
59
- collapse = null, // dimensions to collapse
60
- kx = 1, // x-dimension cost scale
61
- ky = 1, // y-dimension cost scale
62
- r2 = arguments.length ? r * r : 900; // fuzzy radius
63
-
64
- /** @private Search for the mark closest to the mouse. */
65
- function search(scene, index) {
66
- var s = scene[index],
67
- point = {cost: Infinity};
68
- for (var i = 0, n = s.visible && s.children.length; i < n; i++) {
69
- var child = s.children[i], mark = child.mark, p;
70
- if (mark.type == "panel") {
71
- mark.scene = child;
72
- for (var j = 0, m = child.length; j < m; j++) {
73
- mark.index = j;
74
- p = search(child, j);
75
- if (p.cost < point.cost) point = p;
76
- }
77
- delete mark.scene;
78
- delete mark.index;
79
- } else if (mark.$handlers.point) {
80
- var v = mark.mouse();
81
- for (var j = 0, m = child.length; j < m; j++) {
82
- var c = child[j],
83
- dx = v.x - c.left - (c.width || 0) / 2,
84
- dy = v.y - c.top - (c.height || 0) / 2,
85
- dd = kx * dx * dx + ky * dy * dy;
86
- if (dd < point.cost) {
87
- point.distance = dx * dx + dy * dy;
88
- point.cost = dd;
89
- point.scene = child;
90
- point.index = j;
91
- }
92
- }
93
- }
94
- }
95
- return point;
96
- }
97
-
98
- /** @private */
99
- function mousemove() {
100
- /* If the closest mark is far away, clear the current target. */
101
- var point = search(this.scene, this.index);
102
- if ((point.cost == Infinity) || (point.distance > r2)) point = null;
103
-
104
- /* Unpoint the old target, if it's not the new target. */
105
- if (unpoint) {
106
- if (point
107
- && (unpoint.scene == point.scene)
108
- && (unpoint.index == point.index)) return;
109
- pv.Mark.dispatch("unpoint", unpoint.scene, unpoint.index);
110
- }
111
-
112
- /* Point the new target, if there is one. */
113
- if (unpoint = point) {
114
- pv.Mark.dispatch("point", point.scene, point.index);
115
-
116
- /* Unpoint when the mouse leaves the root panel. */
117
- pv.listen(this.root.canvas(), "mouseout", mouseout);
118
- }
119
- }
120
-
121
- /** @private */
122
- function mouseout(e) {
123
- if (unpoint && !pv.ancestor(this, e.relatedTarget)) {
124
- pv.Mark.dispatch("unpoint", unpoint.scene, unpoint.index);
125
- unpoint = null;
126
- }
127
- }
128
-
129
- /**
130
- * Sets or gets the collapse parameter. By default, the standard Cartesian
131
- * distance is computed. However, with some visualizations it is desirable to
132
- * consider only a single dimension, such as the <i>x</i>-dimension for an
133
- * independent variable. In this case, the collapse parameter can be set to
134
- * collapse the <i>y</i> dimension:
135
- *
136
- * <pre> .event("mousemove", pv.Behavior.point(Infinity).collapse("y"))</pre>
137
- *
138
- * @function
139
- * @returns {pv.Behavior.point} this, or the current collapse parameter.
140
- * @name pv.Behavior.point.prototype.collapse
141
- * @param {string} [x] the new collapse parameter
142
- */
143
- mousemove.collapse = function(x) {
144
- if (arguments.length) {
145
- collapse = String(x);
146
- switch (collapse) {
147
- case "y": kx = 1; ky = 0; break;
148
- case "x": kx = 0; ky = 1; break;
149
- default: kx = 1; ky = 1; break;
150
- }
151
- return mousemove;
152
- }
153
- return collapse;
154
- };
155
-
156
- return mousemove;
157
- };
@@ -1,104 +0,0 @@
1
- /**
2
- * Returns a new resize behavior to be registered on mousedown events.
3
- *
4
- * @class Implements interactive resizing of a selection starting with mousedown
5
- * events. Register this behavior on selection handles that should be resizeable
6
- * by the user, such for brushing and linking. This behavior can be used in
7
- * tandom with {@link pv.Behavior.select} and {@link pv.Behavior.drag} to allow
8
- * the selected region to be selected and dragged interactively.
9
- *
10
- * <p>After the initial mousedown event is triggered, this behavior listens for
11
- * mousemove and mouseup events on the window. This allows resizing to continue
12
- * even if the mouse temporarily leaves the assigned panel, or even the root
13
- * panel.
14
- *
15
- * <p>This behavior requires that the data associated with the mark being
16
- * resized have <tt>x</tt>, <tt>y</tt>, <tt>dx</tt> and <tt>dy</tt> attributes
17
- * that correspond to the mark's location and dimensions in pixels. The mark's
18
- * positional properties are not set directly by this behavior; instead, the
19
- * positional properties should be defined as:
20
- *
21
- * <pre> .left(function(d) d.x)
22
- * .top(function(d) d.y)
23
- * .width(function(d) d.dx)
24
- * .height(function(d) d.dy)</pre>
25
- *
26
- * Thus, the behavior does not resize the mark directly, but instead updates the
27
- * size by updating the assigned panel's underlying data. Note that if the
28
- * positional properties are defined with bottom and right (rather than top and
29
- * left), the resize behavior will be inverted, which will confuse users!
30
- *
31
- * <p>The resize behavior is bounded by the assigned mark's enclosing panel; the
32
- * positional attributes are clamped such that the selection does not extend
33
- * outside the panel's bounds.
34
- *
35
- * <p>The mark being resized is automatically re-rendered for each mouse event
36
- * as part of the resize operation. This behavior may be enhanced in the future
37
- * to allow more flexible configuration. In some cases, such as with parallel
38
- * coordinates, resizing the selection may cause related marks to change, in
39
- * which case additional marks may also need to be rendered. This can be
40
- * accomplished by listening for the select psuedo-events:<ul>
41
- *
42
- * <li>resizestart (on mousedown)
43
- * <li>resize (on mousemove)
44
- * <li>resizeend (on mouseup)
45
- *
46
- * </ul>For example, to render the parent panel while resizing, thus
47
- * re-rendering all sibling marks:
48
- *
49
- * <pre> .event("mousedown", pv.Behavior.resize("left"))
50
- * .event("resize", function() this.parent)</pre>
51
- *
52
- * This behavior may be enhanced in the future to allow more flexible
53
- * configuration of the selection behavior.
54
- *
55
- * @extends pv.Behavior
56
- * @see pv.Behavior.select
57
- * @see pv.Behavior.drag
58
- */
59
- pv.Behavior.resize = function(side) {
60
- var scene, // scene context
61
- index, // scene context
62
- r, // region being selected
63
- m1; // initial mouse position
64
-
65
- /** @private */
66
- function mousedown(d) {
67
- index = this.index;
68
- scene = this.scene;
69
- m1 = this.mouse();
70
- r = d;
71
- switch (side) {
72
- case "left": m1.x = r.x + r.dx; break;
73
- case "right": m1.x = r.x; break;
74
- case "top": m1.y = r.y + r.dy; break;
75
- case "bottom": m1.y = r.y; break;
76
- }
77
- pv.Mark.dispatch("resizestart", scene, index);
78
- }
79
-
80
- /** @private */
81
- function mousemove() {
82
- if (!scene) return;
83
- scene.mark.context(scene, index, function() {
84
- var m2 = this.mouse();
85
- r.x = Math.max(0, Math.min(m1.x, m2.x));
86
- r.y = Math.max(0, Math.min(m1.y, m2.y));
87
- r.dx = Math.min(this.parent.width(), Math.max(m2.x, m1.x)) - r.x;
88
- r.dy = Math.min(this.parent.height(), Math.max(m2.y, m1.y)) - r.y;
89
- this.render();
90
- });
91
- pv.Mark.dispatch("resize", scene, index);
92
- }
93
-
94
- /** @private */
95
- function mouseup() {
96
- if (!scene) return;
97
- pv.Mark.dispatch("resizeend", scene, index);
98
- scene = null;
99
- }
100
-
101
- pv.listen(window, "mousemove", mousemove);
102
- pv.listen(window, "mouseup", mouseup);
103
- return mousedown;
104
- };
@@ -1,100 +0,0 @@
1
- /**
2
- * Returns a new select behavior to be registered on mousedown events.
3
- *
4
- * @class Implements interactive selecting starting with mousedown events.
5
- * Register this behavior on panels that should be selectable by the user, such
6
- * for brushing and linking. This behavior can be used in tandom with
7
- * {@link pv.Behavior.drag} to allow the selected region to be dragged
8
- * interactively.
9
- *
10
- * <p>After the initial mousedown event is triggered, this behavior listens for
11
- * mousemove and mouseup events on the window. This allows selecting to continue
12
- * even if the mouse temporarily leaves the assigned panel, or even the root
13
- * panel.
14
- *
15
- * <p>This behavior requires that the data associated with the mark being
16
- * dragged have <tt>x</tt>, <tt>y</tt>, <tt>dx</tt> and <tt>dy</tt> attributes
17
- * that correspond to the mark's location and dimensions in pixels. The mark's
18
- * positional properties are not set directly by this behavior; instead, the
19
- * positional properties should be defined as:
20
- *
21
- * <pre> .left(function(d) d.x)
22
- * .top(function(d) d.y)
23
- * .width(function(d) d.dx)
24
- * .height(function(d) d.dy)</pre>
25
- *
26
- * Thus, the behavior does not resize the mark directly, but instead updates the
27
- * selection by updating the assigned panel's underlying data. Note that if the
28
- * positional properties are defined with bottom and right (rather than top and
29
- * left), the drag behavior will be inverted, which will confuse users!
30
- *
31
- * <p>The select behavior is bounded by the assigned panel; the positional
32
- * attributes are clamped such that the selection does not extend outside the
33
- * panel's bounds.
34
- *
35
- * <p>The panel being selected is automatically re-rendered for each mouse event
36
- * as part of the drag operation. This behavior may be enhanced in the future to
37
- * allow more flexible configuration of select behavior. In some cases, such as
38
- * with parallel coordinates, making a selection may cause related marks to
39
- * change, in which case additional marks may also need to be rendered. This can
40
- * be accomplished by listening for the select psuedo-events:<ul>
41
- *
42
- * <li>selectstart (on mousedown)
43
- * <li>select (on mousemove)
44
- * <li>selectend (on mouseup)
45
- *
46
- * </ul>For example, to render the parent panel while selecting, thus
47
- * re-rendering all sibling marks:
48
- *
49
- * <pre> .event("mousedown", pv.Behavior.drag())
50
- * .event("select", function() this.parent)</pre>
51
- *
52
- * This behavior may be enhanced in the future to allow more flexible
53
- * configuration of the selection behavior.
54
- *
55
- * @extends pv.Behavior
56
- * @see pv.Behavior.drag
57
- */
58
- pv.Behavior.select = function() {
59
- var scene, // scene context
60
- index, // scene context
61
- r, // region being selected
62
- m1; // initial mouse position
63
-
64
- /** @private */
65
- function mousedown(d) {
66
- index = this.index;
67
- scene = this.scene;
68
- m1 = this.mouse();
69
- r = d;
70
- r.x = m1.x;
71
- r.y = m1.y;
72
- r.dx = r.dy = 0;
73
- pv.Mark.dispatch("selectstart", scene, index);
74
- }
75
-
76
- /** @private */
77
- function mousemove() {
78
- if (!scene) return;
79
- scene.mark.context(scene, index, function() {
80
- var m2 = this.mouse();
81
- r.x = Math.max(0, Math.min(m1.x, m2.x));
82
- r.y = Math.max(0, Math.min(m1.y, m2.y));
83
- r.dx = Math.min(this.width(), Math.max(m2.x, m1.x)) - r.x;
84
- r.dy = Math.min(this.height(), Math.max(m2.y, m1.y)) - r.y;
85
- this.render();
86
- });
87
- pv.Mark.dispatch("select", scene, index);
88
- }
89
-
90
- /** @private */
91
- function mouseup() {
92
- if (!scene) return;
93
- pv.Mark.dispatch("selectend", scene, index);
94
- scene = null;
95
- }
96
-
97
- pv.listen(window, "mousemove", mousemove);
98
- pv.listen(window, "mouseup", mouseup);
99
- return mousedown;
100
- };
@@ -1,85 +0,0 @@
1
- /**
2
- * Returns a new zoom behavior to be registered on mousewheel events.
3
- *
4
- * @class Implements interactive zooming using mousewheel events. Register this
5
- * behavior on panels to allow zooming. This behavior can be used in tandem with
6
- * {@link pv.Behavior.pan} to allow both panning and zooming:
7
- *
8
- * <pre> .event("mousedown", pv.Behavior.pan())
9
- * .event("mousewheel", pv.Behavior.zoom())</pre>
10
- *
11
- * The zoom behavior currently supports only mousewheel events; support for
12
- * keyboard shortcuts and gesture events to improve accessibility may be added
13
- * in the future.
14
- *
15
- * <p>The implementation of this behavior relies on the panel's
16
- * <tt>transform</tt> property, which specifies a matrix transformation that is
17
- * applied to child marks. Note that the transform property only affects the
18
- * panel's children, but not the panel itself; therefore the panel's fill and
19
- * stroke will not change when the contents are zoomed. The built-in support for
20
- * transforms only supports uniform scaling and translates, which is sufficient
21
- * for panning and zooming. Note that this is not a strict geometric
22
- * transformation, as the <tt>lineWidth</tt> property is scale-aware: strokes
23
- * are drawn at constant size independent of scale.
24
- *
25
- * <p>Panels have transparent fill styles by default; this means that panels may
26
- * not receive mousewheel events to zoom. To fix this problem, either given the
27
- * panel a visible fill style (such as "white"), or set the <tt>events</tt>
28
- * property to "all" such that the panel receives events despite its transparent
29
- * fill.
30
- *
31
- * <p>The zoom behavior has optional support for bounding. If enabled, the user
32
- * will not be able to zoom out farther than the initial bounds. This feature is
33
- * designed to work in conjunction with the pan behavior.
34
- *
35
- * @extends pv.Behavior
36
- * @see pv.Panel#transform
37
- * @see pv.Mark#scale
38
- * @param {number} speed
39
- */
40
- pv.Behavior.zoom = function(speed) {
41
- var bound; // whether to bound to the panel
42
-
43
- if (!arguments.length) speed = 1 / 48;
44
-
45
- /** @private */
46
- function mousewheel() {
47
- var v = this.mouse(),
48
- k = pv.event.wheel * speed,
49
- m = this.transform().translate(v.x, v.y)
50
- .scale((k < 0) ? (1e3 / (1e3 - k)) : ((1e3 + k) / 1e3))
51
- .translate(-v.x, -v.y);
52
- if (bound) {
53
- m.k = Math.max(1, m.k);
54
- m.x = Math.max((1 - m.k) * this.width(), Math.min(0, m.x));
55
- m.y = Math.max((1 - m.k) * this.height(), Math.min(0, m.y));
56
- }
57
- this.transform(m).render();
58
- pv.Mark.dispatch("zoom", this.scene, this.index);
59
- }
60
-
61
- /**
62
- * Sets or gets the bound parameter. If bounding is enabled, the user will not
63
- * be able to zoom out farther than the initial panel bounds. Bounding is not
64
- * enabled by default. If this behavior is used in tandem with the pan
65
- * behavior, both should use the same bound parameter.
66
- *
67
- * <p>Note: enabling bounding after zooming has already occurred will not
68
- * immediately reset the transform. Bounding should be enabled before the zoom
69
- * behavior is applied.
70
- *
71
- * @function
72
- * @returns {pv.Behavior.zoom} this, or the current bound parameter.
73
- * @name pv.Behavior.zoom.prototype.bound
74
- * @param {boolean} [x] the new bound parameter.
75
- */
76
- mousewheel.bound = function(x) {
77
- if (arguments.length) {
78
- bound = Boolean(x);
79
- return this;
80
- }
81
- return Boolean(bound);
82
- };
83
-
84
- return mousewheel;
85
- };
@@ -1,598 +0,0 @@
1
- /**
2
- * Returns the {@link pv.Color} for the specified color format string. Colors
3
- * may have an associated opacity, or alpha channel. Color formats are specified
4
- * by CSS Color Modular Level 3, using either in RGB or HSL color space. For
5
- * example:<ul>
6
- *
7
- * <li>#f00 // #rgb
8
- * <li>#ff0000 // #rrggbb
9
- * <li>rgb(255, 0, 0)
10
- * <li>rgb(100%, 0%, 0%)
11
- * <li>hsl(0, 100%, 50%)
12
- * <li>rgba(0, 0, 255, 0.5)
13
- * <li>hsla(120, 100%, 50%, 1)
14
- *
15
- * </ul>The SVG 1.0 color keywords names are also supported, such as "aliceblue"
16
- * and "yellowgreen". The "transparent" keyword is supported for fully-
17
- * transparent black.
18
- *
19
- * <p>If the <tt>format</tt> argument is already an instance of <tt>Color</tt>,
20
- * the argument is returned with no further processing.
21
- *
22
- * @param {string} format the color specification string, such as "#f00".
23
- * @returns {pv.Color} the corresponding <tt>Color</tt>.
24
- * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG color
25
- * keywords</a>
26
- * @see <a href="http://www.w3.org/TR/css3-color/">CSS3 color module</a>
27
- */
28
- pv.color = function(format) {
29
- if (format.rgb) return format.rgb();
30
-
31
- /* Handle hsl, rgb. */
32
- var m1 = /([a-z]+)\((.*)\)/i.exec(format);
33
- if (m1) {
34
- var m2 = m1[2].split(","), a = 1;
35
- switch (m1[1]) {
36
- case "hsla":
37
- case "rgba": {
38
- a = parseFloat(m2[3]);
39
- if (!a) return pv.Color.transparent;
40
- break;
41
- }
42
- }
43
- switch (m1[1]) {
44
- case "hsla":
45
- case "hsl": {
46
- var h = parseFloat(m2[0]), // degrees
47
- s = parseFloat(m2[1]) / 100, // percentage
48
- l = parseFloat(m2[2]) / 100; // percentage
49
- return (new pv.Color.Hsl(h, s, l, a)).rgb();
50
- }
51
- case "rgba":
52
- case "rgb": {
53
- function parse(c) { // either integer or percentage
54
- var f = parseFloat(c);
55
- return (c[c.length - 1] == '%') ? Math.round(f * 2.55) : f;
56
- }
57
- var r = parse(m2[0]), g = parse(m2[1]), b = parse(m2[2]);
58
- return pv.rgb(r, g, b, a);
59
- }
60
- }
61
- }
62
-
63
- /* Named colors. */
64
- var named = pv.Color.names[format];
65
- if (named) return named;
66
-
67
- /* Hexadecimal colors: #rgb and #rrggbb. */
68
- if (format.charAt(0) == "#") {
69
- var r, g, b;
70
- if (format.length == 4) {
71
- r = format.charAt(1); r += r;
72
- g = format.charAt(2); g += g;
73
- b = format.charAt(3); b += b;
74
- } else if (format.length == 7) {
75
- r = format.substring(1, 3);
76
- g = format.substring(3, 5);
77
- b = format.substring(5, 7);
78
- }
79
- return pv.rgb(parseInt(r, 16), parseInt(g, 16), parseInt(b, 16), 1);
80
- }
81
-
82
- /* Otherwise, pass-through unsupported colors. */
83
- return new pv.Color(format, 1);
84
- };
85
-
86
- /**
87
- * Constructs a color with the specified color format string and opacity. This
88
- * constructor should not be invoked directly; use {@link pv.color} instead.
89
- *
90
- * @class Represents an abstract (possibly translucent) color. The color is
91
- * divided into two parts: the <tt>color</tt> attribute, an opaque color format
92
- * string, and the <tt>opacity</tt> attribute, a float in [0, 1]. The color
93
- * space is dependent on the implementing class; all colors support the
94
- * {@link #rgb} method to convert to RGB color space for interpolation.
95
- *
96
- * <p>See also the <a href="../../api/Color.html">Color guide</a>.
97
- *
98
- * @param {string} color an opaque color format string, such as "#f00".
99
- * @param {number} opacity the opacity, in [0,1].
100
- * @see pv.color
101
- */
102
- pv.Color = function(color, opacity) {
103
- /**
104
- * An opaque color format string, such as "#f00".
105
- *
106
- * @type string
107
- * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG color
108
- * keywords</a>
109
- * @see <a href="http://www.w3.org/TR/css3-color/">CSS3 color module</a>
110
- */
111
- this.color = color;
112
-
113
- /**
114
- * The opacity, a float in [0, 1].
115
- *
116
- * @type number
117
- */
118
- this.opacity = opacity;
119
- };
120
-
121
- /**
122
- * Returns a new color that is a brighter version of this color. The behavior of
123
- * this method may vary slightly depending on the underlying color space.
124
- * Although brighter and darker are inverse operations, the results of a series
125
- * of invocations of these two methods might be inconsistent because of rounding
126
- * errors.
127
- *
128
- * @param [k] {number} an optional scale factor; defaults to 1.
129
- * @see #darker
130
- * @returns {pv.Color} a brighter color.
131
- */
132
- pv.Color.prototype.brighter = function(k) {
133
- return this.rgb().brighter(k);
134
- };
135
-
136
- /**
137
- * Returns a new color that is a brighter version of this color. The behavior of
138
- * this method may vary slightly depending on the underlying color space.
139
- * Although brighter and darker are inverse operations, the results of a series
140
- * of invocations of these two methods might be inconsistent because of rounding
141
- * errors.
142
- *
143
- * @param [k] {number} an optional scale factor; defaults to 1.
144
- * @see #brighter
145
- * @returns {pv.Color} a darker color.
146
- */
147
- pv.Color.prototype.darker = function(k) {
148
- return this.rgb().darker(k);
149
- };
150
-
151
- /**
152
- * Constructs a new RGB color with the specified channel values.
153
- *
154
- * @param {number} r the red channel, an integer in [0,255].
155
- * @param {number} g the green channel, an integer in [0,255].
156
- * @param {number} b the blue channel, an integer in [0,255].
157
- * @param {number} [a] the alpha channel, a float in [0,1].
158
- * @returns pv.Color.Rgb
159
- */
160
- pv.rgb = function(r, g, b, a) {
161
- return new pv.Color.Rgb(r, g, b, (arguments.length == 4) ? a : 1);
162
- };
163
-
164
- /**
165
- * Constructs a new RGB color with the specified channel values.
166
- *
167
- * @class Represents a color in RGB space.
168
- *
169
- * @param {number} r the red channel, an integer in [0,255].
170
- * @param {number} g the green channel, an integer in [0,255].
171
- * @param {number} b the blue channel, an integer in [0,255].
172
- * @param {number} a the alpha channel, a float in [0,1].
173
- * @extends pv.Color
174
- */
175
- pv.Color.Rgb = function(r, g, b, a) {
176
- pv.Color.call(this, a ? ("rgb(" + r + "," + g + "," + b + ")") : "none", a);
177
-
178
- /**
179
- * The red channel, an integer in [0, 255].
180
- *
181
- * @type number
182
- */
183
- this.r = r;
184
-
185
- /**
186
- * The green channel, an integer in [0, 255].
187
- *
188
- * @type number
189
- */
190
- this.g = g;
191
-
192
- /**
193
- * The blue channel, an integer in [0, 255].
194
- *
195
- * @type number
196
- */
197
- this.b = b;
198
-
199
- /**
200
- * The alpha channel, a float in [0, 1].
201
- *
202
- * @type number
203
- */
204
- this.a = a;
205
- };
206
- pv.Color.Rgb.prototype = pv.extend(pv.Color);
207
-
208
- /**
209
- * Constructs a new RGB color with the same green, blue and alpha channels as
210
- * this color, with the specified red channel.
211
- *
212
- * @param {number} r the red channel, an integer in [0,255].
213
- */
214
- pv.Color.Rgb.prototype.red = function(r) {
215
- return pv.rgb(r, this.g, this.b, this.a);
216
- };
217
-
218
- /**
219
- * Constructs a new RGB color with the same red, blue and alpha channels as this
220
- * color, with the specified green channel.
221
- *
222
- * @param {number} g the green channel, an integer in [0,255].
223
- */
224
- pv.Color.Rgb.prototype.green = function(g) {
225
- return pv.rgb(this.r, g, this.b, this.a);
226
- };
227
-
228
- /**
229
- * Constructs a new RGB color with the same red, green and alpha channels as
230
- * this color, with the specified blue channel.
231
- *
232
- * @param {number} b the blue channel, an integer in [0,255].
233
- */
234
- pv.Color.Rgb.prototype.blue = function(b) {
235
- return pv.rgb(this.r, this.g, b, this.a);
236
- };
237
-
238
- /**
239
- * Constructs a new RGB color with the same red, green and blue channels as this
240
- * color, with the specified alpha channel.
241
- *
242
- * @param {number} a the alpha channel, a float in [0,1].
243
- */
244
- pv.Color.Rgb.prototype.alpha = function(a) {
245
- return pv.rgb(this.r, this.g, this.b, a);
246
- };
247
-
248
- /**
249
- * Returns the RGB color equivalent to this color. This method is abstract and
250
- * must be implemented by subclasses.
251
- *
252
- * @returns {pv.Color.Rgb} an RGB color.
253
- * @function
254
- * @name pv.Color.prototype.rgb
255
- */
256
-
257
- /**
258
- * Returns this.
259
- *
260
- * @returns {pv.Color.Rgb} this.
261
- */
262
- pv.Color.Rgb.prototype.rgb = function() { return this; };
263
-
264
- /**
265
- * Returns a new color that is a brighter version of this color. This method
266
- * applies an arbitrary scale factor to each of the three RGB components of this
267
- * color to create a brighter version of this color. Although brighter and
268
- * darker are inverse operations, the results of a series of invocations of
269
- * these two methods might be inconsistent because of rounding errors.
270
- *
271
- * @param [k] {number} an optional scale factor; defaults to 1.
272
- * @see #darker
273
- * @returns {pv.Color.Rgb} a brighter color.
274
- */
275
- pv.Color.Rgb.prototype.brighter = function(k) {
276
- k = Math.pow(0.7, arguments.length ? k : 1);
277
- var r = this.r, g = this.g, b = this.b, i = 30;
278
- if (!r && !g && !b) return pv.rgb(i, i, i, this.a);
279
- if (r && (r < i)) r = i;
280
- if (g && (g < i)) g = i;
281
- if (b && (b < i)) b = i;
282
- return pv.rgb(
283
- Math.min(255, Math.floor(r / k)),
284
- Math.min(255, Math.floor(g / k)),
285
- Math.min(255, Math.floor(b / k)),
286
- this.a);
287
- };
288
-
289
- /**
290
- * Returns a new color that is a darker version of this color. This method
291
- * applies an arbitrary scale factor to each of the three RGB components of this
292
- * color to create a darker version of this color. Although brighter and darker
293
- * are inverse operations, the results of a series of invocations of these two
294
- * methods might be inconsistent because of rounding errors.
295
- *
296
- * @param [k] {number} an optional scale factor; defaults to 1.
297
- * @see #brighter
298
- * @returns {pv.Color.Rgb} a darker color.
299
- */
300
- pv.Color.Rgb.prototype.darker = function(k) {
301
- k = Math.pow(0.7, arguments.length ? k : 1);
302
- return pv.rgb(
303
- Math.max(0, Math.floor(k * this.r)),
304
- Math.max(0, Math.floor(k * this.g)),
305
- Math.max(0, Math.floor(k * this.b)),
306
- this.a);
307
- };
308
-
309
- /**
310
- * Constructs a new HSL color with the specified values.
311
- *
312
- * @param {number} h the hue, an integer in [0, 360].
313
- * @param {number} s the saturation, a float in [0, 1].
314
- * @param {number} l the lightness, a float in [0, 1].
315
- * @param {number} [a] the opacity, a float in [0, 1].
316
- * @returns pv.Color.Hsl
317
- */
318
- pv.hsl = function(h, s, l, a) {
319
- return new pv.Color.Hsl(h, s, l, (arguments.length == 4) ? a : 1);
320
- };
321
-
322
- /**
323
- * Constructs a new HSL color with the specified values.
324
- *
325
- * @class Represents a color in HSL space.
326
- *
327
- * @param {number} h the hue, an integer in [0, 360].
328
- * @param {number} s the saturation, a float in [0, 1].
329
- * @param {number} l the lightness, a float in [0, 1].
330
- * @param {number} a the opacity, a float in [0, 1].
331
- * @extends pv.Color
332
- */
333
- pv.Color.Hsl = function(h, s, l, a) {
334
- pv.Color.call(this, "hsl(" + h + "," + (s * 100) + "%," + (l * 100) + "%)", a);
335
-
336
- /**
337
- * The hue, an integer in [0, 360].
338
- *
339
- * @type number
340
- */
341
- this.h = h;
342
-
343
- /**
344
- * The saturation, a float in [0, 1].
345
- *
346
- * @type number
347
- */
348
- this.s = s;
349
-
350
- /**
351
- * The lightness, a float in [0, 1].
352
- *
353
- * @type number
354
- */
355
- this.l = l;
356
-
357
- /**
358
- * The opacity, a float in [0, 1].
359
- *
360
- * @type number
361
- */
362
- this.a = a;
363
- };
364
- pv.Color.Hsl.prototype = pv.extend(pv.Color);
365
-
366
- /**
367
- * Constructs a new HSL color with the same saturation, lightness and alpha as
368
- * this color, and the specified hue.
369
- *
370
- * @param {number} h the hue, an integer in [0, 360].
371
- */
372
- pv.Color.Hsl.prototype.hue = function(h) {
373
- return pv.hsl(h, this.s, this.l, this.a);
374
- };
375
-
376
- /**
377
- * Constructs a new HSL color with the same hue, lightness and alpha as this
378
- * color, and the specified saturation.
379
- *
380
- * @param {number} s the saturation, a float in [0, 1].
381
- */
382
- pv.Color.Hsl.prototype.saturation = function(s) {
383
- return pv.hsl(this.h, s, this.l, this.a);
384
- };
385
-
386
- /**
387
- * Constructs a new HSL color with the same hue, saturation and alpha as this
388
- * color, and the specified lightness.
389
- *
390
- * @param {number} l the lightness, a float in [0, 1].
391
- */
392
- pv.Color.Hsl.prototype.lightness = function(l) {
393
- return pv.hsl(this.h, this.s, l, this.a);
394
- };
395
-
396
- /**
397
- * Constructs a new HSL color with the same hue, saturation and lightness as
398
- * this color, and the specified alpha.
399
- *
400
- * @param {number} a the opacity, a float in [0, 1].
401
- */
402
- pv.Color.Hsl.prototype.alpha = function(a) {
403
- return pv.hsl(this.h, this.s, this.l, a);
404
- };
405
-
406
- /**
407
- * Returns the RGB color equivalent to this HSL color.
408
- *
409
- * @returns {pv.Color.Rgb} an RGB color.
410
- */
411
- pv.Color.Hsl.prototype.rgb = function() {
412
- var h = this.h, s = this.s, l = this.l;
413
-
414
- /* Some simple corrections for h, s and l. */
415
- h = h % 360; if (h < 0) h += 360;
416
- s = Math.max(0, Math.min(s, 1));
417
- l = Math.max(0, Math.min(l, 1));
418
-
419
- /* From FvD 13.37, CSS Color Module Level 3 */
420
- var m2 = (l <= .5) ? (l * (1 + s)) : (l + s - l * s);
421
- var m1 = 2 * l - m2;
422
- function v(h) {
423
- if (h > 360) h -= 360;
424
- else if (h < 0) h += 360;
425
- if (h < 60) return m1 + (m2 - m1) * h / 60;
426
- if (h < 180) return m2;
427
- if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
428
- return m1;
429
- }
430
- function vv(h) {
431
- return Math.round(v(h) * 255);
432
- }
433
-
434
- return pv.rgb(vv(h + 120), vv(h), vv(h - 120), this.a);
435
- };
436
-
437
- /**
438
- * @private SVG color keywords, per CSS Color Module Level 3.
439
- *
440
- * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG color
441
- * keywords</a>
442
- */
443
- pv.Color.names = {
444
- aliceblue: "#f0f8ff",
445
- antiquewhite: "#faebd7",
446
- aqua: "#00ffff",
447
- aquamarine: "#7fffd4",
448
- azure: "#f0ffff",
449
- beige: "#f5f5dc",
450
- bisque: "#ffe4c4",
451
- black: "#000000",
452
- blanchedalmond: "#ffebcd",
453
- blue: "#0000ff",
454
- blueviolet: "#8a2be2",
455
- brown: "#a52a2a",
456
- burlywood: "#deb887",
457
- cadetblue: "#5f9ea0",
458
- chartreuse: "#7fff00",
459
- chocolate: "#d2691e",
460
- coral: "#ff7f50",
461
- cornflowerblue: "#6495ed",
462
- cornsilk: "#fff8dc",
463
- crimson: "#dc143c",
464
- cyan: "#00ffff",
465
- darkblue: "#00008b",
466
- darkcyan: "#008b8b",
467
- darkgoldenrod: "#b8860b",
468
- darkgray: "#a9a9a9",
469
- darkgreen: "#006400",
470
- darkgrey: "#a9a9a9",
471
- darkkhaki: "#bdb76b",
472
- darkmagenta: "#8b008b",
473
- darkolivegreen: "#556b2f",
474
- darkorange: "#ff8c00",
475
- darkorchid: "#9932cc",
476
- darkred: "#8b0000",
477
- darksalmon: "#e9967a",
478
- darkseagreen: "#8fbc8f",
479
- darkslateblue: "#483d8b",
480
- darkslategray: "#2f4f4f",
481
- darkslategrey: "#2f4f4f",
482
- darkturquoise: "#00ced1",
483
- darkviolet: "#9400d3",
484
- deeppink: "#ff1493",
485
- deepskyblue: "#00bfff",
486
- dimgray: "#696969",
487
- dimgrey: "#696969",
488
- dodgerblue: "#1e90ff",
489
- firebrick: "#b22222",
490
- floralwhite: "#fffaf0",
491
- forestgreen: "#228b22",
492
- fuchsia: "#ff00ff",
493
- gainsboro: "#dcdcdc",
494
- ghostwhite: "#f8f8ff",
495
- gold: "#ffd700",
496
- goldenrod: "#daa520",
497
- gray: "#808080",
498
- green: "#008000",
499
- greenyellow: "#adff2f",
500
- grey: "#808080",
501
- honeydew: "#f0fff0",
502
- hotpink: "#ff69b4",
503
- indianred: "#cd5c5c",
504
- indigo: "#4b0082",
505
- ivory: "#fffff0",
506
- khaki: "#f0e68c",
507
- lavender: "#e6e6fa",
508
- lavenderblush: "#fff0f5",
509
- lawngreen: "#7cfc00",
510
- lemonchiffon: "#fffacd",
511
- lightblue: "#add8e6",
512
- lightcoral: "#f08080",
513
- lightcyan: "#e0ffff",
514
- lightgoldenrodyellow: "#fafad2",
515
- lightgray: "#d3d3d3",
516
- lightgreen: "#90ee90",
517
- lightgrey: "#d3d3d3",
518
- lightpink: "#ffb6c1",
519
- lightsalmon: "#ffa07a",
520
- lightseagreen: "#20b2aa",
521
- lightskyblue: "#87cefa",
522
- lightslategray: "#778899",
523
- lightslategrey: "#778899",
524
- lightsteelblue: "#b0c4de",
525
- lightyellow: "#ffffe0",
526
- lime: "#00ff00",
527
- limegreen: "#32cd32",
528
- linen: "#faf0e6",
529
- magenta: "#ff00ff",
530
- maroon: "#800000",
531
- mediumaquamarine: "#66cdaa",
532
- mediumblue: "#0000cd",
533
- mediumorchid: "#ba55d3",
534
- mediumpurple: "#9370db",
535
- mediumseagreen: "#3cb371",
536
- mediumslateblue: "#7b68ee",
537
- mediumspringgreen: "#00fa9a",
538
- mediumturquoise: "#48d1cc",
539
- mediumvioletred: "#c71585",
540
- midnightblue: "#191970",
541
- mintcream: "#f5fffa",
542
- mistyrose: "#ffe4e1",
543
- moccasin: "#ffe4b5",
544
- navajowhite: "#ffdead",
545
- navy: "#000080",
546
- oldlace: "#fdf5e6",
547
- olive: "#808000",
548
- olivedrab: "#6b8e23",
549
- orange: "#ffa500",
550
- orangered: "#ff4500",
551
- orchid: "#da70d6",
552
- palegoldenrod: "#eee8aa",
553
- palegreen: "#98fb98",
554
- paleturquoise: "#afeeee",
555
- palevioletred: "#db7093",
556
- papayawhip: "#ffefd5",
557
- peachpuff: "#ffdab9",
558
- peru: "#cd853f",
559
- pink: "#ffc0cb",
560
- plum: "#dda0dd",
561
- powderblue: "#b0e0e6",
562
- purple: "#800080",
563
- red: "#ff0000",
564
- rosybrown: "#bc8f8f",
565
- royalblue: "#4169e1",
566
- saddlebrown: "#8b4513",
567
- salmon: "#fa8072",
568
- sandybrown: "#f4a460",
569
- seagreen: "#2e8b57",
570
- seashell: "#fff5ee",
571
- sienna: "#a0522d",
572
- silver: "#c0c0c0",
573
- skyblue: "#87ceeb",
574
- slateblue: "#6a5acd",
575
- slategray: "#708090",
576
- slategrey: "#708090",
577
- snow: "#fffafa",
578
- springgreen: "#00ff7f",
579
- steelblue: "#4682b4",
580
- tan: "#d2b48c",
581
- teal: "#008080",
582
- thistle: "#d8bfd8",
583
- tomato: "#ff6347",
584
- turquoise: "#40e0d0",
585
- violet: "#ee82ee",
586
- wheat: "#f5deb3",
587
- white: "#ffffff",
588
- whitesmoke: "#f5f5f5",
589
- yellow: "#ffff00",
590
- yellowgreen: "#9acd32",
591
- transparent: pv.Color.transparent = pv.rgb(0, 0, 0, 0)
592
- };
593
-
594
- /* Initialized named colors. */
595
- (function() {
596
- var names = pv.Color.names;
597
- for (var name in names) names[name] = pv.color(names[name]);
598
- })();